From 612f74282ac645e9a765838b216919a7c3572315 Mon Sep 17 00:00:00 2001 From: alpha-guy Date: Sat, 8 May 2021 12:23:30 +0530 Subject: [PATCH 01/16] Add external Uniswap V3 contracts --- .../oracles/UniswapPairPriceAdapter.sol | 2 +- .../abi/uniswap/{ => v2}/StakingRewards.json | 0 external/abi/uniswap/{ => v2}/Uni.json | 0 .../{ => v2}/UniswapGovernorAlpha.json | 0 .../abi/uniswap/{ => v2}/UniswapTimelock.json | 0 .../uniswap/{ => v2}/UniswapV2Factory.json | 0 .../abi/uniswap/{ => v2}/UniswapV2Pair.json | 0 .../uniswap/{ => v2}/UniswapV2Router02.json | 0 external/abi/uniswap/v3/SwapRouter.json | 506 ++++++++++++++++++ external/abi/uniswap/v3/UniswapV3Factory.json | 245 +++++++++ .../uniswap/{ => v2}/GovernorAlpha.sol | 0 .../uniswap/{ => v2}/StakingRewards.sol | 0 external/contracts/uniswap/{ => v2}/Uni.sol | 0 .../uniswap/{ => v2}/UniswapTimelock.sol | 0 .../uniswap/{ => v2}/UniswapV2Factory.sol | 0 .../uniswap/{ => v2}/UniswapV2Pair.sol | 0 .../uniswap/{ => v2}/UniswapV2Router02.sol | 0 .../uniswap/{ => v2}/lib/UniswapV2Library.sol | 2 +- external/contracts/uniswap/v3/SwapRouter.sol | 244 +++++++++ .../contracts/uniswap/v3/UniswapV3Factory.sol | 73 +++ 20 files changed, 1070 insertions(+), 2 deletions(-) rename external/abi/uniswap/{ => v2}/StakingRewards.json (100%) rename external/abi/uniswap/{ => v2}/Uni.json (100%) rename external/abi/uniswap/{ => v2}/UniswapGovernorAlpha.json (100%) rename external/abi/uniswap/{ => v2}/UniswapTimelock.json (100%) rename external/abi/uniswap/{ => v2}/UniswapV2Factory.json (100%) rename external/abi/uniswap/{ => v2}/UniswapV2Pair.json (100%) rename external/abi/uniswap/{ => v2}/UniswapV2Router02.json (100%) create mode 100644 external/abi/uniswap/v3/SwapRouter.json create mode 100644 external/abi/uniswap/v3/UniswapV3Factory.json rename external/contracts/uniswap/{ => v2}/GovernorAlpha.sol (100%) rename external/contracts/uniswap/{ => v2}/StakingRewards.sol (100%) rename external/contracts/uniswap/{ => v2}/Uni.sol (100%) rename external/contracts/uniswap/{ => v2}/UniswapTimelock.sol (100%) rename external/contracts/uniswap/{ => v2}/UniswapV2Factory.sol (100%) rename external/contracts/uniswap/{ => v2}/UniswapV2Pair.sol (100%) rename external/contracts/uniswap/{ => v2}/UniswapV2Router02.sol (100%) rename external/contracts/uniswap/{ => v2}/lib/UniswapV2Library.sol (95%) create mode 100644 external/contracts/uniswap/v3/SwapRouter.sol create mode 100644 external/contracts/uniswap/v3/UniswapV3Factory.sol diff --git a/contracts/protocol/integration/oracles/UniswapPairPriceAdapter.sol b/contracts/protocol/integration/oracles/UniswapPairPriceAdapter.sol index 2d3bfa125..cc7c70e2b 100644 --- a/contracts/protocol/integration/oracles/UniswapPairPriceAdapter.sol +++ b/contracts/protocol/integration/oracles/UniswapPairPriceAdapter.sol @@ -26,7 +26,7 @@ import { AddressArrayUtils } from "../../../lib/AddressArrayUtils.sol"; import { IController } from "../../../interfaces/IController.sol"; import { IPriceOracle } from "../../../interfaces/IPriceOracle.sol"; import { IUniswapV2Pair } from "../../../interfaces/external/IUniswapV2Pair.sol"; -import { UniswapV2Library } from "../../../../external/contracts/uniswap/lib/UniswapV2Library.sol"; +import { UniswapV2Library } from "../../../../external/contracts/uniswap/v2/lib/UniswapV2Library.sol"; import { PreciseUnitMath } from "../../../lib/PreciseUnitMath.sol"; import { ResourceIdentifier } from "../../lib/ResourceIdentifier.sol"; diff --git a/external/abi/uniswap/StakingRewards.json b/external/abi/uniswap/v2/StakingRewards.json similarity index 100% rename from external/abi/uniswap/StakingRewards.json rename to external/abi/uniswap/v2/StakingRewards.json diff --git a/external/abi/uniswap/Uni.json b/external/abi/uniswap/v2/Uni.json similarity index 100% rename from external/abi/uniswap/Uni.json rename to external/abi/uniswap/v2/Uni.json diff --git a/external/abi/uniswap/UniswapGovernorAlpha.json b/external/abi/uniswap/v2/UniswapGovernorAlpha.json similarity index 100% rename from external/abi/uniswap/UniswapGovernorAlpha.json rename to external/abi/uniswap/v2/UniswapGovernorAlpha.json diff --git a/external/abi/uniswap/UniswapTimelock.json b/external/abi/uniswap/v2/UniswapTimelock.json similarity index 100% rename from external/abi/uniswap/UniswapTimelock.json rename to external/abi/uniswap/v2/UniswapTimelock.json diff --git a/external/abi/uniswap/UniswapV2Factory.json b/external/abi/uniswap/v2/UniswapV2Factory.json similarity index 100% rename from external/abi/uniswap/UniswapV2Factory.json rename to external/abi/uniswap/v2/UniswapV2Factory.json diff --git a/external/abi/uniswap/UniswapV2Pair.json b/external/abi/uniswap/v2/UniswapV2Pair.json similarity index 100% rename from external/abi/uniswap/UniswapV2Pair.json rename to external/abi/uniswap/v2/UniswapV2Pair.json diff --git a/external/abi/uniswap/UniswapV2Router02.json b/external/abi/uniswap/v2/UniswapV2Router02.json similarity index 100% rename from external/abi/uniswap/UniswapV2Router02.json rename to external/abi/uniswap/v2/UniswapV2Router02.json diff --git a/external/abi/uniswap/v3/SwapRouter.json b/external/abi/uniswap/v3/SwapRouter.json new file mode 100644 index 000000000..7e34a61f5 --- /dev/null +++ b/external/abi/uniswap/v3/SwapRouter.json @@ -0,0 +1,506 @@ +{ + "_format": "hh-sol-artifact-1", + "contractName": "SwapRouter", + "sourceName": "contracts/SwapRouter.sol", + "abi": [ + { + "inputs": [ + { + "internalType": "address", + "name": "_factory", + "type": "address" + }, + { + "internalType": "address", + "name": "_WETH9", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "WETH9", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "bytes", + "name": "path", + "type": "bytes" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountOutMinimum", + "type": "uint256" + } + ], + "internalType": "struct ISwapRouter.ExactInputParams", + "name": "params", + "type": "tuple" + } + ], + "name": "exactInput", + "outputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "tokenIn", + "type": "address" + }, + { + "internalType": "address", + "name": "tokenOut", + "type": "address" + }, + { + "internalType": "uint24", + "name": "fee", + "type": "uint24" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountOutMinimum", + "type": "uint256" + }, + { + "internalType": "uint160", + "name": "sqrtPriceLimitX96", + "type": "uint160" + } + ], + "internalType": "struct ISwapRouter.ExactInputSingleParams", + "name": "params", + "type": "tuple" + } + ], + "name": "exactInputSingle", + "outputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "bytes", + "name": "path", + "type": "bytes" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountInMaximum", + "type": "uint256" + } + ], + "internalType": "struct ISwapRouter.ExactOutputParams", + "name": "params", + "type": "tuple" + } + ], + "name": "exactOutput", + "outputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "tokenIn", + "type": "address" + }, + { + "internalType": "address", + "name": "tokenOut", + "type": "address" + }, + { + "internalType": "uint24", + "name": "fee", + "type": "uint24" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountInMaximum", + "type": "uint256" + }, + { + "internalType": "uint160", + "name": "sqrtPriceLimitX96", + "type": "uint160" + } + ], + "internalType": "struct ISwapRouter.ExactOutputSingleParams", + "name": "params", + "type": "tuple" + } + ], + "name": "exactOutputSingle", + "outputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "factory", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes[]", + "name": "data", + "type": "bytes[]" + } + ], + "name": "multicall", + "outputs": [ + { + "internalType": "bytes[]", + "name": "results", + "type": "bytes[]" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "selfPermit", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "expiry", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "selfPermitAllowed", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "expiry", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "selfPermitAllowedIfNecessary", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "selfPermitIfNecessary", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amountMinimum", + "type": "uint256" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" + } + ], + "name": "sweepToken", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "int256", + "name": "amount0Delta", + "type": "int256" + }, + { + "internalType": "int256", + "name": "amount1Delta", + "type": "int256" + }, + { + "internalType": "bytes", + "name": "_data", + "type": "bytes" + } + ], + "name": "uniswapV3SwapCallback", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountMinimum", + "type": "uint256" + }, + { + "internalType": "address", + "name": "recipient", + "type": "address" + } + ], + "name": "unwrapWETH9", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } + ], + "bytecode": "0x60c06040526000196000553480156200001757600080fd5b5060405162002b3238038062002b328339810160408190526200003a9162000076565b6001600160601b0319606092831b8116608052911b1660a052620000ad565b80516001600160a01b03811681146200007157600080fd5b919050565b6000806040838503121562000089578182fd5b620000948362000059565b9150620000a46020840162000059565b90509250929050565b60805160601c60a05160601c612a34620000fe6000398060fe5280610512528061064252806106dc52806117f5528061185852806118d9525080610b4b528061101952806119db5250612a346000f3fe6080604052600436106100e15760003560e01c8063c2e3140a1161007f578063df2ab5bb11610059578063df2ab5bb14610283578063f28c049814610296578063f3995c67146102a9578063fa461e33146102bc5761018c565b8063c2e3140a14610248578063c45a01551461025b578063db3e2198146102705761018c565b80634aa4a4fc116100bb5780634aa4a4fc146101e0578063a4a78f0c14610202578063ac9650d814610215578063c04b8d59146102355761018c565b8063414bf389146101915780634659a494146101ba57806349404b7c146101cd5761018c565b3661018c573373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461018a57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f4e6f742057455448390000000000000000000000000000000000000000000000604482015290519081900360640190fd5b005b600080fd5b6101a461019f36600461254f565b6102dc565b6040516101b191906128ff565b60405180910390f35b61018a6101c83660046122cd565b61044e565b61018a6101db366004612656565b61050e565b3480156101ec57600080fd5b506101f56106da565b6040516101b19190612745565b61018a6102103660046122cd565b6106fe565b61022861022336600461232d565b6107db565b6040516101b191906127b8565b6101a46102433660046124a4565b610935565b61018a6102563660046122cd565b610a94565b34801561026757600080fd5b506101f5610b49565b6101a461027e36600461254f565b610b6d565b61018a61029136600461228c565b610cfd565b6101a46102a436600461256b565b610e20565b61018a6102b73660046122cd565b610f54565b3480156102c857600080fd5b5061018a6102d73660046123bf565b610fec565b60008160800135806102ec61111b565b111561035957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f5472616e73616374696f6e20746f6f206f6c6400000000000000000000000000604482015290519081900360640190fd5b6103ff60a08401356103716080860160608701612269565b610382610100870160e08801612269565b604080518082019091528061039a60208a018a612269565b6103aa60608b0160408c01612633565b6103ba60408c0160208d01612269565b6040516020016103cc939291906126cf565b60405160208183030381529060405281526020013373ffffffffffffffffffffffffffffffffffffffff1681525061111f565b91508260c00135821015610448576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161043f90612880565b60405180910390fd5b50919050565b604080517f8fcbaf0c00000000000000000000000000000000000000000000000000000000815233600482015230602482015260448101879052606481018690526001608482015260ff851660a482015260c4810184905260e48101839052905173ffffffffffffffffffffffffffffffffffffffff881691638fcbaf0c9161010480830192600092919082900301818387803b1580156104ee57600080fd5b505af1158015610502573d6000803e3d6000fd5b50505050505050505050565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561059757600080fd5b505afa1580156105ab573d6000803e3d6000fd5b505050506040513d60208110156105c157600080fd5b50519050821561063a578281101561063a57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f496e73756666696369656e742057455448390000000000000000000000000000604482015290519081900360640190fd5b80156106d5577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632e1a7d4d826040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b1580156106b357600080fd5b505af11580156106c7573d6000803e3d6000fd5b505050506106d58282611285565b505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b604080517fdd62ed3e00000000000000000000000000000000000000000000000000000000815233600482015230602482015290517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9173ffffffffffffffffffffffffffffffffffffffff89169163dd62ed3e91604480820192602092909190829003018186803b15801561079357600080fd5b505afa1580156107a7573d6000803e3d6000fd5b505050506040513d60208110156107bd57600080fd5b505110156107d3576107d386868686868661044e565b505050505050565b60608167ffffffffffffffff811180156107f457600080fd5b5060405190808252806020026020018201604052801561082857816020015b60608152602001906001900390816108135790505b50905060005b8281101561092e576000803086868581811061084657fe5b90506020028101906108589190612908565b604051610866929190612735565b600060405180830381855af49150503d80600081146108a1576040519150601f19603f3d011682016040523d82523d6000602084013e6108a6565b606091505b50915091508161090c576044815110156108bf57600080fd5b600481019050808060200190518101906108d9919061243a565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161043f9190612836565b8084848151811061091957fe5b6020908102919091010152505060010161082e565b5092915050565b600081604001518061094561111b565b11156109b257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f5472616e73616374696f6e20746f6f206f6c6400000000000000000000000000604482015290519081900360640190fd5b335b60006109c385600001516113d3565b9050610a1c8560600151826109dc5786602001516109de565b305b600060405180604001604052806109f88b600001516113df565b81526020018773ffffffffffffffffffffffffffffffffffffffff1681525061111f565b60608601528015610a3c578451309250610a35906113f4565b8552610a49565b8460600151935050610a4f565b506109b4565b8360800151831015610a8d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161043f90612880565b5050919050565b604080517fdd62ed3e0000000000000000000000000000000000000000000000000000000081523360048201523060248201529051869173ffffffffffffffffffffffffffffffffffffffff89169163dd62ed3e91604480820192602092909190829003018186803b158015610b0957600080fd5b505afa158015610b1d573d6000803e3d6000fd5b505050506040513d6020811015610b3357600080fd5b505110156107d3576107d3868686868686610f54565b7f000000000000000000000000000000000000000000000000000000000000000081565b6000816080013580610b7d61111b565b1115610bea57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f5472616e73616374696f6e20746f6f206f6c6400000000000000000000000000604482015290519081900360640190fd5b610c9360a0840135610c026080860160608701612269565b610c13610100870160e08801612269565b6040518060400160405280886020016020810190610c319190612269565b610c4160608b0160408c01612633565b610c4e60208c018c612269565b604051602001610c60939291906126cf565b60405160208183030381529060405281526020013373ffffffffffffffffffffffffffffffffffffffff16815250611429565b91508260c00135821115610cd3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161043f90612849565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600055919050565b60008373ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015610d6657600080fd5b505afa158015610d7a573d6000803e3d6000fd5b505050506040513d6020811015610d9057600080fd5b505190508215610e095782811015610e0957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f496e73756666696369656e7420746f6b656e0000000000000000000000000000604482015290519081900360640190fd5b8015610e1a57610e1a8483836115c5565b50505050565b6000816040013580610e3061111b565b1115610e9d57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f5472616e73616374696f6e20746f6f206f6c6400000000000000000000000000604482015290519081900360640190fd5b610f106060840135610eb56040860160208701612269565b6040805180820190915260009080610ecd8980612908565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050509082525033602090910152611429565b5060005491508260800135821115610cd3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161043f90612849565b604080517fd505accf000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481018790526064810186905260ff8516608482015260a4810184905260c48101839052905173ffffffffffffffffffffffffffffffffffffffff88169163d505accf9160e480830192600092919082900301818387803b1580156104ee57600080fd5b6000610ffa828401846125a3565b9050600080600061100e84600001516117a1565b9250925092506110407f00000000000000000000000000000000000000000000000000000000000000008484846117d2565b5060008060008a13611081578473ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1610896110b2565b8373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16108a5b9150915081156110d1576110cc85876020015133846117f1565b610502565b85516110dc906113d3565b156111015785516110ec906113f4565b86526110fb8133600089611429565b50610502565b8060008190555083945061050285876020015133846117f1565b4290565b60008060008061113285600001516117a1565b9194509250905073ffffffffffffffffffffffffffffffffffffffff808316908416106000806111638686866119d4565b73ffffffffffffffffffffffffffffffffffffffff1663128acb088b856111898f611a12565b73ffffffffffffffffffffffffffffffffffffffff8e16156111ab578d6111d1565b876111ca5773fffd8963efd1fc6a506488495d951d5263988d256111d1565b6401000276a45b8d6040516020016111e291906128b7565b6040516020818303038152906040526040518663ffffffff1660e01b8152600401611211959493929190612766565b6040805180830381600087803b15801561122a57600080fd5b505af115801561123e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611262919061239c565b91509150826112715781611273565b805b6000039b9a5050505050505050505050565b6040805160008082526020820190925273ffffffffffffffffffffffffffffffffffffffff84169083906040518082805190602001908083835b602083106112fc57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016112bf565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d806000811461135e576040519150601f19603f3d011682016040523d82523d6000602084013e611363565b606091505b50509050806106d557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600360248201527f5354450000000000000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b8051604211155b919050565b60606113ee826000602b611a44565b92915050565b80516060906113ee9083906017907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe901611a44565b60008060008061143c85600001516117a1565b9194509250905073ffffffffffffffffffffffffffffffffffffffff8084169083161060008061146d8587866119d4565b73ffffffffffffffffffffffffffffffffffffffff1663128acb088b856114938f611a12565b60000373ffffffffffffffffffffffffffffffffffffffff8e16156114b8578d6114de565b876114d75773fffd8963efd1fc6a506488495d951d5263988d256114de565b6401000276a45b8d6040516020016114ef91906128b7565b6040516020818303038152906040526040518663ffffffff1660e01b815260040161151e959493929190612766565b6040805180830381600087803b15801561153757600080fd5b505af115801561154b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061156f919061239c565b9150915060008361158457818360000361158a565b82826000035b909850905073ffffffffffffffffffffffffffffffffffffffff8a166115b6578b81146115b657600080fd5b50505050505050949350505050565b6040805173ffffffffffffffffffffffffffffffffffffffff8481166024830152604480830185905283518084039091018152606490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001781529251825160009485949389169392918291908083835b6020831061169a57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161165d565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d80600081146116fc576040519150601f19603f3d011682016040523d82523d6000602084013e611701565b606091505b509150915081801561172f57508051158061172f575080806020019051602081101561172c57600080fd5b50515b61179a57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600260248201527f5354000000000000000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b5050505050565b600080806117af8482611c2b565b92506117bc846014611d2b565b90506117c9846017611c2b565b91509193909250565b60006117e8856117e3868686611e1b565b611e98565b95945050505050565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff161480156118515750814791508110155b1561199a577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b1580156118be57600080fd5b505af11580156118d2573d6000803e3d6000fd5b50505050507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb84846040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b15801561196857600080fd5b505af115801561197c573d6000803e3d6000fd5b505050506040513d602081101561199257600080fd5b5061179a9050565b73ffffffffffffffffffffffffffffffffffffffff84163014156119c8576119c38584846115c5565b61179a565b61179a85858585611ec8565b6000611a0a7f0000000000000000000000000000000000000000000000000000000000000000611a05868686611e1b565b6120a5565b949350505050565b60007f80000000000000000000000000000000000000000000000000000000000000008210611a4057600080fd5b5090565b60608182601f011015611ab857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f736c6963655f6f766572666c6f77000000000000000000000000000000000000604482015290519081900360640190fd5b828284011015611b2957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f736c6963655f6f766572666c6f77000000000000000000000000000000000000604482015290519081900360640190fd5b81830184511015611b9b57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f736c6963655f6f75744f66426f756e6473000000000000000000000000000000604482015290519081900360640190fd5b606082158015611bba5760405191506000825260208201604052611c22565b6040519150601f8416801560200281840101858101878315602002848b0101015b81831015611bf3578051835260209283019201611bdb565b5050858452601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016604052505b50949350505050565b600081826014011015611c9f57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f746f416464726573735f6f766572666c6f770000000000000000000000000000604482015290519081900360640190fd5b8160140183511015611d1257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f746f416464726573735f6f75744f66426f756e64730000000000000000000000604482015290519081900360640190fd5b5001602001516c01000000000000000000000000900490565b600081826003011015611d9f57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f746f55696e7432345f6f766572666c6f77000000000000000000000000000000604482015290519081900360640190fd5b8160030183511015611e1257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f746f55696e7432345f6f75744f66426f756e6473000000000000000000000000604482015290519081900360640190fd5b50016003015190565b611e236121db565b8273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161115611e5b579192915b506040805160608101825273ffffffffffffffffffffffffffffffffffffffff948516815292909316602083015262ffffff169181019190915290565b6000611ea483836120a5565b90503373ffffffffffffffffffffffffffffffffffffffff8216146113ee57600080fd5b6040805173ffffffffffffffffffffffffffffffffffffffff85811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd00000000000000000000000000000000000000000000000000000000178152925182516000948594938a169392918291908083835b60208310611fa557805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101611f68565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114612007576040519150601f19603f3d011682016040523d82523d6000602084013e61200c565b606091505b509150915081801561203a57508051158061203a575080806020019051602081101561203757600080fd5b50515b6107d357604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600360248201527f5354460000000000000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b6000816020015173ffffffffffffffffffffffffffffffffffffffff16826000015173ffffffffffffffffffffffffffffffffffffffff16106120e757600080fd5b508051602080830151604093840151845173ffffffffffffffffffffffffffffffffffffffff94851681850152939091168385015262ffffff166060808401919091528351808403820181526080840185528051908301207fff0000000000000000000000000000000000000000000000000000000000000060a085015294901b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660a183015260b58201939093527fa8180af292c6986c74fa300a542e049db8a89221e2452e431c3d8103b610c56860d5808301919091528251808303909101815260f5909101909152805191012090565b604080516060810182526000808252602082018190529181019190915290565b80356113da81612a02565b600082601f830112612216578081fd5b813561222961222482612996565b612972565b81815284602083860101111561223d578283fd5b816020850160208301379081016020019190915292915050565b60006101008284031215610448578081fd5b60006020828403121561227a578081fd5b813561228581612a02565b9392505050565b6000806000606084860312156122a0578182fd5b83356122ab81612a02565b92506020840135915060408401356122c281612a02565b809150509250925092565b60008060008060008060c087890312156122e5578182fd5b86356122f081612a02565b95506020870135945060408701359350606087013560ff81168114612313578283fd5b9598949750929560808101359460a0909101359350915050565b6000806020838503121561233f578182fd5b823567ffffffffffffffff80821115612356578384fd5b818501915085601f830112612369578384fd5b813581811115612377578485fd5b866020808302850101111561238a578485fd5b60209290920196919550909350505050565b600080604083850312156123ae578182fd5b505080516020909101519092909150565b600080600080606085870312156123d4578384fd5b8435935060208501359250604085013567ffffffffffffffff808211156123f9578384fd5b818701915087601f83011261240c578384fd5b81358181111561241a578485fd5b88602082850101111561242b578485fd5b95989497505060200194505050565b60006020828403121561244b578081fd5b815167ffffffffffffffff811115612461578182fd5b8201601f81018413612471578182fd5b805161247f61222482612996565b818152856020838501011115612493578384fd5b6117e88260208301602086016129d6565b6000602082840312156124b5578081fd5b813567ffffffffffffffff808211156124cc578283fd5b9083019060a082860312156124df578283fd5b60405160a0810181811083821117156124f457fe5b604052823582811115612505578485fd5b61251187828601612206565b825250612520602084016121fb565b602082015260408301356040820152606083013560608201526080830135608082015280935050505092915050565b60006101008284031215612561578081fd5b6122858383612257565b60006020828403121561257c578081fd5b813567ffffffffffffffff811115612592578182fd5b820160a08185031215612285578182fd5b6000602082840312156125b4578081fd5b813567ffffffffffffffff808211156125cb578283fd5b90830190604082860312156125de578283fd5b6040516040810181811083821117156125f357fe5b604052823582811115612604578485fd5b61261087828601612206565b8252506020830135925061262383612a02565b6020810192909252509392505050565b600060208284031215612644578081fd5b813562ffffff81168114612285578182fd5b60008060408385031215612668578182fd5b82359150602083013561267a81612a02565b809150509250929050565b6000815180845261269d8160208601602086016129d6565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b606093841b7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000908116825260e89390931b7fffffff0000000000000000000000000000000000000000000000000000000000166014820152921b166017820152602b0190565b6000828483379101908152919050565b73ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b600073ffffffffffffffffffffffffffffffffffffffff8088168352861515602084015285604084015280851660608401525060a060808301526127ad60a0830184612685565b979650505050505050565b6000602080830181845280855180835260408601915060408482028701019250838701855b82811015612829577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452612817858351612685565b945092850192908501906001016127dd565b5092979650505050505050565b6000602082526122856020830184612685565b60208082526012908201527f546f6f206d756368207265717565737465640000000000000000000000000000604082015260600190565b60208082526013908201527f546f6f206c6974746c6520726563656976656400000000000000000000000000604082015260600190565b6000602082528251604060208401526128d36060840182612685565b905073ffffffffffffffffffffffffffffffffffffffff60208501511660408401528091505092915050565b90815260200190565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261293c578283fd5b83018035915067ffffffffffffffff821115612956578283fd5b60200191503681900382131561296b57600080fd5b9250929050565b60405181810167ffffffffffffffff8111828210171561298e57fe5b604052919050565b600067ffffffffffffffff8211156129aa57fe5b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60005b838110156129f15781810151838201526020016129d9565b83811115610e1a5750506000910152565b73ffffffffffffffffffffffffffffffffffffffff81168114612a2457600080fd5b5056fea164736f6c6343000706000a", + "deployedBytecode": "0x6080604052600436106100e15760003560e01c8063c2e3140a1161007f578063df2ab5bb11610059578063df2ab5bb14610283578063f28c049814610296578063f3995c67146102a9578063fa461e33146102bc5761018c565b8063c2e3140a14610248578063c45a01551461025b578063db3e2198146102705761018c565b80634aa4a4fc116100bb5780634aa4a4fc146101e0578063a4a78f0c14610202578063ac9650d814610215578063c04b8d59146102355761018c565b8063414bf389146101915780634659a494146101ba57806349404b7c146101cd5761018c565b3661018c573373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461018a57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f4e6f742057455448390000000000000000000000000000000000000000000000604482015290519081900360640190fd5b005b600080fd5b6101a461019f36600461254f565b6102dc565b6040516101b191906128ff565b60405180910390f35b61018a6101c83660046122cd565b61044e565b61018a6101db366004612656565b61050e565b3480156101ec57600080fd5b506101f56106da565b6040516101b19190612745565b61018a6102103660046122cd565b6106fe565b61022861022336600461232d565b6107db565b6040516101b191906127b8565b6101a46102433660046124a4565b610935565b61018a6102563660046122cd565b610a94565b34801561026757600080fd5b506101f5610b49565b6101a461027e36600461254f565b610b6d565b61018a61029136600461228c565b610cfd565b6101a46102a436600461256b565b610e20565b61018a6102b73660046122cd565b610f54565b3480156102c857600080fd5b5061018a6102d73660046123bf565b610fec565b60008160800135806102ec61111b565b111561035957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f5472616e73616374696f6e20746f6f206f6c6400000000000000000000000000604482015290519081900360640190fd5b6103ff60a08401356103716080860160608701612269565b610382610100870160e08801612269565b604080518082019091528061039a60208a018a612269565b6103aa60608b0160408c01612633565b6103ba60408c0160208d01612269565b6040516020016103cc939291906126cf565b60405160208183030381529060405281526020013373ffffffffffffffffffffffffffffffffffffffff1681525061111f565b91508260c00135821015610448576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161043f90612880565b60405180910390fd5b50919050565b604080517f8fcbaf0c00000000000000000000000000000000000000000000000000000000815233600482015230602482015260448101879052606481018690526001608482015260ff851660a482015260c4810184905260e48101839052905173ffffffffffffffffffffffffffffffffffffffff881691638fcbaf0c9161010480830192600092919082900301818387803b1580156104ee57600080fd5b505af1158015610502573d6000803e3d6000fd5b50505050505050505050565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561059757600080fd5b505afa1580156105ab573d6000803e3d6000fd5b505050506040513d60208110156105c157600080fd5b50519050821561063a578281101561063a57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f496e73756666696369656e742057455448390000000000000000000000000000604482015290519081900360640190fd5b80156106d5577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632e1a7d4d826040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b1580156106b357600080fd5b505af11580156106c7573d6000803e3d6000fd5b505050506106d58282611285565b505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b604080517fdd62ed3e00000000000000000000000000000000000000000000000000000000815233600482015230602482015290517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9173ffffffffffffffffffffffffffffffffffffffff89169163dd62ed3e91604480820192602092909190829003018186803b15801561079357600080fd5b505afa1580156107a7573d6000803e3d6000fd5b505050506040513d60208110156107bd57600080fd5b505110156107d3576107d386868686868661044e565b505050505050565b60608167ffffffffffffffff811180156107f457600080fd5b5060405190808252806020026020018201604052801561082857816020015b60608152602001906001900390816108135790505b50905060005b8281101561092e576000803086868581811061084657fe5b90506020028101906108589190612908565b604051610866929190612735565b600060405180830381855af49150503d80600081146108a1576040519150601f19603f3d011682016040523d82523d6000602084013e6108a6565b606091505b50915091508161090c576044815110156108bf57600080fd5b600481019050808060200190518101906108d9919061243a565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161043f9190612836565b8084848151811061091957fe5b6020908102919091010152505060010161082e565b5092915050565b600081604001518061094561111b565b11156109b257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f5472616e73616374696f6e20746f6f206f6c6400000000000000000000000000604482015290519081900360640190fd5b335b60006109c385600001516113d3565b9050610a1c8560600151826109dc5786602001516109de565b305b600060405180604001604052806109f88b600001516113df565b81526020018773ffffffffffffffffffffffffffffffffffffffff1681525061111f565b60608601528015610a3c578451309250610a35906113f4565b8552610a49565b8460600151935050610a4f565b506109b4565b8360800151831015610a8d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161043f90612880565b5050919050565b604080517fdd62ed3e0000000000000000000000000000000000000000000000000000000081523360048201523060248201529051869173ffffffffffffffffffffffffffffffffffffffff89169163dd62ed3e91604480820192602092909190829003018186803b158015610b0957600080fd5b505afa158015610b1d573d6000803e3d6000fd5b505050506040513d6020811015610b3357600080fd5b505110156107d3576107d3868686868686610f54565b7f000000000000000000000000000000000000000000000000000000000000000081565b6000816080013580610b7d61111b565b1115610bea57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f5472616e73616374696f6e20746f6f206f6c6400000000000000000000000000604482015290519081900360640190fd5b610c9360a0840135610c026080860160608701612269565b610c13610100870160e08801612269565b6040518060400160405280886020016020810190610c319190612269565b610c4160608b0160408c01612633565b610c4e60208c018c612269565b604051602001610c60939291906126cf565b60405160208183030381529060405281526020013373ffffffffffffffffffffffffffffffffffffffff16815250611429565b91508260c00135821115610cd3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161043f90612849565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600055919050565b60008373ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015610d6657600080fd5b505afa158015610d7a573d6000803e3d6000fd5b505050506040513d6020811015610d9057600080fd5b505190508215610e095782811015610e0957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f496e73756666696369656e7420746f6b656e0000000000000000000000000000604482015290519081900360640190fd5b8015610e1a57610e1a8483836115c5565b50505050565b6000816040013580610e3061111b565b1115610e9d57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f5472616e73616374696f6e20746f6f206f6c6400000000000000000000000000604482015290519081900360640190fd5b610f106060840135610eb56040860160208701612269565b6040805180820190915260009080610ecd8980612908565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050509082525033602090910152611429565b5060005491508260800135821115610cd3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161043f90612849565b604080517fd505accf000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481018790526064810186905260ff8516608482015260a4810184905260c48101839052905173ffffffffffffffffffffffffffffffffffffffff88169163d505accf9160e480830192600092919082900301818387803b1580156104ee57600080fd5b6000610ffa828401846125a3565b9050600080600061100e84600001516117a1565b9250925092506110407f00000000000000000000000000000000000000000000000000000000000000008484846117d2565b5060008060008a13611081578473ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1610896110b2565b8373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16108a5b9150915081156110d1576110cc85876020015133846117f1565b610502565b85516110dc906113d3565b156111015785516110ec906113f4565b86526110fb8133600089611429565b50610502565b8060008190555083945061050285876020015133846117f1565b4290565b60008060008061113285600001516117a1565b9194509250905073ffffffffffffffffffffffffffffffffffffffff808316908416106000806111638686866119d4565b73ffffffffffffffffffffffffffffffffffffffff1663128acb088b856111898f611a12565b73ffffffffffffffffffffffffffffffffffffffff8e16156111ab578d6111d1565b876111ca5773fffd8963efd1fc6a506488495d951d5263988d256111d1565b6401000276a45b8d6040516020016111e291906128b7565b6040516020818303038152906040526040518663ffffffff1660e01b8152600401611211959493929190612766565b6040805180830381600087803b15801561122a57600080fd5b505af115801561123e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611262919061239c565b91509150826112715781611273565b805b6000039b9a5050505050505050505050565b6040805160008082526020820190925273ffffffffffffffffffffffffffffffffffffffff84169083906040518082805190602001908083835b602083106112fc57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016112bf565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d806000811461135e576040519150601f19603f3d011682016040523d82523d6000602084013e611363565b606091505b50509050806106d557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600360248201527f5354450000000000000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b8051604211155b919050565b60606113ee826000602b611a44565b92915050565b80516060906113ee9083906017907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe901611a44565b60008060008061143c85600001516117a1565b9194509250905073ffffffffffffffffffffffffffffffffffffffff8084169083161060008061146d8587866119d4565b73ffffffffffffffffffffffffffffffffffffffff1663128acb088b856114938f611a12565b60000373ffffffffffffffffffffffffffffffffffffffff8e16156114b8578d6114de565b876114d75773fffd8963efd1fc6a506488495d951d5263988d256114de565b6401000276a45b8d6040516020016114ef91906128b7565b6040516020818303038152906040526040518663ffffffff1660e01b815260040161151e959493929190612766565b6040805180830381600087803b15801561153757600080fd5b505af115801561154b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061156f919061239c565b9150915060008361158457818360000361158a565b82826000035b909850905073ffffffffffffffffffffffffffffffffffffffff8a166115b6578b81146115b657600080fd5b50505050505050949350505050565b6040805173ffffffffffffffffffffffffffffffffffffffff8481166024830152604480830185905283518084039091018152606490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001781529251825160009485949389169392918291908083835b6020831061169a57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161165d565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d80600081146116fc576040519150601f19603f3d011682016040523d82523d6000602084013e611701565b606091505b509150915081801561172f57508051158061172f575080806020019051602081101561172c57600080fd5b50515b61179a57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600260248201527f5354000000000000000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b5050505050565b600080806117af8482611c2b565b92506117bc846014611d2b565b90506117c9846017611c2b565b91509193909250565b60006117e8856117e3868686611e1b565b611e98565b95945050505050565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff161480156118515750814791508110155b1561199a577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b1580156118be57600080fd5b505af11580156118d2573d6000803e3d6000fd5b50505050507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb84846040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b15801561196857600080fd5b505af115801561197c573d6000803e3d6000fd5b505050506040513d602081101561199257600080fd5b5061179a9050565b73ffffffffffffffffffffffffffffffffffffffff84163014156119c8576119c38584846115c5565b61179a565b61179a85858585611ec8565b6000611a0a7f0000000000000000000000000000000000000000000000000000000000000000611a05868686611e1b565b6120a5565b949350505050565b60007f80000000000000000000000000000000000000000000000000000000000000008210611a4057600080fd5b5090565b60608182601f011015611ab857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f736c6963655f6f766572666c6f77000000000000000000000000000000000000604482015290519081900360640190fd5b828284011015611b2957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f736c6963655f6f766572666c6f77000000000000000000000000000000000000604482015290519081900360640190fd5b81830184511015611b9b57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f736c6963655f6f75744f66426f756e6473000000000000000000000000000000604482015290519081900360640190fd5b606082158015611bba5760405191506000825260208201604052611c22565b6040519150601f8416801560200281840101858101878315602002848b0101015b81831015611bf3578051835260209283019201611bdb565b5050858452601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016604052505b50949350505050565b600081826014011015611c9f57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f746f416464726573735f6f766572666c6f770000000000000000000000000000604482015290519081900360640190fd5b8160140183511015611d1257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f746f416464726573735f6f75744f66426f756e64730000000000000000000000604482015290519081900360640190fd5b5001602001516c01000000000000000000000000900490565b600081826003011015611d9f57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f746f55696e7432345f6f766572666c6f77000000000000000000000000000000604482015290519081900360640190fd5b8160030183511015611e1257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f746f55696e7432345f6f75744f66426f756e6473000000000000000000000000604482015290519081900360640190fd5b50016003015190565b611e236121db565b8273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161115611e5b579192915b506040805160608101825273ffffffffffffffffffffffffffffffffffffffff948516815292909316602083015262ffffff169181019190915290565b6000611ea483836120a5565b90503373ffffffffffffffffffffffffffffffffffffffff8216146113ee57600080fd5b6040805173ffffffffffffffffffffffffffffffffffffffff85811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd00000000000000000000000000000000000000000000000000000000178152925182516000948594938a169392918291908083835b60208310611fa557805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101611f68565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114612007576040519150601f19603f3d011682016040523d82523d6000602084013e61200c565b606091505b509150915081801561203a57508051158061203a575080806020019051602081101561203757600080fd5b50515b6107d357604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600360248201527f5354460000000000000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b6000816020015173ffffffffffffffffffffffffffffffffffffffff16826000015173ffffffffffffffffffffffffffffffffffffffff16106120e757600080fd5b508051602080830151604093840151845173ffffffffffffffffffffffffffffffffffffffff94851681850152939091168385015262ffffff166060808401919091528351808403820181526080840185528051908301207fff0000000000000000000000000000000000000000000000000000000000000060a085015294901b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660a183015260b58201939093527fa8180af292c6986c74fa300a542e049db8a89221e2452e431c3d8103b610c56860d5808301919091528251808303909101815260f5909101909152805191012090565b604080516060810182526000808252602082018190529181019190915290565b80356113da81612a02565b600082601f830112612216578081fd5b813561222961222482612996565b612972565b81815284602083860101111561223d578283fd5b816020850160208301379081016020019190915292915050565b60006101008284031215610448578081fd5b60006020828403121561227a578081fd5b813561228581612a02565b9392505050565b6000806000606084860312156122a0578182fd5b83356122ab81612a02565b92506020840135915060408401356122c281612a02565b809150509250925092565b60008060008060008060c087890312156122e5578182fd5b86356122f081612a02565b95506020870135945060408701359350606087013560ff81168114612313578283fd5b9598949750929560808101359460a0909101359350915050565b6000806020838503121561233f578182fd5b823567ffffffffffffffff80821115612356578384fd5b818501915085601f830112612369578384fd5b813581811115612377578485fd5b866020808302850101111561238a578485fd5b60209290920196919550909350505050565b600080604083850312156123ae578182fd5b505080516020909101519092909150565b600080600080606085870312156123d4578384fd5b8435935060208501359250604085013567ffffffffffffffff808211156123f9578384fd5b818701915087601f83011261240c578384fd5b81358181111561241a578485fd5b88602082850101111561242b578485fd5b95989497505060200194505050565b60006020828403121561244b578081fd5b815167ffffffffffffffff811115612461578182fd5b8201601f81018413612471578182fd5b805161247f61222482612996565b818152856020838501011115612493578384fd5b6117e88260208301602086016129d6565b6000602082840312156124b5578081fd5b813567ffffffffffffffff808211156124cc578283fd5b9083019060a082860312156124df578283fd5b60405160a0810181811083821117156124f457fe5b604052823582811115612505578485fd5b61251187828601612206565b825250612520602084016121fb565b602082015260408301356040820152606083013560608201526080830135608082015280935050505092915050565b60006101008284031215612561578081fd5b6122858383612257565b60006020828403121561257c578081fd5b813567ffffffffffffffff811115612592578182fd5b820160a08185031215612285578182fd5b6000602082840312156125b4578081fd5b813567ffffffffffffffff808211156125cb578283fd5b90830190604082860312156125de578283fd5b6040516040810181811083821117156125f357fe5b604052823582811115612604578485fd5b61261087828601612206565b8252506020830135925061262383612a02565b6020810192909252509392505050565b600060208284031215612644578081fd5b813562ffffff81168114612285578182fd5b60008060408385031215612668578182fd5b82359150602083013561267a81612a02565b809150509250929050565b6000815180845261269d8160208601602086016129d6565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b606093841b7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000908116825260e89390931b7fffffff0000000000000000000000000000000000000000000000000000000000166014820152921b166017820152602b0190565b6000828483379101908152919050565b73ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b600073ffffffffffffffffffffffffffffffffffffffff8088168352861515602084015285604084015280851660608401525060a060808301526127ad60a0830184612685565b979650505050505050565b6000602080830181845280855180835260408601915060408482028701019250838701855b82811015612829577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452612817858351612685565b945092850192908501906001016127dd565b5092979650505050505050565b6000602082526122856020830184612685565b60208082526012908201527f546f6f206d756368207265717565737465640000000000000000000000000000604082015260600190565b60208082526013908201527f546f6f206c6974746c6520726563656976656400000000000000000000000000604082015260600190565b6000602082528251604060208401526128d36060840182612685565b905073ffffffffffffffffffffffffffffffffffffffff60208501511660408401528091505092915050565b90815260200190565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261293c578283fd5b83018035915067ffffffffffffffff821115612956578283fd5b60200191503681900382131561296b57600080fd5b9250929050565b60405181810167ffffffffffffffff8111828210171561298e57fe5b604052919050565b600067ffffffffffffffff8211156129aa57fe5b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60005b838110156129f15781810151838201526020016129d9565b83811115610e1a5750506000910152565b73ffffffffffffffffffffffffffffffffffffffff81168114612a2457600080fd5b5056fea164736f6c6343000706000a", + "linkReferences": {}, + "deployedLinkReferences": {} +} diff --git a/external/abi/uniswap/v3/UniswapV3Factory.json b/external/abi/uniswap/v3/UniswapV3Factory.json new file mode 100644 index 000000000..3db211836 --- /dev/null +++ b/external/abi/uniswap/v3/UniswapV3Factory.json @@ -0,0 +1,245 @@ +{ + "_format": "hh-sol-artifact-1", + "contractName": "UniswapV3Factory", + "sourceName": "contracts/UniswapV3Factory.sol", + "abi": [ + { + "inputs": [], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint24", + "name": "fee", + "type": "uint24" + }, + { + "indexed": true, + "internalType": "int24", + "name": "tickSpacing", + "type": "int24" + } + ], + "name": "FeeAmountEnabled", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "oldOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnerChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "token0", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "token1", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint24", + "name": "fee", + "type": "uint24" + }, + { + "indexed": false, + "internalType": "int24", + "name": "tickSpacing", + "type": "int24" + }, + { + "indexed": false, + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "PoolCreated", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "tokenA", + "type": "address" + }, + { + "internalType": "address", + "name": "tokenB", + "type": "address" + }, + { + "internalType": "uint24", + "name": "fee", + "type": "uint24" + } + ], + "name": "createPool", + "outputs": [ + { + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint24", + "name": "fee", + "type": "uint24" + }, + { + "internalType": "int24", + "name": "tickSpacing", + "type": "int24" + } + ], + "name": "enableFeeAmount", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint24", + "name": "", + "type": "uint24" + } + ], + "name": "feeAmountTickSpacing", + "outputs": [ + { + "internalType": "int24", + "name": "", + "type": "int24" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "uint24", + "name": "", + "type": "uint24" + } + ], + "name": "getPool", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "parameters", + "outputs": [ + { + "internalType": "address", + "name": "factory", + "type": "address" + }, + { + "internalType": "address", + "name": "token0", + "type": "address" + }, + { + "internalType": "address", + "name": "token1", + "type": "address" + }, + { + "internalType": "uint24", + "name": "fee", + "type": "uint24" + }, + { + "internalType": "int24", + "name": "tickSpacing", + "type": "int24" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_owner", + "type": "address" + } + ], + "name": "setOwner", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "bytecode": "0x60a060405234801561001057600080fd5b503060601b608052600380546001600160a01b031916339081179091556040516000907fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c908290a36101f4600081815260046020527ffb8cf1d12598d1a039dd1d106665851a96aadf67d0d9ed76fceea282119208b7805462ffffff1916600a90811790915560405190929160008051602061614b83398151915291a3610bb8600081815260046020527f72dffa9b822156d9cf4b0090fa0b656bcb9cc2b2c60eb6acfc20a34f54b31743805462ffffff1916603c90811790915560405190929160008051602061614b83398151915291a3612710600081815260046020527f8cc740d51daa94ff54f33bd779c2d20149f524c340519b49181be5a08615f829805462ffffff191660c890811790915560405190929160008051602061614b83398151915291a360805160601c615fd7610174600039806105515250615fd76000f3fe608060405234801561001057600080fd5b506004361061007d5760003560e01c8063890357301161005b578063890357301461013b5780638a7c195f146101855780638da5cb5b146101b0578063a1671295146101b85761007d565b806313af4035146100825780631698ee82146100aa57806322afcccb14610102575b600080fd5b6100a86004803603602081101561009857600080fd5b50356001600160a01b03166101f4565b005b6100e6600480360360608110156100c057600080fd5b5080356001600160a01b03908116916020810135909116906040013562ffffff16610267565b604080516001600160a01b039092168252519081900360200190f35b6101246004803603602081101561011857600080fd5b503562ffffff16610293565b6040805160029290920b8252519081900360200190f35b6101436102a8565b604080516001600160a01b0396871681529486166020860152929094168383015262ffffff16606083015260029290920b608082015290519081900360a00190f35b6100a86004803603604081101561019b57600080fd5b5062ffffff813516906020013560020b6102de565b6100e66103a1565b6100e6600480360360608110156101ce57600080fd5b5080356001600160a01b03908116916020810135909116906040013562ffffff166103b0565b6003546001600160a01b0316331461020b57600080fd5b6003546040516001600160a01b038084169216907fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c90600090a3600380546001600160a01b0319166001600160a01b0392909216919091179055565b60056020908152600093845260408085208252928452828420905282529020546001600160a01b031681565b60046020526000908152604090205460020b81565b600054600154600280546001600160a01b03938416939283169281169162ffffff600160a01b83041691600160b81b9004900b85565b6003546001600160a01b031633146102f557600080fd5b620f42408262ffffff161061030957600080fd5b60008160020b13801561032057506140008160020b125b61032957600080fd5b62ffffff8216600090815260046020526040902054600290810b900b1561034f57600080fd5b62ffffff828116600081815260046020526040808220805462ffffff1916600287900b958616179055517fc66a3fdf07232cdd185febcc6579d408c241b47ae2f9907d84be655141eeaecc9190a35050565b6003546001600160a01b031681565b60006103ba610546565b826001600160a01b0316846001600160a01b031614156103d957600080fd5b600080846001600160a01b0316866001600160a01b0316106103fc5784866103ff565b85855b90925090506001600160a01b03821661041757600080fd5b62ffffff8416600090815260046020526040902054600290810b9081900b61043e57600080fd5b6001600160a01b0383811660009081526005602090815260408083208685168452825280832062ffffff8a168452909152902054161561047d57600080fd5b61048a308484888561057d565b6001600160a01b03808516600081815260056020818152604080842089871680865290835281852062ffffff8e168087529084528286208054988a166001600160a01b0319998a1681179091558287529484528286208787528452828620818752845294829020805490971684179096558051600289900b815291820192909252815195995091947f783cca1c0412dd0d695e784568c96da2e9c22ff989357a2e8b1d9b2b4e6b71189281900390910190a45050509392505050565b306001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461057b57600080fd5b565b6040805160a0810182526001600160a01b03878116808352878216602080850182905292881684860181905262ffffff888116606080880182905260028a810b6080998a01819052600080546001600160a01b03199081169099178155600180548a1689179055825490981686177fffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffff16600160a01b8502177fffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffff16600160b81b91830b9095160293909317909255875180870194909452838801929092528281019190915285518083039091018152930193849052825192909101919091209091610686906106f5565b8190604051809103906000f59050801580156106a6573d6000803e3d6000fd5b50600080546001600160a01b0319908116909155600180549091169055600280547fffffffffffff00000000000000000000000000000000000000000000000000001690559695505050505050565b6158c8806107038339019056fe6101606040523480156200001257600080fd5b503060601b60805260408051630890357360e41b81529051600091339163890357309160048082019260a092909190829003018186803b1580156200005657600080fd5b505afa1580156200006b573d6000803e3d6000fd5b505050506040513d60a08110156200008257600080fd5b508051602080830151604084015160608086015160809096015160e896871b6001600160e81b0319166101005291811b6001600160601b031990811660e05292811b831660c0529390931b1660a052600282810b900b90921b610120529150620000f79082906200010f811b62002b8417901c565b60801b6001600160801b03191661014052506200017d565b60008082600281900b620d89e719816200012557fe5b05029050600083600281900b620d89e8816200013d57fe5b0502905060008460020b83830360020b816200015557fe5b0560010190508062ffffff166001600160801b038016816200017357fe5b0495945050505050565b60805160601c60a05160601c60c05160601c60e05160601c6101005160e81c6101205160e81c6101405160801c61567e6200024a60003980611fee5280614b5f5280614b96525080610c0052806128fd5280614bca5280614bfc525080610cef52806119cb5280611a0252806129455250806111c75280611a855280611ef4528061244452806129215280613e6b5250806108d252806112f55280611a545280611e8e52806123be5280613d2252508061207b528061227d52806128d9525080612bfb525061567e6000f3fe608060405234801561001057600080fd5b50600436106101ae5760003560e01c806370cf754a116100ee578063c45a015511610097578063ddca3f4311610071578063ddca3f4314610800578063f305839914610820578063f30dba9314610828578063f637731d146108aa576101ae565b8063c45a0155146107d1578063d0c93a7c146107d9578063d21220a7146107f8576101ae565b8063883bdbfd116100c8578063883bdbfd14610633578063a34123a71461073c578063a38807f214610776576101ae565b806370cf754a146105c65780638206a4d1146105ce57806385b66729146105f6576101ae565b80633850c7bd1161015b578063490e6cbc11610135578063490e6cbc146104705780634f1eb3d8146104fc578063514ea4bf1461054d5780635339c296146105a6576101ae565b80633850c7bd1461035b5780633c8a7d8d146103b45780634614131914610456576101ae565b80631ad8b03b1161018c5780631ad8b03b146102aa578063252c09d7146102e157806332148f6714610338576101ae565b80630dfe1681146101b3578063128acb08146101d75780631a68650214610286575b600080fd5b6101bb6108d0565b604080516001600160a01b039092168252519081900360200190f35b61026d600480360360a08110156101ed57600080fd5b6001600160a01b0382358116926020810135151592604082013592606083013516919081019060a08101608082013564010000000081111561022e57600080fd5b82018360208201111561024057600080fd5b8035906020019184600183028401116401000000008311171561026257600080fd5b5090925090506108f4565b6040805192835260208301919091528051918290030190f35b61028e6114ad565b604080516001600160801b039092168252519081900360200190f35b6102b26114bc565b60405180836001600160801b03168152602001826001600160801b031681526020019250505060405180910390f35b6102fe600480360360208110156102f757600080fd5b50356114d6565b6040805163ffffffff909516855260069390930b60208501526001600160a01b039091168383015215156060830152519081900360800190f35b6103596004803603602081101561034e57600080fd5b503561ffff1661151c565b005b610363611616565b604080516001600160a01b03909816885260029690960b602088015261ffff9485168787015292841660608701529216608085015260ff90911660a0840152151560c0830152519081900360e00190f35b61026d600480360360a08110156103ca57600080fd5b6001600160a01b03823516916020810135600290810b92604083013590910b916001600160801b036060820135169181019060a08101608082013564010000000081111561041757600080fd5b82018360208201111561042957600080fd5b8035906020019184600183028401116401000000008311171561044b57600080fd5b509092509050611666565b61045e611922565b60408051918252519081900360200190f35b6103596004803603608081101561048657600080fd5b6001600160a01b0382351691602081013591604082013591908101906080810160608201356401000000008111156104bd57600080fd5b8201836020820111156104cf57600080fd5b803590602001918460018302840111640100000000831117156104f157600080fd5b509092509050611928565b6102b2600480360360a081101561051257600080fd5b506001600160a01b03813516906020810135600290810b91604081013590910b906001600160801b0360608201358116916080013516611d83565b61056a6004803603602081101561056357600080fd5b5035611f9d565b604080516001600160801b0396871681526020810195909552848101939093529084166060840152909216608082015290519081900360a00190f35b61045e600480360360208110156105bc57600080fd5b503560010b611fda565b61028e611fec565b610359600480360360408110156105e457600080fd5b5060ff81358116916020013516612010565b6102b26004803603606081101561060c57600080fd5b506001600160a01b03813516906001600160801b036020820135811691604001351661220f565b6106a36004803603602081101561064957600080fd5b81019060208101813564010000000081111561066457600080fd5b82018360208201111561067657600080fd5b8035906020019184602083028401116401000000008311171561069857600080fd5b5090925090506124dc565b604051808060200180602001838103835285818151815260200191508051906020019060200280838360005b838110156106e75781810151838201526020016106cf565b50505050905001838103825284818151815260200191508051906020019060200280838360005b8381101561072657818101518382015260200161070e565b5050505090500194505050505060405180910390f35b61026d6004803603606081101561075257600080fd5b508035600290810b91602081013590910b90604001356001600160801b0316612569565b6107a06004803603604081101561078c57600080fd5b508035600290810b9160200135900b6126e0565b6040805160069490940b84526001600160a01b03909216602084015263ffffffff1682820152519081900360600190f35b6101bb6128d7565b6107e16128fb565b6040805160029290920b8252519081900360200190f35b6101bb61291f565b610808612943565b6040805162ffffff9092168252519081900360200190f35b61045e612967565b6108486004803603602081101561083e57600080fd5b503560020b61296d565b604080516001600160801b039099168952600f9790970b602089015287870195909552606087019390935260069190910b60808601526001600160a01b031660a085015263ffffffff1660c0840152151560e083015251908190036101000190f35b610359600480360360208110156108c057600080fd5b50356001600160a01b03166129db565b7f000000000000000000000000000000000000000000000000000000000000000081565b6000806108ff612bf0565b85610936576040805162461bcd60e51b8152602060048201526002602482015261415360f01b604482015290519081900360640190fd5b6040805160e0810182526000546001600160a01b0381168252600160a01b8104600290810b810b900b602083015261ffff600160b81b8204811693830193909352600160c81b810483166060830152600160d81b8104909216608082015260ff600160e81b8304811660a0830152600160f01b909204909116151560c082018190526109ef576040805162461bcd60e51b81526020600482015260036024820152624c4f4b60e81b604482015290519081900360640190fd5b87610a3a5780600001516001600160a01b0316866001600160a01b0316118015610a35575073fffd8963efd1fc6a506488495d951d5263988d266001600160a01b038716105b610a6c565b80600001516001600160a01b0316866001600160a01b0316108015610a6c57506401000276a36001600160a01b038716115b610aa3576040805162461bcd60e51b815260206004820152600360248201526214d41360ea1b604482015290519081900360640190fd5b6000805460ff60f01b191681556040805160c08101909152808a610ad25760048460a0015160ff16901c610ae5565b60108460a0015160ff1681610ae357fe5b065b60ff1681526004546001600160801b03166020820152604001610b06612c27565b63ffffffff168152602001600060060b815260200160006001600160a01b031681526020016000151581525090506000808913905060006040518060e001604052808b81526020016000815260200185600001516001600160a01b03168152602001856020015160020b81526020018c610b8257600254610b86565b6001545b815260200160006001600160801b0316815260200184602001516001600160801b031681525090505b805115801590610bd55750886001600160a01b031681604001516001600160a01b031614155b15610f9f57610be261560e565b60408201516001600160a01b031681526060820151610c25906006907f00000000000000000000000000000000000000000000000000000000000000008f612c2b565b15156040830152600290810b810b60208301819052620d89e719910b1215610c5657620d89e7196020820152610c75565b6020810151620d89e860029190910b1315610c7557620d89e860208201525b610c828160200151612d6d565b6001600160a01b031660608201526040820151610d13908d610cbc578b6001600160a01b031683606001516001600160a01b031611610cd6565b8b6001600160a01b031683606001516001600160a01b0316105b610ce4578260600151610ce6565b8b5b60c085015185517f000000000000000000000000000000000000000000000000000000000000000061309f565b60c085015260a084015260808301526001600160a01b031660408301528215610d7557610d498160c00151826080015101613291565b825103825260a0810151610d6b90610d6090613291565b6020840151906132a7565b6020830152610db0565b610d828160a00151613291565b825101825260c08101516080820151610daa91610d9f9101613291565b6020840151906132c3565b60208301525b835160ff1615610df6576000846000015160ff168260c0015181610dd057fe5b60c0840180519290910491829003905260a0840180519091016001600160801b03169052505b60c08201516001600160801b031615610e3557610e298160c00151600160801b8460c001516001600160801b03166132d9565b60808301805190910190525b80606001516001600160a01b031682604001516001600160a01b03161415610f5e57806040015115610f35578360a00151610ebf57610e9d846040015160008760200151886040015188602001518a606001516008613389909695949392919063ffffffff16565b6001600160a01b03166080860152600690810b900b6060850152600160a08501525b6000610f0b82602001518e610ed657600154610edc565b84608001515b8f610eeb578560800151610eef565b6002545b608089015160608a015160408b0151600595949392919061351c565b90508c15610f17576000035b610f258360c00151826135ef565b6001600160801b031660c0840152505b8b610f44578060200151610f4d565b60018160200151035b600290810b900b6060830152610f99565b80600001516001600160a01b031682604001516001600160a01b031614610f9957610f8c82604001516136a5565b600290810b900b60608301525b50610baf565b836020015160020b816060015160020b1461107a57600080610fed86604001518660400151886020015188602001518a606001518b6080015160086139d1909695949392919063ffffffff16565b604085015160608601516000805461ffff60c81b1916600160c81b61ffff958616021761ffff60b81b1916600160b81b95909416949094029290921762ffffff60a01b1916600160a01b62ffffff60029490940b93909316929092029190911773ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03909116179055506110ac9050565b60408101516000805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b039092169190911790555b8060c001516001600160801b031683602001516001600160801b0316146110f25760c0810151600480546001600160801b0319166001600160801b039092169190911790555b8a1561114257608081015160015560a08101516001600160801b03161561113d5760a0810151600380546001600160801b031981166001600160801b03918216909301169190911790555b611188565b608081015160025560a08101516001600160801b0316156111885760a0810151600380546001600160801b03808216600160801b92839004821690940116029190911790555b8115158b1515146111a157602081015181518b036111ae565b80600001518a0381602001515b90965094508a156112e75760008512156111f0576111f07f00000000000000000000000000000000000000000000000000000000000000008d87600003613b86565b60006111fa613cd4565b9050336001600160a01b031663fa461e3388888c8c6040518563ffffffff1660e01b815260040180858152602001848152602001806020018281038252848482818152602001925080828437600081840152601f19601f82011690508083019250505095505050505050600060405180830381600087803b15801561127e57600080fd5b505af1158015611292573d6000803e3d6000fd5b5050505061129e613cd4565b6112a88289613e0d565b11156112e1576040805162461bcd60e51b815260206004820152600360248201526249494160e81b604482015290519081900360640190fd5b50611411565b600086121561131e5761131e7f00000000000000000000000000000000000000000000000000000000000000008d88600003613b86565b6000611328613e1d565b9050336001600160a01b031663fa461e3388888c8c6040518563ffffffff1660e01b815260040180858152602001848152602001806020018281038252848482818152602001925080828437600081840152601f19601f82011690508083019250505095505050505050600060405180830381600087803b1580156113ac57600080fd5b505af11580156113c0573d6000803e3d6000fd5b505050506113cc613e1d565b6113d68288613e0d565b111561140f576040805162461bcd60e51b815260206004820152600360248201526249494160e81b604482015290519081900360640190fd5b505b60408082015160c083015160608085015184518b8152602081018b90526001600160a01b03948516818701526001600160801b039093169183019190915260020b60808201529151908e169133917fc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca679181900360a00190a350506000805460ff60f01b1916600160f01b17905550919890975095505050505050565b6004546001600160801b031681565b6003546001600160801b0380821691600160801b90041682565b60088161ffff81106114e757600080fd5b015463ffffffff81169150640100000000810460060b90600160581b81046001600160a01b031690600160f81b900460ff1684565b600054600160f01b900460ff16611560576040805162461bcd60e51b81526020600482015260036024820152624c4f4b60e81b604482015290519081900360640190fd5b6000805460ff60f01b19169055611575612bf0565b60008054600160d81b900461ffff169061159160088385613eb5565b6000805461ffff808416600160d81b810261ffff60d81b19909316929092179092559192508316146115fe576040805161ffff80851682528316602082015281517fac49e518f90a358f652e4400164f05a5d8f7e35e7747279bc3a93dbf584e125a929181900390910190a15b50506000805460ff60f01b1916600160f01b17905550565b6000546001600160a01b03811690600160a01b810460020b9061ffff600160b81b8204811691600160c81b8104821691600160d81b8204169060ff600160e81b8204811691600160f01b90041687565b600080548190600160f01b900460ff166116ad576040805162461bcd60e51b81526020600482015260036024820152624c4f4b60e81b604482015290519081900360640190fd5b6000805460ff60f01b191690556001600160801b0385166116cd57600080fd5b60008061171b60405180608001604052808c6001600160a01b031681526020018b60020b81526020018a60020b81526020016117118a6001600160801b0316613f58565b600f0b9052613f69565b9250925050819350809250600080600086111561173d5761173a613cd4565b91505b841561174e5761174b613e1d565b90505b336001600160a01b031663d348799787878b8b6040518563ffffffff1660e01b815260040180858152602001848152602001806020018281038252848482818152602001925080828437600081840152601f19601f82011690508083019250505095505050505050600060405180830381600087803b1580156117d057600080fd5b505af11580156117e4573d6000803e3d6000fd5b50505050600086111561183b576117f9613cd4565b6118038388613e0d565b111561183b576040805162461bcd60e51b815260206004820152600260248201526104d360f41b604482015290519081900360640190fd5b841561188b57611849613e1d565b6118538287613e0d565b111561188b576040805162461bcd60e51b81526020600482015260026024820152614d3160f01b604482015290519081900360640190fd5b8960020b8b60020b8d6001600160a01b03167f7a53080ba414158be7ec69b987b5fb7d07dee101fe85488f0853ae16239d0bde338d8b8b60405180856001600160a01b03168152602001846001600160801b0316815260200183815260200182815260200194505050505060405180910390a450506000805460ff60f01b1916600160f01b17905550919890975095505050505050565b60025481565b600054600160f01b900460ff1661196c576040805162461bcd60e51b81526020600482015260036024820152624c4f4b60e81b604482015290519081900360640190fd5b6000805460ff60f01b19169055611981612bf0565b6004546001600160801b0316806119c3576040805162461bcd60e51b81526020600482015260016024820152601360fa1b604482015290519081900360640190fd5b60006119f8867f000000000000000000000000000000000000000000000000000000000000000062ffffff16620f42406141a9565b90506000611a2f867f000000000000000000000000000000000000000000000000000000000000000062ffffff16620f42406141a9565b90506000611a3b613cd4565b90506000611a47613e1d565b90508815611a7a57611a7a7f00000000000000000000000000000000000000000000000000000000000000008b8b613b86565b8715611aab57611aab7f00000000000000000000000000000000000000000000000000000000000000008b8a613b86565b336001600160a01b031663e9cbafb085858a8a6040518563ffffffff1660e01b815260040180858152602001848152602001806020018281038252848482818152602001925080828437600081840152601f19601f82011690508083019250505095505050505050600060405180830381600087803b158015611b2d57600080fd5b505af1158015611b41573d6000803e3d6000fd5b505050506000611b4f613cd4565b90506000611b5b613e1d565b905081611b688588613e0d565b1115611ba0576040805162461bcd60e51b8152602060048201526002602482015261046360f41b604482015290519081900360640190fd5b80611bab8487613e0d565b1115611be3576040805162461bcd60e51b8152602060048201526002602482015261463160f01b604482015290519081900360640190fd5b8382038382038115611c725760008054600160e81b9004600f16908115611c16578160ff168481611c1057fe5b04611c19565b60005b90506001600160801b03811615611c4c57600380546001600160801b038082168401166001600160801b03199091161790555b611c66818503600160801b8d6001600160801b03166132d9565b60018054909101905550505b8015611cfd5760008054600160e81b900460041c600f16908115611ca2578160ff168381611c9c57fe5b04611ca5565b60005b90506001600160801b03811615611cd757600380546001600160801b03600160801b8083048216850182160291161790555b611cf1818403600160801b8d6001600160801b03166132d9565b60028054909101905550505b8d6001600160a01b0316336001600160a01b03167fbdbdb71d7860376ba52b25a5028beea23581364a40522f6bcfb86bb1f2dca6338f8f86866040518085815260200184815260200183815260200182815260200194505050505060405180910390a350506000805460ff60f01b1916600160f01b179055505050505050505050505050565b600080548190600160f01b900460ff16611dca576040805162461bcd60e51b81526020600482015260036024820152624c4f4b60e81b604482015290519081900360640190fd5b6000805460ff60f01b19168155611de460073389896141e3565b60038101549091506001600160801b0390811690861611611e055784611e14565b60038101546001600160801b03165b60038201549093506001600160801b03600160801b909104811690851611611e3c5783611e52565b6003810154600160801b90046001600160801b03165b91506001600160801b03831615611eb7576003810180546001600160801b031981166001600160801b03918216869003821617909155611eb7907f0000000000000000000000000000000000000000000000000000000000000000908a908616613b86565b6001600160801b03821615611f1d576003810180546001600160801b03600160801b808304821686900382160291811691909117909155611f1d907f0000000000000000000000000000000000000000000000000000000000000000908a908516613b86565b604080516001600160a01b038a1681526001600160801b0380861660208301528416818301529051600288810b92908a900b9133917f70935338e69775456a85ddef226c395fb668b63fa0115f5f20610b388e6ca9c0919081900360600190a4506000805460ff60f01b1916600160f01b17905590969095509350505050565b60076020526000908152604090208054600182015460028301546003909301546001600160801b0392831693919281811691600160801b90041685565b60066020526000908152604090205481565b7f000000000000000000000000000000000000000000000000000000000000000081565b600054600160f01b900460ff16612054576040805162461bcd60e51b81526020600482015260036024820152624c4f4b60e81b604482015290519081900360640190fd5b6000805460ff60f01b1916905560408051638da5cb5b60e01b815290516001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691638da5cb5b916004808301926020929190829003018186803b1580156120c157600080fd5b505afa1580156120d5573d6000803e3d6000fd5b505050506040513d60208110156120eb57600080fd5b50516001600160a01b0316331461210157600080fd5b60ff82161580612124575060048260ff16101580156121245750600a8260ff1611155b801561214e575060ff8116158061214e575060048160ff161015801561214e5750600a8160ff1611155b61215757600080fd5b60008054610ff0600484901b16840160ff908116600160e81b9081027fffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff841617909355919004167f973d8d92bb299f4af6ce49b52a8adb85ae46b9f214c4c4fc06ac77401237b1336010826040805160ff9390920683168252600f600486901c16602083015286831682820152918516606082015290519081900360800190a150506000805460ff60f01b1916600160f01b17905550565b600080548190600160f01b900460ff16612256576040805162461bcd60e51b81526020600482015260036024820152624c4f4b60e81b604482015290519081900360640190fd5b6000805460ff60f01b1916905560408051638da5cb5b60e01b815290516001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691638da5cb5b916004808301926020929190829003018186803b1580156122c357600080fd5b505afa1580156122d7573d6000803e3d6000fd5b505050506040513d60208110156122ed57600080fd5b50516001600160a01b0316331461230357600080fd5b6003546001600160801b039081169085161161231f578361232c565b6003546001600160801b03165b6003549092506001600160801b03600160801b9091048116908416116123525782612366565b600354600160801b90046001600160801b03165b90506001600160801b038216156123e7576003546001600160801b038381169116141561239557600019909101905b600380546001600160801b031981166001600160801b039182168590038216179091556123e7907f00000000000000000000000000000000000000000000000000000000000000009087908516613b86565b6001600160801b0381161561246d576003546001600160801b03828116600160801b90920416141561241857600019015b600380546001600160801b03600160801b80830482168590038216029181169190911790915561246d907f00000000000000000000000000000000000000000000000000000000000000009087908416613b86565b604080516001600160801b0380851682528316602082015281516001600160a01b0388169233927f596b573906218d3411850b26a6b437d6c4522fdb43d2d2386263f86d50b8b151929081900390910190a36000805460ff60f01b1916600160f01b1790559094909350915050565b6060806124e7612bf0565b61255e6124f2612c27565b858580806020026020016040519081016040528093929190818152602001838360200280828437600092018290525054600454600896959450600160a01b820460020b935061ffff600160b81b8304811693506001600160801b0390911691600160c81b900416614247565b915091509250929050565b600080548190600160f01b900460ff166125b0576040805162461bcd60e51b81526020600482015260036024820152624c4f4b60e81b604482015290519081900360640190fd5b6000805460ff60f01b1916815560408051608081018252338152600288810b602083015287900b918101919091528190819061260990606081016125fc6001600160801b038a16613f58565b600003600f0b9052613f69565b925092509250816000039450806000039350600085118061262a5750600084115b15612669576003830180546001600160801b038082168089018216600160801b93849004831689019092169092029091176001600160801b0319161790555b604080516001600160801b0388168152602081018790528082018690529051600289810b92908b900b9133917f0c396cd989a39f4459b5fa1aed6a9a8dcdbc45908acfd67e028cd568da98982c919081900360600190a450506000805460ff60f01b1916600160f01b179055509094909350915050565b60008060006126ed612bf0565b6126f785856143a1565b600285810b810b60009081526005602052604080822087840b90930b825281206003830154600681900b9367010000000000000082046001600160a01b0316928492600160d81b810463ffffffff169284929091600160f81b900460ff168061275f57600080fd5b6003820154600681900b985067010000000000000081046001600160a01b03169650600160d81b810463ffffffff169450600160f81b900460ff16806127a457600080fd5b50506040805160e0810182526000546001600160a01b0381168252600160a01b8104600290810b810b810b6020840181905261ffff600160b81b8404811695850195909552600160c81b830485166060850152600160d81b8304909416608084015260ff600160e81b8304811660a0850152600160f01b909204909116151560c08301529093508e810b91900b1215905061284d575093909403965090039350900390506128d0565b8a60020b816020015160020b12156128c1576000612869612c27565b602083015160408401516004546060860151939450600093849361289f936008938893879392916001600160801b031690613389565b9a9003989098039b5050949096039290920396509091030392506128d0915050565b50949093039650039350900390505b9250925092565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000081565b60015481565b60056020526000908152604090208054600182015460028301546003909301546001600160801b03831693600160801b909304600f0b9290600681900b9067010000000000000081046001600160a01b031690600160d81b810463ffffffff1690600160f81b900460ff1688565b6000546001600160a01b031615612a1e576040805162461bcd60e51b8152602060048201526002602482015261414960f01b604482015290519081900360640190fd5b6000612a29826136a5565b9050600080612a41612a39612c27565b60089061446a565b6040805160e0810182526001600160a01b038816808252600288810b6020808501829052600085870181905261ffff898116606088018190529089166080880181905260a08801839052600160c0909801979097528154600160f01b73ffffffffffffffffffffffffffffffffffffffff19909116871762ffffff60a01b1916600160a01b62ffffff9787900b9790971696909602959095177fffffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffff16600160c81b9091021761ffff60d81b1916600160d81b909602959095177fff0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1692909217909355835191825281019190915281519395509193507f98636036cb66a9c19a37435efc1e90142190214e8abeb821bdba3f2990dd4c9592918290030190a150505050565b60008082600281900b620d89e71981612b9957fe5b05029050600083600281900b620d89e881612bb057fe5b0502905060008460020b83830360020b81612bc757fe5b0560010190508062ffffff166001600160801b03801681612be457fe5b0493505050505b919050565b306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614612c2557600080fd5b565b4290565b60008060008460020b8660020b81612c3f57fe5b05905060008660020b128015612c6657508460020b8660020b81612c5f57fe5b0760020b15155b15612c7057600019015b8315612ce557600080612c82836144b6565b600182810b810b600090815260208d9052604090205460ff83169190911b80016000190190811680151597509294509092509085612cc757888360ff16860302612cda565b88612cd1826144c8565b840360ff168603025b965050505050612d63565b600080612cf4836001016144b6565b91509150600060018260ff166001901b031990506000818b60008660010b60010b8152602001908152602001600020541690508060001415955085612d4657888360ff0360ff16866001010102612d5c565b8883612d5183614568565b0360ff168660010101025b9650505050505b5094509492505050565b60008060008360020b12612d84578260020b612d8c565b8260020b6000035b9050620d89e8811115612dca576040805162461bcd60e51b81526020600482015260016024820152601560fa1b604482015290519081900360640190fd5b600060018216612dde57600160801b612df0565b6ffffcb933bd6fad37aa2d162d1a5940015b70ffffffffffffffffffffffffffffffffff1690506002821615612e24576ffff97272373d413259a46990580e213a0260801c5b6004821615612e43576ffff2e50f5f656932ef12357cf3c7fdcc0260801c5b6008821615612e62576fffe5caca7e10e4e61c3624eaa0941cd00260801c5b6010821615612e81576fffcb9843d60f6159c9db58835c9266440260801c5b6020821615612ea0576fff973b41fa98c081472e6896dfb254c00260801c5b6040821615612ebf576fff2ea16466c96a3843ec78b326b528610260801c5b6080821615612ede576ffe5dee046a99a2a811c461f1969c30530260801c5b610100821615612efe576ffcbe86c7900a88aedcffc83b479aa3a40260801c5b610200821615612f1e576ff987a7253ac413176f2b074cf7815e540260801c5b610400821615612f3e576ff3392b0822b70005940c7a398e4b70f30260801c5b610800821615612f5e576fe7159475a2c29b7443b29c7fa6e889d90260801c5b611000821615612f7e576fd097f3bdfd2022b8845ad8f792aa58250260801c5b612000821615612f9e576fa9f746462d870fdf8a65dc1f90e061e50260801c5b614000821615612fbe576f70d869a156d2a1b890bb3df62baf32f70260801c5b618000821615612fde576f31be135f97d08fd981231505542fcfa60260801c5b62010000821615612fff576f09aa508b5b7a84e1c677de54f3e99bc90260801c5b6202000082161561301f576e5d6af8dedb81196699c329225ee6040260801c5b6204000082161561303e576d2216e584f5fa1ea926041bedfe980260801c5b6208000082161561305b576b048a170391f7dc42444e8fa20260801c5b60008460020b131561307657806000198161307257fe5b0490505b64010000000081061561308a57600161308d565b60005b60ff16602082901c0192505050919050565b60008080806001600160a01b03808916908a1610158187128015906131245760006130d88989620f42400362ffffff16620f42406132d9565b9050826130f1576130ec8c8c8c6001614652565b6130fe565b6130fe8b8d8c60016146cd565b955085811061310f578a965061311e565b61311b8c8b838661478a565b96505b5061316e565b8161313b576131368b8b8b60006146cd565b613148565b6131488a8c8b6000614652565b935083886000031061315c5789955061316e565b61316b8b8a8a600003856147d6565b95505b6001600160a01b038a81169087161482156131d15780801561318d5750815b6131a35761319e878d8c60016146cd565b6131a5565b855b95508080156131b2575081155b6131c8576131c3878d8c6000614652565b6131ca565b845b945061321b565b8080156131db5750815b6131f1576131ec8c888c6001614652565b6131f3565b855b9550808015613200575081155b613216576132118c888c60006146cd565b613218565b845b94505b8115801561322b57508860000385115b15613237578860000394505b81801561325657508a6001600160a01b0316876001600160a01b031614155b15613265578589039350613282565b61327f868962ffffff168a620f42400362ffffff166141a9565b93505b50505095509550955095915050565b6000600160ff1b82106132a357600080fd5b5090565b808203828113156000831215146132bd57600080fd5b92915050565b818101828112156000831215146132bd57600080fd5b600080806000198587098686029250828110908390030390508061330f576000841161330457600080fd5b508290049050613382565b80841161331b57600080fd5b6000848688096000868103871696879004966002600389028118808a02820302808a02820302808a02820302808a02820302808a02820302808a02909103029181900381900460010186841190950394909402919094039290920491909117919091029150505b9392505050565b60008063ffffffff8716613430576000898661ffff1661ffff81106133aa57fe5b60408051608081018252919092015463ffffffff8082168084526401000000008304600690810b810b900b6020850152600160581b83046001600160a01b031694840194909452600160f81b90910460ff16151560608301529092508a161461341c57613419818a8988614822565b90505b806020015181604001519250925050613510565b8688036000806134458c8c858c8c8c8c6148d2565b91509150816000015163ffffffff168363ffffffff161415613477578160200151826040015194509450505050613510565b805163ffffffff8481169116141561349f578060200151816040015194509450505050613510565b8151815160208085015190840151918390039286039163ffffffff80841692908516910360060b816134cd57fe5b05028460200151018263ffffffff168263ffffffff1686604001518660400151036001600160a01b031602816134ff57fe5b048560400151019650965050505050505b97509795505050505050565b600295860b860b60009081526020979097526040909620600181018054909503909455938301805490920390915560038201805463ffffffff600160d81b6001600160a01b036701000000000000008085048216909603169094027fffffffffff0000000000000000000000000000000000000000ffffffffffffff90921691909117600681810b90960390950b66ffffffffffffff1666ffffffffffffff199095169490941782810485169095039093160263ffffffff60d81b1990931692909217905554600160801b9004600f0b90565b60008082600f0b121561365457826001600160801b03168260000384039150816001600160801b03161061364f576040805162461bcd60e51b81526020600482015260026024820152614c5360f01b604482015290519081900360640190fd5b6132bd565b826001600160801b03168284019150816001600160801b031610156132bd576040805162461bcd60e51b81526020600482015260026024820152614c4160f01b604482015290519081900360640190fd5b60006401000276a36001600160a01b038316108015906136e1575073fffd8963efd1fc6a506488495d951d5263988d266001600160a01b038316105b613716576040805162461bcd60e51b81526020600482015260016024820152602960f91b604482015290519081900360640190fd5b77ffffffffffffffffffffffffffffffffffffffff00000000602083901b166001600160801b03811160071b81811c67ffffffffffffffff811160061b90811c63ffffffff811160051b90811c61ffff811160041b90811c60ff8111600390811b91821c600f811160021b90811c918211600190811b92831c979088119617909417909217179091171717608081106137b757607f810383901c91506137c1565b80607f0383901b91505b908002607f81811c60ff83811c9190911c800280831c81831c1c800280841c81841c1c800280851c81851c1c800280861c81861c1c800280871c81871c1c800280881c81881c1c800280891c81891c1c8002808a1c818a1c1c8002808b1c818b1c1c8002808c1c818c1c1c8002808d1c818d1c1c8002808e1c9c81901c9c909c1c80029c8d901c9e9d607f198f0160401b60c09190911c678000000000000000161760c19b909b1c674000000000000000169a909a1760c29990991c672000000000000000169890981760c39790971c671000000000000000169690961760c49590951c670800000000000000169490941760c59390931c670400000000000000169290921760c69190911c670200000000000000161760c79190911c670100000000000000161760c89190911c6680000000000000161760c99190911c6640000000000000161760ca9190911c6620000000000000161760cb9190911c6610000000000000161760cc9190911c6608000000000000161760cd9190911c66040000000000001617693627a301d71055774c8581026f028f6481ab7f045a5af012a19d003aa9198101608090811d906fdb2df09e81959a81455e260799a0632f8301901d600281810b9083900b146139c257886001600160a01b03166139a682612d6d565b6001600160a01b031611156139bb57816139bd565b805b6139c4565b815b9998505050505050505050565b6000806000898961ffff1661ffff81106139e757fe5b60408051608081018252919092015463ffffffff8082168084526401000000008304600690810b810b900b6020850152600160581b83046001600160a01b031694840194909452600160f81b90910460ff161515606083015290925089161415613a575788859250925050613510565b8461ffff168461ffff16118015613a7857506001850361ffff168961ffff16145b15613a8557839150613a89565b8491505b8161ffff168960010161ffff1681613a9d57fe5b069250613aac81898989614822565b8a8461ffff1661ffff8110613abd57fe5b825191018054602084015160408501516060909501511515600160f81b027effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6001600160a01b03909616600160581b027fff0000000000000000000000000000000000000000ffffffffffffffffffffff60069390930b66ffffffffffffff16640100000000026affffffffffffff000000001963ffffffff90971663ffffffff199095169490941795909516929092171692909217929092161790555097509795505050505050565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b1781529251825160009485949389169392918291908083835b60208310613c025780518252601f199092019160209182019101613be3565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114613c64576040519150601f19603f3d011682016040523d82523d6000602084013e613c69565b606091505b5091509150818015613c97575080511580613c975750808060200190516020811015613c9457600080fd5b50515b613ccd576040805162461bcd60e51b81526020600482015260026024820152612a2360f11b604482015290519081900360640190fd5b5050505050565b604080513060248083019190915282518083039091018152604490910182526020810180516001600160e01b03166370a0823160e01b17815291518151600093849384936001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001693919290918291908083835b60208310613d6d5780518252601f199092019160209182019101613d4e565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d8060008114613dcd576040519150601f19603f3d011682016040523d82523d6000602084013e613dd2565b606091505b5091509150818015613de657506020815110155b613def57600080fd5b808060200190516020811015613e0457600080fd5b50519250505090565b808201828110156132bd57600080fd5b604080513060248083019190915282518083039091018152604490910182526020810180516001600160e01b03166370a0823160e01b17815291518151600093849384936001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016939192909182919080838360208310613d6d5780518252601f199092019160209182019101613d4e565b6000808361ffff1611613ef3576040805162461bcd60e51b81526020600482015260016024820152604960f81b604482015290519081900360640190fd5b8261ffff168261ffff1611613f09575081613382565b825b8261ffff168161ffff161015613f4f576001858261ffff1661ffff8110613f2e57fe5b01805463ffffffff191663ffffffff92909216919091179055600101613f0b565b50909392505050565b80600f81900b8114612beb57600080fd5b6000806000613f76612bf0565b613f88846020015185604001516143a1565b6040805160e0810182526000546001600160a01b0381168252600160a01b8104600290810b810b900b602080840182905261ffff600160b81b8404811685870152600160c81b84048116606080870191909152600160d81b8504909116608086015260ff600160e81b8504811660a0870152600160f01b909404909316151560c08501528851908901519489015192890151939461402c9491939092909190614acf565b93508460600151600f0b6000146141a157846020015160020b816020015160020b12156140815761407a6140638660200151612d6d565b6140708760400151612d6d565b8760600151614c84565b92506141a1565b846040015160020b816020015160020b12156141775760045460408201516001600160801b03909116906140d3906140b7612c27565b60208501516060860151608087015160089493929187916139d1565b6000805461ffff60c81b1916600160c81b61ffff938416021761ffff60b81b1916600160b81b939092169290920217905581516040870151614123919061411990612d6d565b8860600151614c84565b93506141416141358760200151612d6d565b83516060890151614cc8565b92506141518187606001516135ef565b600480546001600160801b0319166001600160801b0392909216919091179055506141a1565b61419e6141878660200151612d6d565b6141948760400151612d6d565b8760600151614cc8565b91505b509193909250565b60006141b68484846132d9565b9050600082806141c257fe5b84860911156133825760001981106141d957600080fd5b6001019392505050565b6040805160609490941b6bffffffffffffffffffffffff1916602080860191909152600293840b60e890811b60348701529290930b90911b60378401528051808403601a018152603a90930181528251928201929092206000908152929052902090565b60608060008361ffff1611614287576040805162461bcd60e51b81526020600482015260016024820152604960f81b604482015290519081900360640190fd5b865167ffffffffffffffff8111801561429f57600080fd5b506040519080825280602002602001820160405280156142c9578160200160208202803683370190505b509150865167ffffffffffffffff811180156142e457600080fd5b5060405190808252806020026020018201604052801561430e578160200160208202803683370190505b50905060005b87518110156143945761433f8a8a8a848151811061432e57fe5b60200260200101518a8a8a8a613389565b84838151811061434b57fe5b6020026020010184848151811061435e57fe5b60200260200101826001600160a01b03166001600160a01b03168152508260060b60060b81525050508080600101915050614314565b5097509795505050505050565b8060020b8260020b126143e1576040805162461bcd60e51b8152602060048201526003602482015262544c5560e81b604482015290519081900360640190fd5b620d89e719600283900b1215614424576040805162461bcd60e51b8152602060048201526003602482015262544c4d60e81b604482015290519081900360640190fd5b620d89e8600282900b1315614466576040805162461bcd60e51b815260206004820152600360248201526254554d60e81b604482015290519081900360640190fd5b5050565b6040805160808101825263ffffffff9283168082526000602083018190529282019290925260016060909101819052835463ffffffff1916909117909116600160f81b17909155908190565b60020b600881901d9161010090910790565b60008082116144d657600080fd5b600160801b82106144e957608091821c91015b68010000000000000000821061450157604091821c91015b640100000000821061451557602091821c91015b62010000821061452757601091821c91015b610100821061453857600891821c91015b6010821061454857600491821c91015b6004821061455857600291821c91015b60028210612beb57600101919050565b600080821161457657600080fd5b5060ff6001600160801b0382161561459157607f1901614599565b608082901c91505b67ffffffffffffffff8216156145b257603f19016145ba565b604082901c91505b63ffffffff8216156145cf57601f19016145d7565b602082901c91505b61ffff8216156145ea57600f19016145f2565b601082901c91505b60ff821615614604576007190161460c565b600882901c91505b600f82161561461e5760031901614626565b600482901c91505b60038216156146385760011901614640565b600282901c91505b6001821615612beb5760001901919050565b6000836001600160a01b0316856001600160a01b03161115614672579293925b8161469f5761469a836001600160801b03168686036001600160a01b0316600160601b6132d9565b6146c2565b6146c2836001600160801b03168686036001600160a01b0316600160601b6141a9565b90505b949350505050565b6000836001600160a01b0316856001600160a01b031611156146ed579293925b7bffffffffffffffffffffffffffffffff000000000000000000000000606084901b166001600160a01b03868603811690871661472957600080fd5b8361475957866001600160a01b031661474c8383896001600160a01b03166132d9565b8161475357fe5b0461477f565b61477f6147708383896001600160a01b03166141a9565b886001600160a01b0316614cf7565b979650505050505050565b600080856001600160a01b0316116147a157600080fd5b6000846001600160801b0316116147b757600080fd5b816147c95761469a8585856001614d02565b6146c28585856001614de3565b600080856001600160a01b0316116147ed57600080fd5b6000846001600160801b03161161480357600080fd5b816148155761469a8585856000614de3565b6146c28585856000614d02565b61482a61564a565b600085600001518503905060405180608001604052808663ffffffff1681526020018263ffffffff168660020b0288602001510160060b81526020016000856001600160801b03161161487e576001614880565b845b6001600160801b031673ffffffff00000000000000000000000000000000608085901b16816148ab57fe5b048860400151016001600160a01b0316815260200160011515815250915050949350505050565b6148da61564a565b6148e261564a565b888561ffff1661ffff81106148f357fe5b60408051608081018252919092015463ffffffff81168083526401000000008204600690810b810b900b6020840152600160581b82046001600160a01b031693830193909352600160f81b900460ff1615156060820152925061495890899089614ed8565b15614990578663ffffffff16826000015163ffffffff16141561497a57613510565b8161498783898988614822565b91509150613510565b888361ffff168660010161ffff16816149a557fe5b0661ffff1661ffff81106149b557fe5b60408051608081018252929091015463ffffffff811683526401000000008104600690810b810b900b60208401526001600160a01b03600160581b8204169183019190915260ff600160f81b90910416151560608201819052909250614a6c57604080516080810182528a5463ffffffff811682526401000000008104600690810b810b900b6020830152600160581b81046001600160a01b031692820192909252600160f81b90910460ff161515606082015291505b614a7b88836000015189614ed8565b614ab2576040805162461bcd60e51b815260206004820152600360248201526213d31160ea1b604482015290519081900360640190fd5b614abf8989898887614f9b565b9150915097509795505050505050565b6000614ade60078787876141e3565b60015460025491925090600080600f87900b15614c24576000614aff612c27565b6000805460045492935090918291614b499160089186918591600160a01b810460020b9161ffff600160b81b83048116926001600160801b0390921691600160c81b900416613389565b9092509050614b8360058d8b8d8b8b87898b60007f000000000000000000000000000000000000000000000000000000000000000061513b565b9450614bba60058c8b8d8b8b87898b60017f000000000000000000000000000000000000000000000000000000000000000061513b565b93508415614bee57614bee60068d7f0000000000000000000000000000000000000000000000000000000000000000615325565b8315614c2057614c2060068c7f0000000000000000000000000000000000000000000000000000000000000000615325565b5050505b600080614c3660058c8c8b8a8a61538b565b9092509050614c47878a8484615437565b600089600f0b1215614c75578315614c6457614c6460058c6155cc565b8215614c7557614c7560058b6155cc565b50505050505095945050505050565b60008082600f0b12614caa57614ca5614ca085858560016146cd565b613291565b6146c5565b614cbd614ca085858560000360006146cd565b600003949350505050565b60008082600f0b12614ce457614ca5614ca08585856001614652565b614cbd614ca08585856000036000614652565b808204910615150190565b60008115614d755760006001600160a01b03841115614d3857614d3384600160601b876001600160801b03166132d9565b614d50565b6001600160801b038516606085901b81614d4e57fe5b045b9050614d6d614d686001600160a01b03881683613e0d565b6155f8565b9150506146c5565b60006001600160a01b03841115614da357614d9e84600160601b876001600160801b03166141a9565b614dba565b614dba606085901b6001600160801b038716614cf7565b905080866001600160a01b031611614dd157600080fd5b6001600160a01b0386160390506146c5565b600082614df15750836146c5565b7bffffffffffffffffffffffffffffffff000000000000000000000000606085901b168215614e91576001600160a01b03861684810290858281614e3157fe5b041415614e6257818101828110614e6057614e5683896001600160a01b0316836141a9565b93505050506146c5565b505b614e8882614e83878a6001600160a01b03168681614e7c57fe5b0490613e0d565b614cf7565b925050506146c5565b6001600160a01b03861684810290858281614ea857fe5b04148015614eb557508082115b614ebe57600080fd5b808203614e56614d68846001600160a01b038b16846141a9565b60008363ffffffff168363ffffffff1611158015614f0257508363ffffffff168263ffffffff1611155b15614f1e578163ffffffff168363ffffffff1611159050613382565b60008463ffffffff168463ffffffff1611614f46578363ffffffff1664010000000001614f4e565b8363ffffffff165b64ffffffffff16905060008563ffffffff168463ffffffff1611614f7f578363ffffffff1664010000000001614f87565b8363ffffffff165b64ffffffffff169091111595945050505050565b614fa361564a565b614fab61564a565b60008361ffff168560010161ffff1681614fc157fe5b0661ffff169050600060018561ffff16830103905060005b506002818301048961ffff87168281614fee57fe5b0661ffff8110614ffa57fe5b60408051608081018252929091015463ffffffff811683526401000000008104600690810b810b900b60208401526001600160a01b03600160581b8204169183019190915260ff600160f81b9091041615156060820181905290955061506557806001019250614fd9565b898661ffff16826001018161507657fe5b0661ffff811061508257fe5b60408051608081018252929091015463ffffffff811683526401000000008104600690810b810b900b60208401526001600160a01b03600160581b8204169183019190915260ff600160f81b909104161515606082015285519094506000906150ed908b908b614ed8565b905080801561510657506151068a8a8760000151614ed8565b15615111575061512e565b8061512157600182039250615128565b8160010193505b50614fd9565b5050509550959350505050565b60028a810b900b600090815260208c90526040812080546001600160801b031682615166828d6135ef565b9050846001600160801b0316816001600160801b031611156151b4576040805162461bcd60e51b81526020600482015260026024820152614c4f60f01b604482015290519081900360640190fd5b6001600160801b03828116159082161581141594501561528a578c60020b8e60020b1361525a57600183018b9055600283018a90556003830180547fffffffffff0000000000000000000000000000000000000000ffffffffffffff166701000000000000006001600160a01b038c16021766ffffffffffffff191666ffffffffffffff60068b900b161763ffffffff60d81b1916600160d81b63ffffffff8a16021790555b6003830180547effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b1790555b82546001600160801b0319166001600160801b038216178355856152d35782546152ce906152c990600160801b9004600f90810b810b908f900b6132c3565b613f58565b6152f4565b82546152f4906152c990600160801b9004600f90810b810b908f900b6132a7565b8354600f9190910b6001600160801b03908116600160801b0291161790925550909c9b505050505050505050505050565b8060020b8260020b8161533457fe5b0760020b1561534257600080fd5b60008061535d8360020b8560020b8161535757fe5b056144b6565b600191820b820b60009081526020979097526040909620805460ff9097169190911b90951890945550505050565b600285810b80820b60009081526020899052604080822088850b850b83529082209193849391929184918291908a900b126153d1575050600182015460028301546153e4565b8360010154880391508360020154870390505b6000808b60020b8b60020b121561540657505060018301546002840154615419565b84600101548a0391508460020154890390505b92909803979097039b96909503949094039850939650505050505050565b6040805160a08101825285546001600160801b0390811682526001870154602083015260028701549282019290925260038601548083166060830152600160801b900490911660808201526000600f85900b6154d65781516001600160801b03166154ce576040805162461bcd60e51b815260206004820152600260248201526104e560f41b604482015290519081900360640190fd5b5080516154e5565b81516154e290866135ef565b90505b60006155098360200151860384600001516001600160801b0316600160801b6132d9565b9050600061552f8460400151860385600001516001600160801b0316600160801b6132d9565b905086600f0b6000146155565787546001600160801b0319166001600160801b0384161788555b60018801869055600288018590556001600160801b03821615158061558457506000816001600160801b0316115b156155c2576003880180546001600160801b031981166001600160801b039182168501821617808216600160801b9182900483168501909216021790555b5050505050505050565b600290810b810b6000908152602092909252604082208281556001810183905590810182905560030155565b806001600160a01b0381168114612beb57600080fd5b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081019190915290565b6040805160808101825260008082526020820181905291810182905260608101919091529056fea164736f6c6343000706000aa164736f6c6343000706000ac66a3fdf07232cdd185febcc6579d408c241b47ae2f9907d84be655141eeaecc", + "deployedBytecode": "0x608060405234801561001057600080fd5b506004361061007d5760003560e01c8063890357301161005b578063890357301461013b5780638a7c195f146101855780638da5cb5b146101b0578063a1671295146101b85761007d565b806313af4035146100825780631698ee82146100aa57806322afcccb14610102575b600080fd5b6100a86004803603602081101561009857600080fd5b50356001600160a01b03166101f4565b005b6100e6600480360360608110156100c057600080fd5b5080356001600160a01b03908116916020810135909116906040013562ffffff16610267565b604080516001600160a01b039092168252519081900360200190f35b6101246004803603602081101561011857600080fd5b503562ffffff16610293565b6040805160029290920b8252519081900360200190f35b6101436102a8565b604080516001600160a01b0396871681529486166020860152929094168383015262ffffff16606083015260029290920b608082015290519081900360a00190f35b6100a86004803603604081101561019b57600080fd5b5062ffffff813516906020013560020b6102de565b6100e66103a1565b6100e6600480360360608110156101ce57600080fd5b5080356001600160a01b03908116916020810135909116906040013562ffffff166103b0565b6003546001600160a01b0316331461020b57600080fd5b6003546040516001600160a01b038084169216907fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c90600090a3600380546001600160a01b0319166001600160a01b0392909216919091179055565b60056020908152600093845260408085208252928452828420905282529020546001600160a01b031681565b60046020526000908152604090205460020b81565b600054600154600280546001600160a01b03938416939283169281169162ffffff600160a01b83041691600160b81b9004900b85565b6003546001600160a01b031633146102f557600080fd5b620f42408262ffffff161061030957600080fd5b60008160020b13801561032057506140008160020b125b61032957600080fd5b62ffffff8216600090815260046020526040902054600290810b900b1561034f57600080fd5b62ffffff828116600081815260046020526040808220805462ffffff1916600287900b958616179055517fc66a3fdf07232cdd185febcc6579d408c241b47ae2f9907d84be655141eeaecc9190a35050565b6003546001600160a01b031681565b60006103ba610546565b826001600160a01b0316846001600160a01b031614156103d957600080fd5b600080846001600160a01b0316866001600160a01b0316106103fc5784866103ff565b85855b90925090506001600160a01b03821661041757600080fd5b62ffffff8416600090815260046020526040902054600290810b9081900b61043e57600080fd5b6001600160a01b0383811660009081526005602090815260408083208685168452825280832062ffffff8a168452909152902054161561047d57600080fd5b61048a308484888561057d565b6001600160a01b03808516600081815260056020818152604080842089871680865290835281852062ffffff8e168087529084528286208054988a166001600160a01b0319998a1681179091558287529484528286208787528452828620818752845294829020805490971684179096558051600289900b815291820192909252815195995091947f783cca1c0412dd0d695e784568c96da2e9c22ff989357a2e8b1d9b2b4e6b71189281900390910190a45050509392505050565b306001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461057b57600080fd5b565b6040805160a0810182526001600160a01b03878116808352878216602080850182905292881684860181905262ffffff888116606080880182905260028a810b6080998a01819052600080546001600160a01b03199081169099178155600180548a1689179055825490981686177fffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffff16600160a01b8502177fffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffff16600160b81b91830b9095160293909317909255875180870194909452838801929092528281019190915285518083039091018152930193849052825192909101919091209091610686906106f5565b8190604051809103906000f59050801580156106a6573d6000803e3d6000fd5b50600080546001600160a01b0319908116909155600180549091169055600280547fffffffffffff00000000000000000000000000000000000000000000000000001690559695505050505050565b6158c8806107038339019056fe6101606040523480156200001257600080fd5b503060601b60805260408051630890357360e41b81529051600091339163890357309160048082019260a092909190829003018186803b1580156200005657600080fd5b505afa1580156200006b573d6000803e3d6000fd5b505050506040513d60a08110156200008257600080fd5b508051602080830151604084015160608086015160809096015160e896871b6001600160e81b0319166101005291811b6001600160601b031990811660e05292811b831660c0529390931b1660a052600282810b900b90921b610120529150620000f79082906200010f811b62002b8417901c565b60801b6001600160801b03191661014052506200017d565b60008082600281900b620d89e719816200012557fe5b05029050600083600281900b620d89e8816200013d57fe5b0502905060008460020b83830360020b816200015557fe5b0560010190508062ffffff166001600160801b038016816200017357fe5b0495945050505050565b60805160601c60a05160601c60c05160601c60e05160601c6101005160e81c6101205160e81c6101405160801c61567e6200024a60003980611fee5280614b5f5280614b96525080610c0052806128fd5280614bca5280614bfc525080610cef52806119cb5280611a0252806129455250806111c75280611a855280611ef4528061244452806129215280613e6b5250806108d252806112f55280611a545280611e8e52806123be5280613d2252508061207b528061227d52806128d9525080612bfb525061567e6000f3fe608060405234801561001057600080fd5b50600436106101ae5760003560e01c806370cf754a116100ee578063c45a015511610097578063ddca3f4311610071578063ddca3f4314610800578063f305839914610820578063f30dba9314610828578063f637731d146108aa576101ae565b8063c45a0155146107d1578063d0c93a7c146107d9578063d21220a7146107f8576101ae565b8063883bdbfd116100c8578063883bdbfd14610633578063a34123a71461073c578063a38807f214610776576101ae565b806370cf754a146105c65780638206a4d1146105ce57806385b66729146105f6576101ae565b80633850c7bd1161015b578063490e6cbc11610135578063490e6cbc146104705780634f1eb3d8146104fc578063514ea4bf1461054d5780635339c296146105a6576101ae565b80633850c7bd1461035b5780633c8a7d8d146103b45780634614131914610456576101ae565b80631ad8b03b1161018c5780631ad8b03b146102aa578063252c09d7146102e157806332148f6714610338576101ae565b80630dfe1681146101b3578063128acb08146101d75780631a68650214610286575b600080fd5b6101bb6108d0565b604080516001600160a01b039092168252519081900360200190f35b61026d600480360360a08110156101ed57600080fd5b6001600160a01b0382358116926020810135151592604082013592606083013516919081019060a08101608082013564010000000081111561022e57600080fd5b82018360208201111561024057600080fd5b8035906020019184600183028401116401000000008311171561026257600080fd5b5090925090506108f4565b6040805192835260208301919091528051918290030190f35b61028e6114ad565b604080516001600160801b039092168252519081900360200190f35b6102b26114bc565b60405180836001600160801b03168152602001826001600160801b031681526020019250505060405180910390f35b6102fe600480360360208110156102f757600080fd5b50356114d6565b6040805163ffffffff909516855260069390930b60208501526001600160a01b039091168383015215156060830152519081900360800190f35b6103596004803603602081101561034e57600080fd5b503561ffff1661151c565b005b610363611616565b604080516001600160a01b03909816885260029690960b602088015261ffff9485168787015292841660608701529216608085015260ff90911660a0840152151560c0830152519081900360e00190f35b61026d600480360360a08110156103ca57600080fd5b6001600160a01b03823516916020810135600290810b92604083013590910b916001600160801b036060820135169181019060a08101608082013564010000000081111561041757600080fd5b82018360208201111561042957600080fd5b8035906020019184600183028401116401000000008311171561044b57600080fd5b509092509050611666565b61045e611922565b60408051918252519081900360200190f35b6103596004803603608081101561048657600080fd5b6001600160a01b0382351691602081013591604082013591908101906080810160608201356401000000008111156104bd57600080fd5b8201836020820111156104cf57600080fd5b803590602001918460018302840111640100000000831117156104f157600080fd5b509092509050611928565b6102b2600480360360a081101561051257600080fd5b506001600160a01b03813516906020810135600290810b91604081013590910b906001600160801b0360608201358116916080013516611d83565b61056a6004803603602081101561056357600080fd5b5035611f9d565b604080516001600160801b0396871681526020810195909552848101939093529084166060840152909216608082015290519081900360a00190f35b61045e600480360360208110156105bc57600080fd5b503560010b611fda565b61028e611fec565b610359600480360360408110156105e457600080fd5b5060ff81358116916020013516612010565b6102b26004803603606081101561060c57600080fd5b506001600160a01b03813516906001600160801b036020820135811691604001351661220f565b6106a36004803603602081101561064957600080fd5b81019060208101813564010000000081111561066457600080fd5b82018360208201111561067657600080fd5b8035906020019184602083028401116401000000008311171561069857600080fd5b5090925090506124dc565b604051808060200180602001838103835285818151815260200191508051906020019060200280838360005b838110156106e75781810151838201526020016106cf565b50505050905001838103825284818151815260200191508051906020019060200280838360005b8381101561072657818101518382015260200161070e565b5050505090500194505050505060405180910390f35b61026d6004803603606081101561075257600080fd5b508035600290810b91602081013590910b90604001356001600160801b0316612569565b6107a06004803603604081101561078c57600080fd5b508035600290810b9160200135900b6126e0565b6040805160069490940b84526001600160a01b03909216602084015263ffffffff1682820152519081900360600190f35b6101bb6128d7565b6107e16128fb565b6040805160029290920b8252519081900360200190f35b6101bb61291f565b610808612943565b6040805162ffffff9092168252519081900360200190f35b61045e612967565b6108486004803603602081101561083e57600080fd5b503560020b61296d565b604080516001600160801b039099168952600f9790970b602089015287870195909552606087019390935260069190910b60808601526001600160a01b031660a085015263ffffffff1660c0840152151560e083015251908190036101000190f35b610359600480360360208110156108c057600080fd5b50356001600160a01b03166129db565b7f000000000000000000000000000000000000000000000000000000000000000081565b6000806108ff612bf0565b85610936576040805162461bcd60e51b8152602060048201526002602482015261415360f01b604482015290519081900360640190fd5b6040805160e0810182526000546001600160a01b0381168252600160a01b8104600290810b810b900b602083015261ffff600160b81b8204811693830193909352600160c81b810483166060830152600160d81b8104909216608082015260ff600160e81b8304811660a0830152600160f01b909204909116151560c082018190526109ef576040805162461bcd60e51b81526020600482015260036024820152624c4f4b60e81b604482015290519081900360640190fd5b87610a3a5780600001516001600160a01b0316866001600160a01b0316118015610a35575073fffd8963efd1fc6a506488495d951d5263988d266001600160a01b038716105b610a6c565b80600001516001600160a01b0316866001600160a01b0316108015610a6c57506401000276a36001600160a01b038716115b610aa3576040805162461bcd60e51b815260206004820152600360248201526214d41360ea1b604482015290519081900360640190fd5b6000805460ff60f01b191681556040805160c08101909152808a610ad25760048460a0015160ff16901c610ae5565b60108460a0015160ff1681610ae357fe5b065b60ff1681526004546001600160801b03166020820152604001610b06612c27565b63ffffffff168152602001600060060b815260200160006001600160a01b031681526020016000151581525090506000808913905060006040518060e001604052808b81526020016000815260200185600001516001600160a01b03168152602001856020015160020b81526020018c610b8257600254610b86565b6001545b815260200160006001600160801b0316815260200184602001516001600160801b031681525090505b805115801590610bd55750886001600160a01b031681604001516001600160a01b031614155b15610f9f57610be261560e565b60408201516001600160a01b031681526060820151610c25906006907f00000000000000000000000000000000000000000000000000000000000000008f612c2b565b15156040830152600290810b810b60208301819052620d89e719910b1215610c5657620d89e7196020820152610c75565b6020810151620d89e860029190910b1315610c7557620d89e860208201525b610c828160200151612d6d565b6001600160a01b031660608201526040820151610d13908d610cbc578b6001600160a01b031683606001516001600160a01b031611610cd6565b8b6001600160a01b031683606001516001600160a01b0316105b610ce4578260600151610ce6565b8b5b60c085015185517f000000000000000000000000000000000000000000000000000000000000000061309f565b60c085015260a084015260808301526001600160a01b031660408301528215610d7557610d498160c00151826080015101613291565b825103825260a0810151610d6b90610d6090613291565b6020840151906132a7565b6020830152610db0565b610d828160a00151613291565b825101825260c08101516080820151610daa91610d9f9101613291565b6020840151906132c3565b60208301525b835160ff1615610df6576000846000015160ff168260c0015181610dd057fe5b60c0840180519290910491829003905260a0840180519091016001600160801b03169052505b60c08201516001600160801b031615610e3557610e298160c00151600160801b8460c001516001600160801b03166132d9565b60808301805190910190525b80606001516001600160a01b031682604001516001600160a01b03161415610f5e57806040015115610f35578360a00151610ebf57610e9d846040015160008760200151886040015188602001518a606001516008613389909695949392919063ffffffff16565b6001600160a01b03166080860152600690810b900b6060850152600160a08501525b6000610f0b82602001518e610ed657600154610edc565b84608001515b8f610eeb578560800151610eef565b6002545b608089015160608a015160408b0151600595949392919061351c565b90508c15610f17576000035b610f258360c00151826135ef565b6001600160801b031660c0840152505b8b610f44578060200151610f4d565b60018160200151035b600290810b900b6060830152610f99565b80600001516001600160a01b031682604001516001600160a01b031614610f9957610f8c82604001516136a5565b600290810b900b60608301525b50610baf565b836020015160020b816060015160020b1461107a57600080610fed86604001518660400151886020015188602001518a606001518b6080015160086139d1909695949392919063ffffffff16565b604085015160608601516000805461ffff60c81b1916600160c81b61ffff958616021761ffff60b81b1916600160b81b95909416949094029290921762ffffff60a01b1916600160a01b62ffffff60029490940b93909316929092029190911773ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03909116179055506110ac9050565b60408101516000805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b039092169190911790555b8060c001516001600160801b031683602001516001600160801b0316146110f25760c0810151600480546001600160801b0319166001600160801b039092169190911790555b8a1561114257608081015160015560a08101516001600160801b03161561113d5760a0810151600380546001600160801b031981166001600160801b03918216909301169190911790555b611188565b608081015160025560a08101516001600160801b0316156111885760a0810151600380546001600160801b03808216600160801b92839004821690940116029190911790555b8115158b1515146111a157602081015181518b036111ae565b80600001518a0381602001515b90965094508a156112e75760008512156111f0576111f07f00000000000000000000000000000000000000000000000000000000000000008d87600003613b86565b60006111fa613cd4565b9050336001600160a01b031663fa461e3388888c8c6040518563ffffffff1660e01b815260040180858152602001848152602001806020018281038252848482818152602001925080828437600081840152601f19601f82011690508083019250505095505050505050600060405180830381600087803b15801561127e57600080fd5b505af1158015611292573d6000803e3d6000fd5b5050505061129e613cd4565b6112a88289613e0d565b11156112e1576040805162461bcd60e51b815260206004820152600360248201526249494160e81b604482015290519081900360640190fd5b50611411565b600086121561131e5761131e7f00000000000000000000000000000000000000000000000000000000000000008d88600003613b86565b6000611328613e1d565b9050336001600160a01b031663fa461e3388888c8c6040518563ffffffff1660e01b815260040180858152602001848152602001806020018281038252848482818152602001925080828437600081840152601f19601f82011690508083019250505095505050505050600060405180830381600087803b1580156113ac57600080fd5b505af11580156113c0573d6000803e3d6000fd5b505050506113cc613e1d565b6113d68288613e0d565b111561140f576040805162461bcd60e51b815260206004820152600360248201526249494160e81b604482015290519081900360640190fd5b505b60408082015160c083015160608085015184518b8152602081018b90526001600160a01b03948516818701526001600160801b039093169183019190915260020b60808201529151908e169133917fc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca679181900360a00190a350506000805460ff60f01b1916600160f01b17905550919890975095505050505050565b6004546001600160801b031681565b6003546001600160801b0380821691600160801b90041682565b60088161ffff81106114e757600080fd5b015463ffffffff81169150640100000000810460060b90600160581b81046001600160a01b031690600160f81b900460ff1684565b600054600160f01b900460ff16611560576040805162461bcd60e51b81526020600482015260036024820152624c4f4b60e81b604482015290519081900360640190fd5b6000805460ff60f01b19169055611575612bf0565b60008054600160d81b900461ffff169061159160088385613eb5565b6000805461ffff808416600160d81b810261ffff60d81b19909316929092179092559192508316146115fe576040805161ffff80851682528316602082015281517fac49e518f90a358f652e4400164f05a5d8f7e35e7747279bc3a93dbf584e125a929181900390910190a15b50506000805460ff60f01b1916600160f01b17905550565b6000546001600160a01b03811690600160a01b810460020b9061ffff600160b81b8204811691600160c81b8104821691600160d81b8204169060ff600160e81b8204811691600160f01b90041687565b600080548190600160f01b900460ff166116ad576040805162461bcd60e51b81526020600482015260036024820152624c4f4b60e81b604482015290519081900360640190fd5b6000805460ff60f01b191690556001600160801b0385166116cd57600080fd5b60008061171b60405180608001604052808c6001600160a01b031681526020018b60020b81526020018a60020b81526020016117118a6001600160801b0316613f58565b600f0b9052613f69565b9250925050819350809250600080600086111561173d5761173a613cd4565b91505b841561174e5761174b613e1d565b90505b336001600160a01b031663d348799787878b8b6040518563ffffffff1660e01b815260040180858152602001848152602001806020018281038252848482818152602001925080828437600081840152601f19601f82011690508083019250505095505050505050600060405180830381600087803b1580156117d057600080fd5b505af11580156117e4573d6000803e3d6000fd5b50505050600086111561183b576117f9613cd4565b6118038388613e0d565b111561183b576040805162461bcd60e51b815260206004820152600260248201526104d360f41b604482015290519081900360640190fd5b841561188b57611849613e1d565b6118538287613e0d565b111561188b576040805162461bcd60e51b81526020600482015260026024820152614d3160f01b604482015290519081900360640190fd5b8960020b8b60020b8d6001600160a01b03167f7a53080ba414158be7ec69b987b5fb7d07dee101fe85488f0853ae16239d0bde338d8b8b60405180856001600160a01b03168152602001846001600160801b0316815260200183815260200182815260200194505050505060405180910390a450506000805460ff60f01b1916600160f01b17905550919890975095505050505050565b60025481565b600054600160f01b900460ff1661196c576040805162461bcd60e51b81526020600482015260036024820152624c4f4b60e81b604482015290519081900360640190fd5b6000805460ff60f01b19169055611981612bf0565b6004546001600160801b0316806119c3576040805162461bcd60e51b81526020600482015260016024820152601360fa1b604482015290519081900360640190fd5b60006119f8867f000000000000000000000000000000000000000000000000000000000000000062ffffff16620f42406141a9565b90506000611a2f867f000000000000000000000000000000000000000000000000000000000000000062ffffff16620f42406141a9565b90506000611a3b613cd4565b90506000611a47613e1d565b90508815611a7a57611a7a7f00000000000000000000000000000000000000000000000000000000000000008b8b613b86565b8715611aab57611aab7f00000000000000000000000000000000000000000000000000000000000000008b8a613b86565b336001600160a01b031663e9cbafb085858a8a6040518563ffffffff1660e01b815260040180858152602001848152602001806020018281038252848482818152602001925080828437600081840152601f19601f82011690508083019250505095505050505050600060405180830381600087803b158015611b2d57600080fd5b505af1158015611b41573d6000803e3d6000fd5b505050506000611b4f613cd4565b90506000611b5b613e1d565b905081611b688588613e0d565b1115611ba0576040805162461bcd60e51b8152602060048201526002602482015261046360f41b604482015290519081900360640190fd5b80611bab8487613e0d565b1115611be3576040805162461bcd60e51b8152602060048201526002602482015261463160f01b604482015290519081900360640190fd5b8382038382038115611c725760008054600160e81b9004600f16908115611c16578160ff168481611c1057fe5b04611c19565b60005b90506001600160801b03811615611c4c57600380546001600160801b038082168401166001600160801b03199091161790555b611c66818503600160801b8d6001600160801b03166132d9565b60018054909101905550505b8015611cfd5760008054600160e81b900460041c600f16908115611ca2578160ff168381611c9c57fe5b04611ca5565b60005b90506001600160801b03811615611cd757600380546001600160801b03600160801b8083048216850182160291161790555b611cf1818403600160801b8d6001600160801b03166132d9565b60028054909101905550505b8d6001600160a01b0316336001600160a01b03167fbdbdb71d7860376ba52b25a5028beea23581364a40522f6bcfb86bb1f2dca6338f8f86866040518085815260200184815260200183815260200182815260200194505050505060405180910390a350506000805460ff60f01b1916600160f01b179055505050505050505050505050565b600080548190600160f01b900460ff16611dca576040805162461bcd60e51b81526020600482015260036024820152624c4f4b60e81b604482015290519081900360640190fd5b6000805460ff60f01b19168155611de460073389896141e3565b60038101549091506001600160801b0390811690861611611e055784611e14565b60038101546001600160801b03165b60038201549093506001600160801b03600160801b909104811690851611611e3c5783611e52565b6003810154600160801b90046001600160801b03165b91506001600160801b03831615611eb7576003810180546001600160801b031981166001600160801b03918216869003821617909155611eb7907f0000000000000000000000000000000000000000000000000000000000000000908a908616613b86565b6001600160801b03821615611f1d576003810180546001600160801b03600160801b808304821686900382160291811691909117909155611f1d907f0000000000000000000000000000000000000000000000000000000000000000908a908516613b86565b604080516001600160a01b038a1681526001600160801b0380861660208301528416818301529051600288810b92908a900b9133917f70935338e69775456a85ddef226c395fb668b63fa0115f5f20610b388e6ca9c0919081900360600190a4506000805460ff60f01b1916600160f01b17905590969095509350505050565b60076020526000908152604090208054600182015460028301546003909301546001600160801b0392831693919281811691600160801b90041685565b60066020526000908152604090205481565b7f000000000000000000000000000000000000000000000000000000000000000081565b600054600160f01b900460ff16612054576040805162461bcd60e51b81526020600482015260036024820152624c4f4b60e81b604482015290519081900360640190fd5b6000805460ff60f01b1916905560408051638da5cb5b60e01b815290516001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691638da5cb5b916004808301926020929190829003018186803b1580156120c157600080fd5b505afa1580156120d5573d6000803e3d6000fd5b505050506040513d60208110156120eb57600080fd5b50516001600160a01b0316331461210157600080fd5b60ff82161580612124575060048260ff16101580156121245750600a8260ff1611155b801561214e575060ff8116158061214e575060048160ff161015801561214e5750600a8160ff1611155b61215757600080fd5b60008054610ff0600484901b16840160ff908116600160e81b9081027fffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff841617909355919004167f973d8d92bb299f4af6ce49b52a8adb85ae46b9f214c4c4fc06ac77401237b1336010826040805160ff9390920683168252600f600486901c16602083015286831682820152918516606082015290519081900360800190a150506000805460ff60f01b1916600160f01b17905550565b600080548190600160f01b900460ff16612256576040805162461bcd60e51b81526020600482015260036024820152624c4f4b60e81b604482015290519081900360640190fd5b6000805460ff60f01b1916905560408051638da5cb5b60e01b815290516001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691638da5cb5b916004808301926020929190829003018186803b1580156122c357600080fd5b505afa1580156122d7573d6000803e3d6000fd5b505050506040513d60208110156122ed57600080fd5b50516001600160a01b0316331461230357600080fd5b6003546001600160801b039081169085161161231f578361232c565b6003546001600160801b03165b6003549092506001600160801b03600160801b9091048116908416116123525782612366565b600354600160801b90046001600160801b03165b90506001600160801b038216156123e7576003546001600160801b038381169116141561239557600019909101905b600380546001600160801b031981166001600160801b039182168590038216179091556123e7907f00000000000000000000000000000000000000000000000000000000000000009087908516613b86565b6001600160801b0381161561246d576003546001600160801b03828116600160801b90920416141561241857600019015b600380546001600160801b03600160801b80830482168590038216029181169190911790915561246d907f00000000000000000000000000000000000000000000000000000000000000009087908416613b86565b604080516001600160801b0380851682528316602082015281516001600160a01b0388169233927f596b573906218d3411850b26a6b437d6c4522fdb43d2d2386263f86d50b8b151929081900390910190a36000805460ff60f01b1916600160f01b1790559094909350915050565b6060806124e7612bf0565b61255e6124f2612c27565b858580806020026020016040519081016040528093929190818152602001838360200280828437600092018290525054600454600896959450600160a01b820460020b935061ffff600160b81b8304811693506001600160801b0390911691600160c81b900416614247565b915091509250929050565b600080548190600160f01b900460ff166125b0576040805162461bcd60e51b81526020600482015260036024820152624c4f4b60e81b604482015290519081900360640190fd5b6000805460ff60f01b1916815560408051608081018252338152600288810b602083015287900b918101919091528190819061260990606081016125fc6001600160801b038a16613f58565b600003600f0b9052613f69565b925092509250816000039450806000039350600085118061262a5750600084115b15612669576003830180546001600160801b038082168089018216600160801b93849004831689019092169092029091176001600160801b0319161790555b604080516001600160801b0388168152602081018790528082018690529051600289810b92908b900b9133917f0c396cd989a39f4459b5fa1aed6a9a8dcdbc45908acfd67e028cd568da98982c919081900360600190a450506000805460ff60f01b1916600160f01b179055509094909350915050565b60008060006126ed612bf0565b6126f785856143a1565b600285810b810b60009081526005602052604080822087840b90930b825281206003830154600681900b9367010000000000000082046001600160a01b0316928492600160d81b810463ffffffff169284929091600160f81b900460ff168061275f57600080fd5b6003820154600681900b985067010000000000000081046001600160a01b03169650600160d81b810463ffffffff169450600160f81b900460ff16806127a457600080fd5b50506040805160e0810182526000546001600160a01b0381168252600160a01b8104600290810b810b810b6020840181905261ffff600160b81b8404811695850195909552600160c81b830485166060850152600160d81b8304909416608084015260ff600160e81b8304811660a0850152600160f01b909204909116151560c08301529093508e810b91900b1215905061284d575093909403965090039350900390506128d0565b8a60020b816020015160020b12156128c1576000612869612c27565b602083015160408401516004546060860151939450600093849361289f936008938893879392916001600160801b031690613389565b9a9003989098039b5050949096039290920396509091030392506128d0915050565b50949093039650039350900390505b9250925092565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000081565b60015481565b60056020526000908152604090208054600182015460028301546003909301546001600160801b03831693600160801b909304600f0b9290600681900b9067010000000000000081046001600160a01b031690600160d81b810463ffffffff1690600160f81b900460ff1688565b6000546001600160a01b031615612a1e576040805162461bcd60e51b8152602060048201526002602482015261414960f01b604482015290519081900360640190fd5b6000612a29826136a5565b9050600080612a41612a39612c27565b60089061446a565b6040805160e0810182526001600160a01b038816808252600288810b6020808501829052600085870181905261ffff898116606088018190529089166080880181905260a08801839052600160c0909801979097528154600160f01b73ffffffffffffffffffffffffffffffffffffffff19909116871762ffffff60a01b1916600160a01b62ffffff9787900b9790971696909602959095177fffffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffff16600160c81b9091021761ffff60d81b1916600160d81b909602959095177fff0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1692909217909355835191825281019190915281519395509193507f98636036cb66a9c19a37435efc1e90142190214e8abeb821bdba3f2990dd4c9592918290030190a150505050565b60008082600281900b620d89e71981612b9957fe5b05029050600083600281900b620d89e881612bb057fe5b0502905060008460020b83830360020b81612bc757fe5b0560010190508062ffffff166001600160801b03801681612be457fe5b0493505050505b919050565b306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614612c2557600080fd5b565b4290565b60008060008460020b8660020b81612c3f57fe5b05905060008660020b128015612c6657508460020b8660020b81612c5f57fe5b0760020b15155b15612c7057600019015b8315612ce557600080612c82836144b6565b600182810b810b600090815260208d9052604090205460ff83169190911b80016000190190811680151597509294509092509085612cc757888360ff16860302612cda565b88612cd1826144c8565b840360ff168603025b965050505050612d63565b600080612cf4836001016144b6565b91509150600060018260ff166001901b031990506000818b60008660010b60010b8152602001908152602001600020541690508060001415955085612d4657888360ff0360ff16866001010102612d5c565b8883612d5183614568565b0360ff168660010101025b9650505050505b5094509492505050565b60008060008360020b12612d84578260020b612d8c565b8260020b6000035b9050620d89e8811115612dca576040805162461bcd60e51b81526020600482015260016024820152601560fa1b604482015290519081900360640190fd5b600060018216612dde57600160801b612df0565b6ffffcb933bd6fad37aa2d162d1a5940015b70ffffffffffffffffffffffffffffffffff1690506002821615612e24576ffff97272373d413259a46990580e213a0260801c5b6004821615612e43576ffff2e50f5f656932ef12357cf3c7fdcc0260801c5b6008821615612e62576fffe5caca7e10e4e61c3624eaa0941cd00260801c5b6010821615612e81576fffcb9843d60f6159c9db58835c9266440260801c5b6020821615612ea0576fff973b41fa98c081472e6896dfb254c00260801c5b6040821615612ebf576fff2ea16466c96a3843ec78b326b528610260801c5b6080821615612ede576ffe5dee046a99a2a811c461f1969c30530260801c5b610100821615612efe576ffcbe86c7900a88aedcffc83b479aa3a40260801c5b610200821615612f1e576ff987a7253ac413176f2b074cf7815e540260801c5b610400821615612f3e576ff3392b0822b70005940c7a398e4b70f30260801c5b610800821615612f5e576fe7159475a2c29b7443b29c7fa6e889d90260801c5b611000821615612f7e576fd097f3bdfd2022b8845ad8f792aa58250260801c5b612000821615612f9e576fa9f746462d870fdf8a65dc1f90e061e50260801c5b614000821615612fbe576f70d869a156d2a1b890bb3df62baf32f70260801c5b618000821615612fde576f31be135f97d08fd981231505542fcfa60260801c5b62010000821615612fff576f09aa508b5b7a84e1c677de54f3e99bc90260801c5b6202000082161561301f576e5d6af8dedb81196699c329225ee6040260801c5b6204000082161561303e576d2216e584f5fa1ea926041bedfe980260801c5b6208000082161561305b576b048a170391f7dc42444e8fa20260801c5b60008460020b131561307657806000198161307257fe5b0490505b64010000000081061561308a57600161308d565b60005b60ff16602082901c0192505050919050565b60008080806001600160a01b03808916908a1610158187128015906131245760006130d88989620f42400362ffffff16620f42406132d9565b9050826130f1576130ec8c8c8c6001614652565b6130fe565b6130fe8b8d8c60016146cd565b955085811061310f578a965061311e565b61311b8c8b838661478a565b96505b5061316e565b8161313b576131368b8b8b60006146cd565b613148565b6131488a8c8b6000614652565b935083886000031061315c5789955061316e565b61316b8b8a8a600003856147d6565b95505b6001600160a01b038a81169087161482156131d15780801561318d5750815b6131a35761319e878d8c60016146cd565b6131a5565b855b95508080156131b2575081155b6131c8576131c3878d8c6000614652565b6131ca565b845b945061321b565b8080156131db5750815b6131f1576131ec8c888c6001614652565b6131f3565b855b9550808015613200575081155b613216576132118c888c60006146cd565b613218565b845b94505b8115801561322b57508860000385115b15613237578860000394505b81801561325657508a6001600160a01b0316876001600160a01b031614155b15613265578589039350613282565b61327f868962ffffff168a620f42400362ffffff166141a9565b93505b50505095509550955095915050565b6000600160ff1b82106132a357600080fd5b5090565b808203828113156000831215146132bd57600080fd5b92915050565b818101828112156000831215146132bd57600080fd5b600080806000198587098686029250828110908390030390508061330f576000841161330457600080fd5b508290049050613382565b80841161331b57600080fd5b6000848688096000868103871696879004966002600389028118808a02820302808a02820302808a02820302808a02820302808a02820302808a02909103029181900381900460010186841190950394909402919094039290920491909117919091029150505b9392505050565b60008063ffffffff8716613430576000898661ffff1661ffff81106133aa57fe5b60408051608081018252919092015463ffffffff8082168084526401000000008304600690810b810b900b6020850152600160581b83046001600160a01b031694840194909452600160f81b90910460ff16151560608301529092508a161461341c57613419818a8988614822565b90505b806020015181604001519250925050613510565b8688036000806134458c8c858c8c8c8c6148d2565b91509150816000015163ffffffff168363ffffffff161415613477578160200151826040015194509450505050613510565b805163ffffffff8481169116141561349f578060200151816040015194509450505050613510565b8151815160208085015190840151918390039286039163ffffffff80841692908516910360060b816134cd57fe5b05028460200151018263ffffffff168263ffffffff1686604001518660400151036001600160a01b031602816134ff57fe5b048560400151019650965050505050505b97509795505050505050565b600295860b860b60009081526020979097526040909620600181018054909503909455938301805490920390915560038201805463ffffffff600160d81b6001600160a01b036701000000000000008085048216909603169094027fffffffffff0000000000000000000000000000000000000000ffffffffffffff90921691909117600681810b90960390950b66ffffffffffffff1666ffffffffffffff199095169490941782810485169095039093160263ffffffff60d81b1990931692909217905554600160801b9004600f0b90565b60008082600f0b121561365457826001600160801b03168260000384039150816001600160801b03161061364f576040805162461bcd60e51b81526020600482015260026024820152614c5360f01b604482015290519081900360640190fd5b6132bd565b826001600160801b03168284019150816001600160801b031610156132bd576040805162461bcd60e51b81526020600482015260026024820152614c4160f01b604482015290519081900360640190fd5b60006401000276a36001600160a01b038316108015906136e1575073fffd8963efd1fc6a506488495d951d5263988d266001600160a01b038316105b613716576040805162461bcd60e51b81526020600482015260016024820152602960f91b604482015290519081900360640190fd5b77ffffffffffffffffffffffffffffffffffffffff00000000602083901b166001600160801b03811160071b81811c67ffffffffffffffff811160061b90811c63ffffffff811160051b90811c61ffff811160041b90811c60ff8111600390811b91821c600f811160021b90811c918211600190811b92831c979088119617909417909217179091171717608081106137b757607f810383901c91506137c1565b80607f0383901b91505b908002607f81811c60ff83811c9190911c800280831c81831c1c800280841c81841c1c800280851c81851c1c800280861c81861c1c800280871c81871c1c800280881c81881c1c800280891c81891c1c8002808a1c818a1c1c8002808b1c818b1c1c8002808c1c818c1c1c8002808d1c818d1c1c8002808e1c9c81901c9c909c1c80029c8d901c9e9d607f198f0160401b60c09190911c678000000000000000161760c19b909b1c674000000000000000169a909a1760c29990991c672000000000000000169890981760c39790971c671000000000000000169690961760c49590951c670800000000000000169490941760c59390931c670400000000000000169290921760c69190911c670200000000000000161760c79190911c670100000000000000161760c89190911c6680000000000000161760c99190911c6640000000000000161760ca9190911c6620000000000000161760cb9190911c6610000000000000161760cc9190911c6608000000000000161760cd9190911c66040000000000001617693627a301d71055774c8581026f028f6481ab7f045a5af012a19d003aa9198101608090811d906fdb2df09e81959a81455e260799a0632f8301901d600281810b9083900b146139c257886001600160a01b03166139a682612d6d565b6001600160a01b031611156139bb57816139bd565b805b6139c4565b815b9998505050505050505050565b6000806000898961ffff1661ffff81106139e757fe5b60408051608081018252919092015463ffffffff8082168084526401000000008304600690810b810b900b6020850152600160581b83046001600160a01b031694840194909452600160f81b90910460ff161515606083015290925089161415613a575788859250925050613510565b8461ffff168461ffff16118015613a7857506001850361ffff168961ffff16145b15613a8557839150613a89565b8491505b8161ffff168960010161ffff1681613a9d57fe5b069250613aac81898989614822565b8a8461ffff1661ffff8110613abd57fe5b825191018054602084015160408501516060909501511515600160f81b027effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6001600160a01b03909616600160581b027fff0000000000000000000000000000000000000000ffffffffffffffffffffff60069390930b66ffffffffffffff16640100000000026affffffffffffff000000001963ffffffff90971663ffffffff199095169490941795909516929092171692909217929092161790555097509795505050505050565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b1781529251825160009485949389169392918291908083835b60208310613c025780518252601f199092019160209182019101613be3565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114613c64576040519150601f19603f3d011682016040523d82523d6000602084013e613c69565b606091505b5091509150818015613c97575080511580613c975750808060200190516020811015613c9457600080fd5b50515b613ccd576040805162461bcd60e51b81526020600482015260026024820152612a2360f11b604482015290519081900360640190fd5b5050505050565b604080513060248083019190915282518083039091018152604490910182526020810180516001600160e01b03166370a0823160e01b17815291518151600093849384936001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001693919290918291908083835b60208310613d6d5780518252601f199092019160209182019101613d4e565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d8060008114613dcd576040519150601f19603f3d011682016040523d82523d6000602084013e613dd2565b606091505b5091509150818015613de657506020815110155b613def57600080fd5b808060200190516020811015613e0457600080fd5b50519250505090565b808201828110156132bd57600080fd5b604080513060248083019190915282518083039091018152604490910182526020810180516001600160e01b03166370a0823160e01b17815291518151600093849384936001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016939192909182919080838360208310613d6d5780518252601f199092019160209182019101613d4e565b6000808361ffff1611613ef3576040805162461bcd60e51b81526020600482015260016024820152604960f81b604482015290519081900360640190fd5b8261ffff168261ffff1611613f09575081613382565b825b8261ffff168161ffff161015613f4f576001858261ffff1661ffff8110613f2e57fe5b01805463ffffffff191663ffffffff92909216919091179055600101613f0b565b50909392505050565b80600f81900b8114612beb57600080fd5b6000806000613f76612bf0565b613f88846020015185604001516143a1565b6040805160e0810182526000546001600160a01b0381168252600160a01b8104600290810b810b900b602080840182905261ffff600160b81b8404811685870152600160c81b84048116606080870191909152600160d81b8504909116608086015260ff600160e81b8504811660a0870152600160f01b909404909316151560c08501528851908901519489015192890151939461402c9491939092909190614acf565b93508460600151600f0b6000146141a157846020015160020b816020015160020b12156140815761407a6140638660200151612d6d565b6140708760400151612d6d565b8760600151614c84565b92506141a1565b846040015160020b816020015160020b12156141775760045460408201516001600160801b03909116906140d3906140b7612c27565b60208501516060860151608087015160089493929187916139d1565b6000805461ffff60c81b1916600160c81b61ffff938416021761ffff60b81b1916600160b81b939092169290920217905581516040870151614123919061411990612d6d565b8860600151614c84565b93506141416141358760200151612d6d565b83516060890151614cc8565b92506141518187606001516135ef565b600480546001600160801b0319166001600160801b0392909216919091179055506141a1565b61419e6141878660200151612d6d565b6141948760400151612d6d565b8760600151614cc8565b91505b509193909250565b60006141b68484846132d9565b9050600082806141c257fe5b84860911156133825760001981106141d957600080fd5b6001019392505050565b6040805160609490941b6bffffffffffffffffffffffff1916602080860191909152600293840b60e890811b60348701529290930b90911b60378401528051808403601a018152603a90930181528251928201929092206000908152929052902090565b60608060008361ffff1611614287576040805162461bcd60e51b81526020600482015260016024820152604960f81b604482015290519081900360640190fd5b865167ffffffffffffffff8111801561429f57600080fd5b506040519080825280602002602001820160405280156142c9578160200160208202803683370190505b509150865167ffffffffffffffff811180156142e457600080fd5b5060405190808252806020026020018201604052801561430e578160200160208202803683370190505b50905060005b87518110156143945761433f8a8a8a848151811061432e57fe5b60200260200101518a8a8a8a613389565b84838151811061434b57fe5b6020026020010184848151811061435e57fe5b60200260200101826001600160a01b03166001600160a01b03168152508260060b60060b81525050508080600101915050614314565b5097509795505050505050565b8060020b8260020b126143e1576040805162461bcd60e51b8152602060048201526003602482015262544c5560e81b604482015290519081900360640190fd5b620d89e719600283900b1215614424576040805162461bcd60e51b8152602060048201526003602482015262544c4d60e81b604482015290519081900360640190fd5b620d89e8600282900b1315614466576040805162461bcd60e51b815260206004820152600360248201526254554d60e81b604482015290519081900360640190fd5b5050565b6040805160808101825263ffffffff9283168082526000602083018190529282019290925260016060909101819052835463ffffffff1916909117909116600160f81b17909155908190565b60020b600881901d9161010090910790565b60008082116144d657600080fd5b600160801b82106144e957608091821c91015b68010000000000000000821061450157604091821c91015b640100000000821061451557602091821c91015b62010000821061452757601091821c91015b610100821061453857600891821c91015b6010821061454857600491821c91015b6004821061455857600291821c91015b60028210612beb57600101919050565b600080821161457657600080fd5b5060ff6001600160801b0382161561459157607f1901614599565b608082901c91505b67ffffffffffffffff8216156145b257603f19016145ba565b604082901c91505b63ffffffff8216156145cf57601f19016145d7565b602082901c91505b61ffff8216156145ea57600f19016145f2565b601082901c91505b60ff821615614604576007190161460c565b600882901c91505b600f82161561461e5760031901614626565b600482901c91505b60038216156146385760011901614640565b600282901c91505b6001821615612beb5760001901919050565b6000836001600160a01b0316856001600160a01b03161115614672579293925b8161469f5761469a836001600160801b03168686036001600160a01b0316600160601b6132d9565b6146c2565b6146c2836001600160801b03168686036001600160a01b0316600160601b6141a9565b90505b949350505050565b6000836001600160a01b0316856001600160a01b031611156146ed579293925b7bffffffffffffffffffffffffffffffff000000000000000000000000606084901b166001600160a01b03868603811690871661472957600080fd5b8361475957866001600160a01b031661474c8383896001600160a01b03166132d9565b8161475357fe5b0461477f565b61477f6147708383896001600160a01b03166141a9565b886001600160a01b0316614cf7565b979650505050505050565b600080856001600160a01b0316116147a157600080fd5b6000846001600160801b0316116147b757600080fd5b816147c95761469a8585856001614d02565b6146c28585856001614de3565b600080856001600160a01b0316116147ed57600080fd5b6000846001600160801b03161161480357600080fd5b816148155761469a8585856000614de3565b6146c28585856000614d02565b61482a61564a565b600085600001518503905060405180608001604052808663ffffffff1681526020018263ffffffff168660020b0288602001510160060b81526020016000856001600160801b03161161487e576001614880565b845b6001600160801b031673ffffffff00000000000000000000000000000000608085901b16816148ab57fe5b048860400151016001600160a01b0316815260200160011515815250915050949350505050565b6148da61564a565b6148e261564a565b888561ffff1661ffff81106148f357fe5b60408051608081018252919092015463ffffffff81168083526401000000008204600690810b810b900b6020840152600160581b82046001600160a01b031693830193909352600160f81b900460ff1615156060820152925061495890899089614ed8565b15614990578663ffffffff16826000015163ffffffff16141561497a57613510565b8161498783898988614822565b91509150613510565b888361ffff168660010161ffff16816149a557fe5b0661ffff1661ffff81106149b557fe5b60408051608081018252929091015463ffffffff811683526401000000008104600690810b810b900b60208401526001600160a01b03600160581b8204169183019190915260ff600160f81b90910416151560608201819052909250614a6c57604080516080810182528a5463ffffffff811682526401000000008104600690810b810b900b6020830152600160581b81046001600160a01b031692820192909252600160f81b90910460ff161515606082015291505b614a7b88836000015189614ed8565b614ab2576040805162461bcd60e51b815260206004820152600360248201526213d31160ea1b604482015290519081900360640190fd5b614abf8989898887614f9b565b9150915097509795505050505050565b6000614ade60078787876141e3565b60015460025491925090600080600f87900b15614c24576000614aff612c27565b6000805460045492935090918291614b499160089186918591600160a01b810460020b9161ffff600160b81b83048116926001600160801b0390921691600160c81b900416613389565b9092509050614b8360058d8b8d8b8b87898b60007f000000000000000000000000000000000000000000000000000000000000000061513b565b9450614bba60058c8b8d8b8b87898b60017f000000000000000000000000000000000000000000000000000000000000000061513b565b93508415614bee57614bee60068d7f0000000000000000000000000000000000000000000000000000000000000000615325565b8315614c2057614c2060068c7f0000000000000000000000000000000000000000000000000000000000000000615325565b5050505b600080614c3660058c8c8b8a8a61538b565b9092509050614c47878a8484615437565b600089600f0b1215614c75578315614c6457614c6460058c6155cc565b8215614c7557614c7560058b6155cc565b50505050505095945050505050565b60008082600f0b12614caa57614ca5614ca085858560016146cd565b613291565b6146c5565b614cbd614ca085858560000360006146cd565b600003949350505050565b60008082600f0b12614ce457614ca5614ca08585856001614652565b614cbd614ca08585856000036000614652565b808204910615150190565b60008115614d755760006001600160a01b03841115614d3857614d3384600160601b876001600160801b03166132d9565b614d50565b6001600160801b038516606085901b81614d4e57fe5b045b9050614d6d614d686001600160a01b03881683613e0d565b6155f8565b9150506146c5565b60006001600160a01b03841115614da357614d9e84600160601b876001600160801b03166141a9565b614dba565b614dba606085901b6001600160801b038716614cf7565b905080866001600160a01b031611614dd157600080fd5b6001600160a01b0386160390506146c5565b600082614df15750836146c5565b7bffffffffffffffffffffffffffffffff000000000000000000000000606085901b168215614e91576001600160a01b03861684810290858281614e3157fe5b041415614e6257818101828110614e6057614e5683896001600160a01b0316836141a9565b93505050506146c5565b505b614e8882614e83878a6001600160a01b03168681614e7c57fe5b0490613e0d565b614cf7565b925050506146c5565b6001600160a01b03861684810290858281614ea857fe5b04148015614eb557508082115b614ebe57600080fd5b808203614e56614d68846001600160a01b038b16846141a9565b60008363ffffffff168363ffffffff1611158015614f0257508363ffffffff168263ffffffff1611155b15614f1e578163ffffffff168363ffffffff1611159050613382565b60008463ffffffff168463ffffffff1611614f46578363ffffffff1664010000000001614f4e565b8363ffffffff165b64ffffffffff16905060008563ffffffff168463ffffffff1611614f7f578363ffffffff1664010000000001614f87565b8363ffffffff165b64ffffffffff169091111595945050505050565b614fa361564a565b614fab61564a565b60008361ffff168560010161ffff1681614fc157fe5b0661ffff169050600060018561ffff16830103905060005b506002818301048961ffff87168281614fee57fe5b0661ffff8110614ffa57fe5b60408051608081018252929091015463ffffffff811683526401000000008104600690810b810b900b60208401526001600160a01b03600160581b8204169183019190915260ff600160f81b9091041615156060820181905290955061506557806001019250614fd9565b898661ffff16826001018161507657fe5b0661ffff811061508257fe5b60408051608081018252929091015463ffffffff811683526401000000008104600690810b810b900b60208401526001600160a01b03600160581b8204169183019190915260ff600160f81b909104161515606082015285519094506000906150ed908b908b614ed8565b905080801561510657506151068a8a8760000151614ed8565b15615111575061512e565b8061512157600182039250615128565b8160010193505b50614fd9565b5050509550959350505050565b60028a810b900b600090815260208c90526040812080546001600160801b031682615166828d6135ef565b9050846001600160801b0316816001600160801b031611156151b4576040805162461bcd60e51b81526020600482015260026024820152614c4f60f01b604482015290519081900360640190fd5b6001600160801b03828116159082161581141594501561528a578c60020b8e60020b1361525a57600183018b9055600283018a90556003830180547fffffffffff0000000000000000000000000000000000000000ffffffffffffff166701000000000000006001600160a01b038c16021766ffffffffffffff191666ffffffffffffff60068b900b161763ffffffff60d81b1916600160d81b63ffffffff8a16021790555b6003830180547effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b1790555b82546001600160801b0319166001600160801b038216178355856152d35782546152ce906152c990600160801b9004600f90810b810b908f900b6132c3565b613f58565b6152f4565b82546152f4906152c990600160801b9004600f90810b810b908f900b6132a7565b8354600f9190910b6001600160801b03908116600160801b0291161790925550909c9b505050505050505050505050565b8060020b8260020b8161533457fe5b0760020b1561534257600080fd5b60008061535d8360020b8560020b8161535757fe5b056144b6565b600191820b820b60009081526020979097526040909620805460ff9097169190911b90951890945550505050565b600285810b80820b60009081526020899052604080822088850b850b83529082209193849391929184918291908a900b126153d1575050600182015460028301546153e4565b8360010154880391508360020154870390505b6000808b60020b8b60020b121561540657505060018301546002840154615419565b84600101548a0391508460020154890390505b92909803979097039b96909503949094039850939650505050505050565b6040805160a08101825285546001600160801b0390811682526001870154602083015260028701549282019290925260038601548083166060830152600160801b900490911660808201526000600f85900b6154d65781516001600160801b03166154ce576040805162461bcd60e51b815260206004820152600260248201526104e560f41b604482015290519081900360640190fd5b5080516154e5565b81516154e290866135ef565b90505b60006155098360200151860384600001516001600160801b0316600160801b6132d9565b9050600061552f8460400151860385600001516001600160801b0316600160801b6132d9565b905086600f0b6000146155565787546001600160801b0319166001600160801b0384161788555b60018801869055600288018590556001600160801b03821615158061558457506000816001600160801b0316115b156155c2576003880180546001600160801b031981166001600160801b039182168501821617808216600160801b9182900483168501909216021790555b5050505050505050565b600290810b810b6000908152602092909252604082208281556001810183905590810182905560030155565b806001600160a01b0381168114612beb57600080fd5b6040805160e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c081019190915290565b6040805160808101825260008082526020820181905291810182905260608101919091529056fea164736f6c6343000706000aa164736f6c6343000706000a", + "linkReferences": {}, + "deployedLinkReferences": {} +} diff --git a/external/contracts/uniswap/GovernorAlpha.sol b/external/contracts/uniswap/v2/GovernorAlpha.sol similarity index 100% rename from external/contracts/uniswap/GovernorAlpha.sol rename to external/contracts/uniswap/v2/GovernorAlpha.sol diff --git a/external/contracts/uniswap/StakingRewards.sol b/external/contracts/uniswap/v2/StakingRewards.sol similarity index 100% rename from external/contracts/uniswap/StakingRewards.sol rename to external/contracts/uniswap/v2/StakingRewards.sol diff --git a/external/contracts/uniswap/Uni.sol b/external/contracts/uniswap/v2/Uni.sol similarity index 100% rename from external/contracts/uniswap/Uni.sol rename to external/contracts/uniswap/v2/Uni.sol diff --git a/external/contracts/uniswap/UniswapTimelock.sol b/external/contracts/uniswap/v2/UniswapTimelock.sol similarity index 100% rename from external/contracts/uniswap/UniswapTimelock.sol rename to external/contracts/uniswap/v2/UniswapTimelock.sol diff --git a/external/contracts/uniswap/UniswapV2Factory.sol b/external/contracts/uniswap/v2/UniswapV2Factory.sol similarity index 100% rename from external/contracts/uniswap/UniswapV2Factory.sol rename to external/contracts/uniswap/v2/UniswapV2Factory.sol diff --git a/external/contracts/uniswap/UniswapV2Pair.sol b/external/contracts/uniswap/v2/UniswapV2Pair.sol similarity index 100% rename from external/contracts/uniswap/UniswapV2Pair.sol rename to external/contracts/uniswap/v2/UniswapV2Pair.sol diff --git a/external/contracts/uniswap/UniswapV2Router02.sol b/external/contracts/uniswap/v2/UniswapV2Router02.sol similarity index 100% rename from external/contracts/uniswap/UniswapV2Router02.sol rename to external/contracts/uniswap/v2/UniswapV2Router02.sol diff --git a/external/contracts/uniswap/lib/UniswapV2Library.sol b/external/contracts/uniswap/v2/lib/UniswapV2Library.sol similarity index 95% rename from external/contracts/uniswap/lib/UniswapV2Library.sol rename to external/contracts/uniswap/v2/lib/UniswapV2Library.sol index fa3cd68f4..b0d958528 100644 --- a/external/contracts/uniswap/lib/UniswapV2Library.sol +++ b/external/contracts/uniswap/v2/lib/UniswapV2Library.sol @@ -1,6 +1,6 @@ pragma solidity 0.6.10; -import "../../../../contracts/interfaces/external/IUniswapV2Pair.sol"; +import "../../../../../contracts/interfaces/external/IUniswapV2Pair.sol"; import { SafeMath } from "@openzeppelin/contracts/math/SafeMath.sol"; diff --git a/external/contracts/uniswap/v3/SwapRouter.sol b/external/contracts/uniswap/v3/SwapRouter.sol new file mode 100644 index 000000000..be180e0e7 --- /dev/null +++ b/external/contracts/uniswap/v3/SwapRouter.sol @@ -0,0 +1,244 @@ +// 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 './interfaces/ISwapRouter.sol'; +import './base/PeripheryImmutableState.sol'; +import './base/PeripheryValidation.sol'; +import './base/PeripheryPaymentsWithFee.sol'; +import './base/Multicall.sol'; +import './base/SelfPermit.sol'; +import './libraries/Path.sol'; +import './libraries/PoolAddress.sol'; +import './libraries/CallbackValidation.sol'; +import './interfaces/external/IWETH9.sol'; + +/// @title Uniswap V3 Swap Router +/// @notice Router for stateless execution of swaps against Uniswap V3 +contract SwapRouter is + ISwapRouter, + PeripheryImmutableState, + PeripheryValidation, + PeripheryPaymentsWithFee, + Multicall, + SelfPermit +{ + 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; + + constructor(address _factory, address _WETH9) PeripheryImmutableState(_factory, _WETH9) {} + + /// @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; + tokenIn = tokenOut; // swap in/out because exact output swaps are reversed + pay(tokenIn, 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) { + // allow swapping to the router address with address 0 + if (recipient == address(0)) 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 ISwapRouter + function exactInputSingle(ExactInputSingleParams calldata params) + external + payable + override + checkDeadline(params.deadline) + returns (uint256 amountOut) + { + amountOut = exactInputInternal( + params.amountIn, + params.recipient, + params.sqrtPriceLimitX96, + SwapCallbackData({path: abi.encodePacked(params.tokenIn, params.fee, params.tokenOut), payer: msg.sender}) + ); + require(amountOut >= params.amountOutMinimum, 'Too little received'); + } + + /// @inheritdoc ISwapRouter + function exactInput(ExactInputParams memory params) + external + payable + override + checkDeadline(params.deadline) + returns (uint256 amountOut) + { + address payer = msg.sender; // msg.sender pays for the first hop + + 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); // at this point, the caller has paid + 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) { + // allow swapping to the router address with address 0 + if (recipient == address(0)) 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 ISwapRouter + function exactOutputSingle(ExactOutputSingleParams calldata params) + external + payable + override + checkDeadline(params.deadline) + 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 ISwapRouter + function exactOutput(ExactOutputParams calldata params) + external + payable + override + checkDeadline(params.deadline) + returns (uint256 amountIn) + { + // it's okay that the payer is fixed to msg.sender here, as they're only paying for the "final" exact output + // swap, which happens first, and subsequent swaps are paid for within nested callback frames + 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; + } +} \ No newline at end of file diff --git a/external/contracts/uniswap/v3/UniswapV3Factory.sol b/external/contracts/uniswap/v3/UniswapV3Factory.sol new file mode 100644 index 000000000..3553ce55e --- /dev/null +++ b/external/contracts/uniswap/v3/UniswapV3Factory.sol @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity =0.7.6; + +import './interfaces/IUniswapV3Factory.sol'; + +import './UniswapV3PoolDeployer.sol'; +import './NoDelegateCall.sol'; + +import './UniswapV3Pool.sol'; + +/// @title Canonical Uniswap V3 factory +/// @notice Deploys Uniswap V3 pools and manages ownership and control over pool protocol fees +contract UniswapV3Factory is IUniswapV3Factory, UniswapV3PoolDeployer, NoDelegateCall { + /// @inheritdoc IUniswapV3Factory + address public override owner; + + /// @inheritdoc IUniswapV3Factory + mapping(uint24 => int24) public override feeAmountTickSpacing; + /// @inheritdoc IUniswapV3Factory + mapping(address => mapping(address => mapping(uint24 => address))) public override getPool; + + constructor() { + owner = msg.sender; + emit OwnerChanged(address(0), msg.sender); + + feeAmountTickSpacing[500] = 10; + emit FeeAmountEnabled(500, 10); + feeAmountTickSpacing[3000] = 60; + emit FeeAmountEnabled(3000, 60); + feeAmountTickSpacing[10000] = 200; + emit FeeAmountEnabled(10000, 200); + } + + /// @inheritdoc IUniswapV3Factory + function createPool( + address tokenA, + address tokenB, + uint24 fee + ) external override noDelegateCall returns (address pool) { + require(tokenA != tokenB); + (address token0, address token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA); + require(token0 != address(0)); + int24 tickSpacing = feeAmountTickSpacing[fee]; + require(tickSpacing != 0); + require(getPool[token0][token1][fee] == address(0)); + pool = deploy(address(this), token0, token1, fee, tickSpacing); + getPool[token0][token1][fee] = pool; + // populate mapping in the reverse direction, deliberate choice to avoid the cost of comparing addresses + getPool[token1][token0][fee] = pool; + emit PoolCreated(token0, token1, fee, tickSpacing, pool); + } + + /// @inheritdoc IUniswapV3Factory + function setOwner(address _owner) external override { + require(msg.sender == owner); + emit OwnerChanged(owner, _owner); + owner = _owner; + } + + /// @inheritdoc IUniswapV3Factory + function enableFeeAmount(uint24 fee, int24 tickSpacing) public override { + require(msg.sender == owner); + require(fee < 1000000); + // tick spacing is capped at 16384 to prevent the situation where tickSpacing is so large that + // TickBitmap#nextInitializedTickWithinOneWord overflows int24 container from a valid tick + // 16384 ticks represents a >5x price change with ticks of 1 bips + require(tickSpacing > 0 && tickSpacing < 16384); + require(feeAmountTickSpacing[fee] == 0); + + feeAmountTickSpacing[fee] = tickSpacing; + emit FeeAmountEnabled(fee, tickSpacing); + } +} From 5db6addd27cde957a89b77a6302733dcb3e30cdf Mon Sep 17 00:00:00 2001 From: alpha-guy Date: Sun, 9 May 2021 11:11:41 +0530 Subject: [PATCH 02/16] Add UniswapV3 Index Exchange Adapter contract * Modify compiler-version in .solhint.json --- .solhint.json | 2 +- .../interfaces/IIndexExchangeAdapter.sol | 2 +- contracts/lib/BytesLib.sol | 101 ++++++++++++++ .../UniswapV3IndexExchangeAdapter.sol | 131 ++++++++++++++++++ hardhat.config.ts | 16 ++- package.json | 1 + yarn.lock | 36 +++++ 7 files changed, 283 insertions(+), 6 deletions(-) create mode 100644 contracts/lib/BytesLib.sol create mode 100644 contracts/protocol/integration/index-exchange/UniswapV3IndexExchangeAdapter.sol diff --git a/.solhint.json b/.solhint.json index 997c4c612..ca5139919 100644 --- a/.solhint.json +++ b/.solhint.json @@ -2,6 +2,6 @@ "extends": "solhint:recommended", "rules": { "reason-string": ["warn", { "maxLength": 50 }], - "compiler-version": ["error", "0.6.10"] + "compiler-version": ["error", ">=0.6.10"] } } diff --git a/contracts/interfaces/IIndexExchangeAdapter.sol b/contracts/interfaces/IIndexExchangeAdapter.sol index c54130e4b..ff22e32f1 100644 --- a/contracts/interfaces/IIndexExchangeAdapter.sol +++ b/contracts/interfaces/IIndexExchangeAdapter.sol @@ -15,7 +15,7 @@ SPDX-License-Identifier: Apache License, Version 2.0 */ -pragma solidity 0.6.10; +pragma solidity >=0.6.10; interface IIndexExchangeAdapter { function getSpender() external view returns(address); diff --git a/contracts/lib/BytesLib.sol b/contracts/lib/BytesLib.sol new file mode 100644 index 000000000..5e92118e2 --- /dev/null +++ b/contracts/lib/BytesLib.sol @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * @title Solidity Bytes Arrays Utils + * @author Gonçalo Sá + * + * @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity. + * The library lets you concatenate, slice and type cast bytes arrays both in memory and storage. + */ +pragma solidity >=0.6.10; + +library BytesLib { + function slice( + bytes memory _bytes, + uint256 _start, + uint256 _length + ) internal pure returns (bytes memory) { + require(_length + 31 >= _length, "slice_overflow"); + require(_start + _length >= _start, "slice_overflow"); + require(_bytes.length >= _start + _length, "slice_outOfBounds"); + + bytes memory tempBytes; + + assembly { + switch iszero(_length) + case 0 { + // Get a location of some free memory and store it in tempBytes as + // Solidity does for memory variables. + tempBytes := mload(0x40) + + // The first word of the slice result is potentially a partial + // word read from the original array. To read it, we calculate + // the length of that partial word and start copying that many + // bytes into the array. The first word we copy will start with + // data we don't care about, but the last `lengthmod` bytes will + // land at the beginning of the contents of the new array. When + // we're done copying, we overwrite the full first word with + // the actual length of the slice. + let lengthmod := and(_length, 31) + + // The multiplication in the next line is necessary + // because when slicing multiples of 32 bytes (lengthmod == 0) + // the following copy loop was copying the origin's length + // and then ending prematurely not copying everything it should. + let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod))) + let end := add(mc, _length) + + for { + // The multiplication in the next line has the same exact purpose + // as the one above. + let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start) + } lt(mc, end) { + mc := add(mc, 0x20) + cc := add(cc, 0x20) + } { + mstore(mc, mload(cc)) + } + + mstore(tempBytes, _length) + + //update free-memory pointer + //allocating the array padded to 32 bytes like the compiler does now + mstore(0x40, and(add(mc, 31), not(31))) + } + //if we want a zero-length slice let's just return a zero-length array + default { + tempBytes := mload(0x40) + //zero out the 32 bytes slice we are about to return + //we need to do it because Solidity does not garbage collect + mstore(tempBytes, 0) + + mstore(0x40, add(tempBytes, 0x20)) + } + } + + return tempBytes; + } + + function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) { + require(_start + 20 >= _start, "toAddress_overflow"); + require(_bytes.length >= _start + 20, "toAddress_outOfBounds"); + address tempAddress; + + assembly { + tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000) + } + + return tempAddress; + } + + function toUint24(bytes memory _bytes, uint256 _start) internal pure returns (uint24) { + require(_start + 3 >= _start, "toUint24_overflow"); + require(_bytes.length >= _start + 3, "toUint24_outOfBounds"); + uint24 tempUint; + + assembly { + tempUint := mload(add(add(_bytes, 0x3), _start)) + } + + return tempUint; + } +} diff --git a/contracts/protocol/integration/index-exchange/UniswapV3IndexExchangeAdapter.sol b/contracts/protocol/integration/index-exchange/UniswapV3IndexExchangeAdapter.sol new file mode 100644 index 000000000..4d4a3cede --- /dev/null +++ b/contracts/protocol/integration/index-exchange/UniswapV3IndexExchangeAdapter.sol @@ -0,0 +1,131 @@ +/* + Copyright 2021 Set Labs Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + SPDX-License-Identifier: Apache License, Version 2.0 +*/ + +pragma solidity >=0.7.5; +pragma abicoder v2; + +import { ISwapRouter } from "@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol"; + +import { BytesLib } from "../../../lib/BytesLib.sol"; +import { IIndexExchangeAdapter } from "../../../interfaces/IIndexExchangeAdapter.sol"; + +/** + * @title UniswapV3IndexExchangeAdapter + * @author Set Protocol + * + * A Uniswap V3 exchange adapter that returns calldata for trading with GeneralIndexModule, allows encoding a trade with a fixed input quantity or + * a fixed output quantity. + */ +contract UniswapV3IndexExchangeAdapter is IIndexExchangeAdapter { + + using BytesLib for bytes; + + /* ============ State Variables ============ */ + + // Address of Uniswap V3 SwapRouter contract + address public immutable router; + // Uniswap router function string for swapping exact amount of input tokens for a minimum of output tokens + string internal constant SWAP_EXACT_INPUT = "exactInput((bytes,address,uint256,uint256,uint256))"; + // Uniswap router function string for swapping max amoutn of input tokens for an exact amount of output tokens + string internal constant SWAP_EXACT_OUTPUT = "exactOutput((bytes,address,uint256,uint256,uint256))"; + + /* ============ Constructor ============ */ + + /** + * Set state variables + * + * @param _router Address of Uniswap V3 SwapRouter contract + */ + constructor(address _router) public { + router = _router; + } + + /* ============ External Getter Functions ============ */ + + /** + * Return calldata for trading with Uniswap V3 SwapRouter. Trade paths are created from input and output tokens, _isSendTokenFixed indicates whether + * a fixed amount of token should be sold or an unfixed amount. + * + * Note: When _isSendTokenFixed is false, _sourceQuantity is defined as the max token quantity you are willing to trade, and + * _destinationQuantity is the exact quantity of token you are receiving. + * + * @param _sourceToken Address of source token to be sold + * @param _destinationToken Address of destination token to buy + * @param _destinationAddress Address that assets should be transferred to + * @param _isSendTokenFixed Boolean indicating if the send quantity is fixed, used to determine correct trade interface + * @param _sourceQuantity Fixed/Max amount of source token to sell + * @param _destinationQuantity Min/Fixed amount of destination token to buy + * @param _data Arbitrary bytes containing fees value, expressed in hundredths of a bip, + * used to determine the pool to trade among similar asset pools on Uniswap V3 + * + * @return address Target contract address + * @return uint256 Call value + * @return bytes Trade calldata + */ + function getTradeCalldata( + address _sourceToken, + address _destinationToken, + address _destinationAddress, + bool _isSendTokenFixed, + uint256 _sourceQuantity, + uint256 _destinationQuantity, + bytes memory _data + ) + external + view + override + returns (address, uint256, bytes memory) + { + uint24 fees = _data.toUint24(0); + bytes memory path = abi.encodePacked(_sourceToken, fees, _destinationToken); + + bytes memory callData = _isSendTokenFixed + ? abi.encodeWithSignature( + SWAP_EXACT_INPUT, + ISwapRouter.ExactInputParams(path, _destinationAddress, block.timestamp, _sourceQuantity, _destinationQuantity) + ) : abi.encodeWithSignature( + SWAP_EXACT_OUTPUT, + ISwapRouter.ExactOutputParams(path, _destinationAddress, block.timestamp, _destinationQuantity, _sourceQuantity) + ); + + return (router, 0, callData); + } + + /** + * Returns the address to approve source tokens to for trading. This is the Uniswap router address + * + * @return address Address of the contract to approve tokens to + */ + function getSpender() external view override returns (address) { + return router; + } + + /** + * Helper that returns the encoded data of trade path. + * + * @param _sourceToken Address of source token to be sold + * @param _fees Fees of the Uniswap V3 pool to be used, expressed in hundredths of a bip + * @param _destinationToken Address of destination token to buy + * + * @return bytes Encoded data used for trading on Uniswap + */ + function getUniswapEncodedPath(address _sourceToken, uint24 _fees, address _destinationToken) external pure returns (bytes memory) { + bytes memory path = abi.encodePacked(_sourceToken, _fees, _destinationToken); + return path; + } +} \ No newline at end of file diff --git a/hardhat.config.ts b/hardhat.config.ts index d9891bebc..e3adfe53e 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -11,10 +11,18 @@ import "./tasks"; const config: HardhatUserConfig = { solidity: { - version: "0.6.10", - settings: { - optimizer: { enabled: true, runs: 200 }, - }, + compilers: [ + { + version: "0.6.10", + settings: { + optimizer: { enabled: true, runs: 200 }, + }, + }, + { + version: "0.7.5", + } + ] + }, namedAccounts: { deployer: 0, diff --git a/package.json b/package.json index 98ef675a6..ed6ab2f83 100644 --- a/package.json +++ b/package.json @@ -85,6 +85,7 @@ "web3": "^1.2.9" }, "dependencies": { + "@uniswap/v3-periphery": "^1.0.0", "fs-extra": "^5.0.0", "module-alias": "^2.2.2", "replace-in-file": "^6.1.0", diff --git a/yarn.lock b/yarn.lock index 0502f6e19..03799a48a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -559,6 +559,11 @@ "@types/sinon-chai" "^3.2.3" "@types/web3" "1.0.19" +"@openzeppelin/contracts@3.4.1-solc-0.7-2": + version "3.4.1-solc-0.7-2" + resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-3.4.1-solc-0.7-2.tgz#371c67ebffe50f551c3146a9eec5fe6ffe862e92" + integrity sha512-tAG9LWg8+M2CMu7hIsqHPaTyG4uDzjr6mhvH96LvOpLZZj6tgzTluBt+LsCf1/QaYrlis6pITvpIaIhE+iZB+Q== + "@openzeppelin/contracts@^3.1.0": version "3.3.0" resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-3.3.0.tgz#ffdb693c5c349fc33bba420248dd3ac0a2d7c408" @@ -901,6 +906,32 @@ "@types/bn.js" "*" "@types/underscore" "*" +"@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.0" + resolved "https://registry.yarnpkg.com/@uniswap/v3-core/-/v3-core-1.0.0.tgz#6c24adacc4c25dceee0ba3ca142b35adbd7e359d" + integrity sha512-kSC4djMGKMHj7sLMYVnn61k9nu+lHjMIxgg9CDQT+s2QYLoA56GbSK9Oxr+qJXzzygbkrmuY6cwgP6cW2JXPFA== + +"@uniswap/v3-periphery@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@uniswap/v3-periphery/-/v3-periphery-1.0.0.tgz#8e789dcd70bdd06e01e21dd75372dc76ab38ea47" + integrity sha512-kRqUrjnyh+X1wJdSENPDFr9sjRVebv2KyLtfqDOPij0dXJ69GspFU2qrZXjouc6LYdkWG7x3fagiTlw0eGniYQ== + dependencies: + "@openzeppelin/contracts" "3.4.1-solc-0.7-2" + "@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" @@ -1836,6 +1867,11 @@ base64-js@^1.3.1: resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== +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" From 720024886e19920c805a9a916cd0a6e68c754f34 Mon Sep 17 00:00:00 2001 From: alpha-guy Date: Sun, 9 May 2021 11:14:00 +0530 Subject: [PATCH 03/16] Add tests --- .../uniswapV3IndexExchangeAdapter.spec.ts | 191 ++++++++++++++++++ utils/contracts/index.ts | 1 + utils/contracts/uniswap.ts | 6 +- utils/deploys/deployAdapters.ts | 6 + utils/deploys/deployExternal.ts | 17 ++ 5 files changed, 220 insertions(+), 1 deletion(-) create mode 100644 test/protocol/integration/index-exchange/uniswapV3IndexExchangeAdapter.spec.ts diff --git a/test/protocol/integration/index-exchange/uniswapV3IndexExchangeAdapter.spec.ts b/test/protocol/integration/index-exchange/uniswapV3IndexExchangeAdapter.spec.ts new file mode 100644 index 000000000..9a850970a --- /dev/null +++ b/test/protocol/integration/index-exchange/uniswapV3IndexExchangeAdapter.spec.ts @@ -0,0 +1,191 @@ +import "module-alias/register"; + +import { utils } from "ethers"; +import { BigNumber } from "@ethersproject/bignumber"; +import { Address, Bytes } from "@utils/types"; +import { Account } from "@utils/test/types"; +import { + ZERO, +} from "@utils/constants"; +import { SwapRouter, UniswapV3Factory } from "@utils/contracts/uniswap"; +import { UniswapV3IndexExchangeAdapter } from "@utils/contracts"; +import DeployHelper from "@utils/deploys"; +import { SystemFixture } from "@utils/fixtures"; +import { + ether, +} from "@utils/index"; +import { + addSnapshotBeforeRestoreAfterEach, + getAccounts, + getSystemFixture, + getWaffleExpect, + getLastBlockTimestamp +} from "@utils/test/index"; + +const expect = getWaffleExpect(); + +describe("UniswapV3IndexExchangeAdapter", () => { + let owner: Account; + let mockSetToken: Account; + let deployer: DeployHelper; + let setup: SystemFixture; + + let swapRouter: SwapRouter; + let factory: UniswapV3Factory; + let uniswapV3ExchangeAdapter: UniswapV3IndexExchangeAdapter; + + before(async () => { + [ + owner, + mockSetToken, + ] = await getAccounts(); + + deployer = new DeployHelper(owner.wallet); + + setup = getSystemFixture(owner.address); + await setup.initialize(); + + factory = await deployer.external.deployUniswapV3Factory(); + swapRouter = await deployer.external.deploySwapRouter(factory.address, setup.weth.address); + + uniswapV3ExchangeAdapter = await deployer.adapters.deployUniswapV3IndexExchangeAdapter(swapRouter.address); + }); + + addSnapshotBeforeRestoreAfterEach(); + + describe("constructor", async () => { + let subjectRouterAddress: Address; + + beforeEach(async () => { + subjectRouterAddress = swapRouter.address; + }); + + async function subject(): Promise { + return await deployer.adapters.deployUniswapV3IndexExchangeAdapter(subjectRouterAddress); + } + + it("should have the correct router address", async () => { + const deployedUniswapV3IndexExchangeAdapter = await subject(); + + const routerAddress = await deployedUniswapV3IndexExchangeAdapter.router(); + const expectedRouterAddress = subjectRouterAddress; + + expect(routerAddress).to.eq(expectedRouterAddress); + }); + }); + + describe("getSpender", async () => { + async function subject(): Promise { + return await uniswapV3ExchangeAdapter.getSpender(); + } + + it("should return the correct spender address", async () => { + const spender = await subject(); + const expectedSpender = swapRouter.address; + + expect(spender).to.eq(expectedSpender); + }); + }); + + describe("getTradeCalldata", async () => { + let sourceToken: Address; + let destinationToken: Address; + let sourceQuantity: BigNumber; + let destinationQuantity: BigNumber; + let poolFeesPercentage: BigNumber; + + let subjectMockSetToken: Address; + let subjectSourceToken: Address; + let subjectDestinationToken: Address; + let subjectIsSendTokenFixed: boolean; + let subjectSourceQuantity: BigNumber; + let subjectDestinationQuantity: BigNumber; + let subjectData: Bytes; + + function constructFeesData(_poolFeesPercentage: BigNumber): Bytes { + return utils.hexZeroPad(utils.hexlify(_poolFeesPercentage), 3); + } + + beforeEach(async () => { + sourceToken = setup.wbtc.address; // WBTC Address + sourceQuantity = BigNumber.from(100000000); // Trade 1 WBTC + destinationToken = setup.dai.address; // DAI Address + destinationQuantity = ether(50000); // Receive at least 50k DAI + poolFeesPercentage = BigNumber.from(3000); // 0.3% fee + + subjectSourceToken = sourceToken; + subjectDestinationToken = destinationToken; + subjectMockSetToken = mockSetToken.address; + subjectIsSendTokenFixed = true; + subjectSourceQuantity = sourceQuantity; + subjectDestinationQuantity = destinationQuantity; + subjectData = constructFeesData(poolFeesPercentage); + }); + + async function subject(): Promise { + return await uniswapV3ExchangeAdapter.getTradeCalldata( + subjectSourceToken, + subjectDestinationToken, + subjectMockSetToken, + subjectIsSendTokenFixed, + subjectSourceQuantity, + subjectDestinationQuantity, + subjectData, + ); + } + + describe("when boolean to swap exact tokens for tokens is true", async () => { + it("should return the correct trade calldata", async () => { + const [tragetAddress, ethValue, callData] = await subject(); + + const callTimestamp = await getLastBlockTimestamp(); + const path: Bytes = await uniswapV3ExchangeAdapter.getUniswapEncodedPath( + sourceToken, + poolFeesPercentage, + destinationToken + ); + + const expectedCallData = swapRouter.interface.encodeFunctionData("exactInput", [{ + path: path, + recipient: subjectMockSetToken, + deadline: callTimestamp, + amountIn: sourceQuantity, + amountOutMinimum: destinationQuantity, + }]); + + expect(tragetAddress).to.eq(swapRouter.address); + expect(ethValue).to.eq(ZERO); + expect(callData).to.eq(expectedCallData); + }); + }); + + describe("when boolean to swap exact tokens for tokens is false", async () => { + beforeEach(async () => { + subjectIsSendTokenFixed = false; + }); + + it("should return the correct trade calldata", async () => { + const [tragetAddress, ethValue, callData] = await subject(); + + const callTimestamp = await getLastBlockTimestamp(); + const path: Bytes = await uniswapV3ExchangeAdapter.getUniswapEncodedPath( + sourceToken, + poolFeesPercentage, + destinationToken + ); + + const expectedCallData = swapRouter.interface.encodeFunctionData("exactOutput", [{ + path: path, + recipient: subjectMockSetToken, + deadline: callTimestamp, + amountOut: destinationQuantity, + amountInMaximum: sourceQuantity, + }]); + + expect(tragetAddress).to.eq(swapRouter.address); + expect(ethValue).to.eq(ZERO); + expect(callData).to.eq(expectedCallData); + }); + }); + }); +}); \ No newline at end of file diff --git a/utils/contracts/index.ts b/utils/contracts/index.ts index c0be420fe..d2989a116 100644 --- a/utils/contracts/index.ts +++ b/utils/contracts/index.ts @@ -83,6 +83,7 @@ export { UniswapPairPriceAdapter } from "../../typechain/UniswapPairPriceAdapter export { UniswapV2ExchangeAdapter } from "../../typechain/UniswapV2ExchangeAdapter"; export { UniswapV2ExchangeAdapterV2 } from "../../typechain/UniswapV2ExchangeAdapterV2"; export { UniswapV2IndexExchangeAdapter } from "../../typechain/UniswapV2IndexExchangeAdapter"; +export { UniswapV3IndexExchangeAdapter } from "../../typechain/UniswapV3IndexExchangeAdapter"; export { UniswapV2TransferFeeExchangeAdapter } from "../../typechain/UniswapV2TransferFeeExchangeAdapter"; export { UniswapV2Factory } from "../../typechain/UniswapV2Factory"; export { UniswapV2Pair } from "../../typechain/UniswapV2Pair"; diff --git a/utils/contracts/uniswap.ts b/utils/contracts/uniswap.ts index b2d879e0a..6f0db3466 100644 --- a/utils/contracts/uniswap.ts +++ b/utils/contracts/uniswap.ts @@ -5,4 +5,8 @@ export { UniswapGovernorAlpha } from "../../typechain/UniswapGovernorAlpha"; export { UniswapTimelock } from "../../typechain/UniswapTimelock"; export { UniswapV2Factory } from "../../typechain/UniswapV2Factory"; export { UniswapV2Pair } from "../../typechain/UniswapV2Pair"; -export { UniswapV2Router02 } from "../../typechain/UniswapV2Router02"; \ No newline at end of file +export { UniswapV2Router02 } from "../../typechain/UniswapV2Router02"; + +// External Uniswap V3 contracts +export { SwapRouter } from "../../typechain/SwapRouter"; +export { UniswapV3Factory } from "../../typechain/UniswapV3Factory"; \ No newline at end of file diff --git a/utils/deploys/deployAdapters.ts b/utils/deploys/deployAdapters.ts index 18737a82b..1f095d03e 100644 --- a/utils/deploys/deployAdapters.ts +++ b/utils/deploys/deployAdapters.ts @@ -17,6 +17,7 @@ import { UniswapV2ExchangeAdapter, UniswapV2ExchangeAdapterV2, UniswapV2IndexExchangeAdapter, + UniswapV3IndexExchangeAdapter, UniswapV2TransferFeeExchangeAdapter, ZeroExApiAdapter, SnapshotGovernanceAdapter, @@ -44,6 +45,7 @@ import { UniswapV2ExchangeAdapter__factory } from "../../typechain/factories/Uni import { UniswapV2TransferFeeExchangeAdapter__factory } from "../../typechain/factories/UniswapV2TransferFeeExchangeAdapter__factory"; import { UniswapV2ExchangeAdapterV2__factory } from "../../typechain/factories/UniswapV2ExchangeAdapterV2__factory"; import { UniswapV2IndexExchangeAdapter__factory } from "../../typechain/factories/UniswapV2IndexExchangeAdapter__factory"; +import { UniswapV3IndexExchangeAdapter__factory } from "../../typechain/factories/UniswapV3IndexExchangeAdapter__factory"; import { SnapshotGovernanceAdapter__factory } from "../../typechain/factories/SnapshotGovernanceAdapter__factory"; import { SynthetixExchangeAdapter__factory } from "../../typechain/factories/SynthetixExchangeAdapter__factory"; import { CompoundBravoGovernanceAdapter__factory } from "../../typechain/factories/CompoundBravoGovernanceAdapter__factory"; @@ -157,6 +159,10 @@ export default class DeployAdapters { return await new UniswapPairPriceAdapter__factory(this._deployerSigner).attach(uniswapAdapterAddress); } + public async deployUniswapV3IndexExchangeAdapter(router: Address): Promise { + return await new UniswapV3IndexExchangeAdapter__factory(this._deployerSigner).deploy(router); + } + public async deployZeroExApiAdapter(zeroExAddress: Address): Promise { return await new ZeroExApiAdapter__factory(this._deployerSigner).deploy(zeroExAddress); } diff --git a/utils/deploys/deployExternal.ts b/utils/deploys/deployExternal.ts index 523090b7e..d85b9a916 100644 --- a/utils/deploys/deployExternal.ts +++ b/utils/deploys/deployExternal.ts @@ -113,6 +113,14 @@ import { UniswapV2Factory__factory } from "../../typechain/factories/UniswapV2Fa import { UniswapV2Pair__factory } from "../../typechain/factories/UniswapV2Pair__factory"; import { UniswapV2Router02__factory } from "../../typechain/factories/UniswapV2Router02__factory"; +import { + SwapRouter, + UniswapV3Factory +} from "../contracts/uniswap"; + +import { SwapRouter__factory } from "../../typechain/factories/SwapRouter__factory"; +import { UniswapV3Factory__factory } from "../../typechain/factories/UniswapV3Factory__factory"; + import { BFactory, BRegistry, @@ -530,6 +538,15 @@ export default class DeployExternalContracts { return await new DelegateRegistry__factory(this._deployerSigner).deploy(); } + // UNISWAP V3 + public async deployUniswapV3Factory(): Promise { + return await new UniswapV3Factory__factory(this._deployerSigner).deploy(); + } + + public async deploySwapRouter(_factory: Address, _weth: Address): Promise { + return await new SwapRouter__factory(this._deployerSigner).deploy(_factory, _weth); + } + // YEARN public async deployVault(): Promise { return await new Vault__factory(this._deployerSigner).deploy(); From 3896fd3461b07c0791e5d1ef9e3579fb8be7b1c3 Mon Sep 17 00:00:00 2001 From: alpha-guy Date: Sun, 9 May 2021 11:46:53 +0530 Subject: [PATCH 04/16] Fix coverage --- contracts/lib/BytesLib.sol | 101 ------------------ .../UniswapV3IndexExchangeAdapter.sol | 7 +- .../uniswapV3IndexExchangeAdapter.spec.ts | 35 +++++- 3 files changed, 36 insertions(+), 107 deletions(-) delete mode 100644 contracts/lib/BytesLib.sol diff --git a/contracts/lib/BytesLib.sol b/contracts/lib/BytesLib.sol deleted file mode 100644 index 5e92118e2..000000000 --- a/contracts/lib/BytesLib.sol +++ /dev/null @@ -1,101 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * @title Solidity Bytes Arrays Utils - * @author Gonçalo Sá - * - * @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity. - * The library lets you concatenate, slice and type cast bytes arrays both in memory and storage. - */ -pragma solidity >=0.6.10; - -library BytesLib { - function slice( - bytes memory _bytes, - uint256 _start, - uint256 _length - ) internal pure returns (bytes memory) { - require(_length + 31 >= _length, "slice_overflow"); - require(_start + _length >= _start, "slice_overflow"); - require(_bytes.length >= _start + _length, "slice_outOfBounds"); - - bytes memory tempBytes; - - assembly { - switch iszero(_length) - case 0 { - // Get a location of some free memory and store it in tempBytes as - // Solidity does for memory variables. - tempBytes := mload(0x40) - - // The first word of the slice result is potentially a partial - // word read from the original array. To read it, we calculate - // the length of that partial word and start copying that many - // bytes into the array. The first word we copy will start with - // data we don't care about, but the last `lengthmod` bytes will - // land at the beginning of the contents of the new array. When - // we're done copying, we overwrite the full first word with - // the actual length of the slice. - let lengthmod := and(_length, 31) - - // The multiplication in the next line is necessary - // because when slicing multiples of 32 bytes (lengthmod == 0) - // the following copy loop was copying the origin's length - // and then ending prematurely not copying everything it should. - let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod))) - let end := add(mc, _length) - - for { - // The multiplication in the next line has the same exact purpose - // as the one above. - let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start) - } lt(mc, end) { - mc := add(mc, 0x20) - cc := add(cc, 0x20) - } { - mstore(mc, mload(cc)) - } - - mstore(tempBytes, _length) - - //update free-memory pointer - //allocating the array padded to 32 bytes like the compiler does now - mstore(0x40, and(add(mc, 31), not(31))) - } - //if we want a zero-length slice let's just return a zero-length array - default { - tempBytes := mload(0x40) - //zero out the 32 bytes slice we are about to return - //we need to do it because Solidity does not garbage collect - mstore(tempBytes, 0) - - mstore(0x40, add(tempBytes, 0x20)) - } - } - - return tempBytes; - } - - function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) { - require(_start + 20 >= _start, "toAddress_overflow"); - require(_bytes.length >= _start + 20, "toAddress_outOfBounds"); - address tempAddress; - - assembly { - tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000) - } - - return tempAddress; - } - - function toUint24(bytes memory _bytes, uint256 _start) internal pure returns (uint24) { - require(_start + 3 >= _start, "toUint24_overflow"); - require(_bytes.length >= _start + 3, "toUint24_outOfBounds"); - uint24 tempUint; - - assembly { - tempUint := mload(add(add(_bytes, 0x3), _start)) - } - - return tempUint; - } -} diff --git a/contracts/protocol/integration/index-exchange/UniswapV3IndexExchangeAdapter.sol b/contracts/protocol/integration/index-exchange/UniswapV3IndexExchangeAdapter.sol index 4d4a3cede..601082fe1 100644 --- a/contracts/protocol/integration/index-exchange/UniswapV3IndexExchangeAdapter.sol +++ b/contracts/protocol/integration/index-exchange/UniswapV3IndexExchangeAdapter.sol @@ -20,8 +20,8 @@ pragma solidity >=0.7.5; pragma abicoder v2; import { ISwapRouter } from "@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol"; +import { BytesLib } from "@uniswap/v3-periphery/contracts/libraries/BytesLib.sol"; -import { BytesLib } from "../../../lib/BytesLib.sol"; import { IIndexExchangeAdapter } from "../../../interfaces/IIndexExchangeAdapter.sol"; /** @@ -51,7 +51,7 @@ contract UniswapV3IndexExchangeAdapter is IIndexExchangeAdapter { * * @param _router Address of Uniswap V3 SwapRouter contract */ - constructor(address _router) public { + constructor(address _router) { router = _router; } @@ -125,7 +125,6 @@ contract UniswapV3IndexExchangeAdapter is IIndexExchangeAdapter { * @return bytes Encoded data used for trading on Uniswap */ function getUniswapEncodedPath(address _sourceToken, uint24 _fees, address _destinationToken) external pure returns (bytes memory) { - bytes memory path = abi.encodePacked(_sourceToken, _fees, _destinationToken); - return path; + return abi.encodePacked(_sourceToken, _fees, _destinationToken); } } \ No newline at end of file diff --git a/test/protocol/integration/index-exchange/uniswapV3IndexExchangeAdapter.spec.ts b/test/protocol/integration/index-exchange/uniswapV3IndexExchangeAdapter.spec.ts index 9a850970a..b3207be21 100644 --- a/test/protocol/integration/index-exchange/uniswapV3IndexExchangeAdapter.spec.ts +++ b/test/protocol/integration/index-exchange/uniswapV3IndexExchangeAdapter.spec.ts @@ -1,6 +1,6 @@ import "module-alias/register"; -import { utils } from "ethers"; +import { hexlify, hexZeroPad } from "ethers/lib/utils"; import { BigNumber } from "@ethersproject/bignumber"; import { Address, Bytes } from "@utils/types"; import { Account } from "@utils/test/types"; @@ -87,6 +87,37 @@ describe("UniswapV3IndexExchangeAdapter", () => { }); }); + + // describe("getUniswapEncodedPath", async () => { + // let subjectFees: BigNumber; + // let subjectSourceToken: Address; + // let subjectDestinationToken: Address; + + // beforeEach(async () => { + // subjectFees = BigNumber.from(10000); // 1% pool fees + // subjectSourceToken = setup.wbtc.address; + // subjectDestinationToken = setup.dai.address; + // }); + + // async function subject(): Promise { + // return await uniswapV3ExchangeAdapter.getUniswapEncodedPath( + // subjectSourceToken, + // subjectFees, + // subjectDestinationToken + // ); + // } + + // it("should return the correct data", async () => { + // const uniswapData = await subject(); + // const expectedData = defaultAbiCoder.encode( + // ["address", "uint24", "address"], + // [subjectSourceToken, subjectFees, subjectDestinationToken] + // ); + + // expect(uniswapData).to.eq(expectedData); + // }); + // }); + describe("getTradeCalldata", async () => { let sourceToken: Address; let destinationToken: Address; @@ -103,7 +134,7 @@ describe("UniswapV3IndexExchangeAdapter", () => { let subjectData: Bytes; function constructFeesData(_poolFeesPercentage: BigNumber): Bytes { - return utils.hexZeroPad(utils.hexlify(_poolFeesPercentage), 3); + return hexZeroPad(hexlify(_poolFeesPercentage), 3); } beforeEach(async () => { From 6d91eaa4983d4deebd564cbbc68f7121f5e6b381 Mon Sep 17 00:00:00 2001 From: alpha-guy Date: Wed, 12 May 2021 18:59:55 +0530 Subject: [PATCH 05/16] Improve javadocs and add getEncodedTradePath() test --- .../UniswapV3IndexExchangeAdapter.sol | 21 ++++-- .../uniswapV3IndexExchangeAdapter.spec.ts | 71 ++++++++++--------- 2 files changed, 50 insertions(+), 42 deletions(-) diff --git a/contracts/protocol/integration/index-exchange/UniswapV3IndexExchangeAdapter.sol b/contracts/protocol/integration/index-exchange/UniswapV3IndexExchangeAdapter.sol index 601082fe1..edeba0424 100644 --- a/contracts/protocol/integration/index-exchange/UniswapV3IndexExchangeAdapter.sol +++ b/contracts/protocol/integration/index-exchange/UniswapV3IndexExchangeAdapter.sol @@ -58,11 +58,18 @@ contract UniswapV3IndexExchangeAdapter is IIndexExchangeAdapter { /* ============ External Getter Functions ============ */ /** - * Return calldata for trading with Uniswap V3 SwapRouter. Trade paths are created from input and output tokens, _isSendTokenFixed indicates whether - * a fixed amount of token should be sold or an unfixed amount. + * Return calldata for trading with Uniswap V3 SwapRouter. Trade paths are created from _sourceToken, + * _destinationToken and pool fees (which is encoded in _data). * - * Note: When _isSendTokenFixed is false, _sourceQuantity is defined as the max token quantity you are willing to trade, and - * _destinationQuantity is the exact quantity of token you are receiving. + * --------------------------------------------------------------------------------------------------------------- + * _isSendTokenFixed | Parameter | Amount | + * --------------------------------------------------------------------------------------------------------------- + * True | _sourceQuantity | Fixed amount of _sourceToken to trade | + * | _destinationQuantity | Minimum amount of _destinationToken willing to receive | + * --------------------------------------------------------------------------------------------------------------- + * False | _sourceQuantity | Maximum amount of _sourceToken to trade | + * | _destinationQuantity | Fixed amount of _destinationToken want to receive | + * --------------------------------------------------------------------------------------------------------------- * * @param _sourceToken Address of source token to be sold * @param _destinationToken Address of destination token to buy @@ -107,7 +114,7 @@ contract UniswapV3IndexExchangeAdapter is IIndexExchangeAdapter { } /** - * Returns the address to approve source tokens to for trading. This is the Uniswap router address + * Returns the address to approve source tokens to for trading. This is the Uniswap V3 router address. * * @return address Address of the contract to approve tokens to */ @@ -116,7 +123,7 @@ contract UniswapV3IndexExchangeAdapter is IIndexExchangeAdapter { } /** - * Helper that returns the encoded data of trade path. + * Helper that returns the encoded data of Uniswap V3 trade path. * * @param _sourceToken Address of source token to be sold * @param _fees Fees of the Uniswap V3 pool to be used, expressed in hundredths of a bip @@ -124,7 +131,7 @@ contract UniswapV3IndexExchangeAdapter is IIndexExchangeAdapter { * * @return bytes Encoded data used for trading on Uniswap */ - function getUniswapEncodedPath(address _sourceToken, uint24 _fees, address _destinationToken) external pure returns (bytes memory) { + function getEncodedTradePath(address _sourceToken, uint24 _fees, address _destinationToken) external pure returns (bytes memory) { return abi.encodePacked(_sourceToken, _fees, _destinationToken); } } \ No newline at end of file diff --git a/test/protocol/integration/index-exchange/uniswapV3IndexExchangeAdapter.spec.ts b/test/protocol/integration/index-exchange/uniswapV3IndexExchangeAdapter.spec.ts index b3207be21..7f91e2321 100644 --- a/test/protocol/integration/index-exchange/uniswapV3IndexExchangeAdapter.spec.ts +++ b/test/protocol/integration/index-exchange/uniswapV3IndexExchangeAdapter.spec.ts @@ -34,6 +34,10 @@ describe("UniswapV3IndexExchangeAdapter", () => { let factory: UniswapV3Factory; let uniswapV3ExchangeAdapter: UniswapV3IndexExchangeAdapter; + function constructFeesData(_poolFeesPercentage: BigNumber): Bytes { + return hexZeroPad(hexlify(_poolFeesPercentage), 3); + } + before(async () => { [ owner, @@ -88,35 +92,36 @@ describe("UniswapV3IndexExchangeAdapter", () => { }); - // describe("getUniswapEncodedPath", async () => { - // let subjectFees: BigNumber; - // let subjectSourceToken: Address; - // let subjectDestinationToken: Address; - - // beforeEach(async () => { - // subjectFees = BigNumber.from(10000); // 1% pool fees - // subjectSourceToken = setup.wbtc.address; - // subjectDestinationToken = setup.dai.address; - // }); - - // async function subject(): Promise { - // return await uniswapV3ExchangeAdapter.getUniswapEncodedPath( - // subjectSourceToken, - // subjectFees, - // subjectDestinationToken - // ); - // } - - // it("should return the correct data", async () => { - // const uniswapData = await subject(); - // const expectedData = defaultAbiCoder.encode( - // ["address", "uint24", "address"], - // [subjectSourceToken, subjectFees, subjectDestinationToken] - // ); - - // expect(uniswapData).to.eq(expectedData); - // }); - // }); + describe("getEncodedTradePath", async () => { + let subjectFees: BigNumber; + let subjectSourceToken: Address; + let subjectDestinationToken: Address; + + beforeEach(async () => { + subjectFees = BigNumber.from(10000); // 1% pool fees + subjectSourceToken = setup.wbtc.address; + subjectDestinationToken = setup.dai.address; + }); + + async function subject(): Promise { + return await uniswapV3ExchangeAdapter.getEncodedTradePath( + subjectSourceToken, + subjectFees, + subjectDestinationToken + ); + } + + it("should return the correct data", async () => { + const uniswapData = await subject(); + + const encodePackedData = subjectSourceToken + + constructFeesData(subjectFees).replace("0x", "") + + subjectDestinationToken.replace("0x", ""); + const expectedData = encodePackedData.toLowerCase(); + + expect(uniswapData).to.eq(expectedData); + }); + }); describe("getTradeCalldata", async () => { let sourceToken: Address; @@ -133,10 +138,6 @@ describe("UniswapV3IndexExchangeAdapter", () => { let subjectDestinationQuantity: BigNumber; let subjectData: Bytes; - function constructFeesData(_poolFeesPercentage: BigNumber): Bytes { - return hexZeroPad(hexlify(_poolFeesPercentage), 3); - } - beforeEach(async () => { sourceToken = setup.wbtc.address; // WBTC Address sourceQuantity = BigNumber.from(100000000); // Trade 1 WBTC @@ -170,7 +171,7 @@ describe("UniswapV3IndexExchangeAdapter", () => { const [tragetAddress, ethValue, callData] = await subject(); const callTimestamp = await getLastBlockTimestamp(); - const path: Bytes = await uniswapV3ExchangeAdapter.getUniswapEncodedPath( + const path: Bytes = await uniswapV3ExchangeAdapter.getEncodedTradePath( sourceToken, poolFeesPercentage, destinationToken @@ -199,7 +200,7 @@ describe("UniswapV3IndexExchangeAdapter", () => { const [tragetAddress, ethValue, callData] = await subject(); const callTimestamp = await getLastBlockTimestamp(); - const path: Bytes = await uniswapV3ExchangeAdapter.getUniswapEncodedPath( + const path: Bytes = await uniswapV3ExchangeAdapter.getEncodedTradePath( sourceToken, poolFeesPercentage, destinationToken From a72cbf1990d204660ec9b6c6073b8e0b2d0890fb Mon Sep 17 00:00:00 2001 From: alpha-guy Date: Wed, 12 May 2021 19:23:23 +0530 Subject: [PATCH 06/16] Use soldityPack in getEncodedTradePath test --- .../uniswapV3IndexExchangeAdapter.spec.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/test/protocol/integration/index-exchange/uniswapV3IndexExchangeAdapter.spec.ts b/test/protocol/integration/index-exchange/uniswapV3IndexExchangeAdapter.spec.ts index 7f91e2321..7491adbfe 100644 --- a/test/protocol/integration/index-exchange/uniswapV3IndexExchangeAdapter.spec.ts +++ b/test/protocol/integration/index-exchange/uniswapV3IndexExchangeAdapter.spec.ts @@ -1,6 +1,6 @@ import "module-alias/register"; -import { hexlify, hexZeroPad } from "ethers/lib/utils"; +import { hexlify, solidityPack, hexZeroPad } from "ethers/lib/utils"; import { BigNumber } from "@ethersproject/bignumber"; import { Address, Bytes } from "@utils/types"; import { Account } from "@utils/test/types"; @@ -112,14 +112,14 @@ describe("UniswapV3IndexExchangeAdapter", () => { } it("should return the correct data", async () => { - const uniswapData = await subject(); + const tradePathData = await subject(); - const encodePackedData = subjectSourceToken - + constructFeesData(subjectFees).replace("0x", "") - + subjectDestinationToken.replace("0x", ""); - const expectedData = encodePackedData.toLowerCase(); + const expectedTradePathData = solidityPack( + ["address", "uint24", "address"], + [subjectSourceToken, subjectFees, subjectDestinationToken] + ); - expect(uniswapData).to.eq(expectedData); + expect(tradePathData).to.eq(expectedTradePathData); }); }); From 28ce969fd90c093dbc0edae73047bcb22f5cbdd1 Mon Sep 17 00:00:00 2001 From: alpha-guy Date: Fri, 4 Jun 2021 20:22:46 +0530 Subject: [PATCH 07/16] Change compiler version to 0.6.10 * Add suggested changes * Remove getTradeEncodedPath function * Remove @uniswap/v3-periphery as dependency * Add @uniswap/v3-core as dependency --- .solhint.json | 2 +- contracts/interfaces/external/ISwapRouter.sol | 73 +++++++++++++ contracts/lib/BytesLib.sol | 101 ++++++++++++++++++ .../UniswapV3IndexExchangeAdapter.sol | 28 ++--- hardhat.config.ts | 16 +-- package.json | 2 +- .../uniswapV3IndexExchangeAdapter.spec.ts | 47 +------- yarn.lock | 33 +----- 8 files changed, 195 insertions(+), 107 deletions(-) create mode 100644 contracts/interfaces/external/ISwapRouter.sol create mode 100644 contracts/lib/BytesLib.sol diff --git a/.solhint.json b/.solhint.json index ca5139919..997c4c612 100644 --- a/.solhint.json +++ b/.solhint.json @@ -2,6 +2,6 @@ "extends": "solhint:recommended", "rules": { "reason-string": ["warn", { "maxLength": 50 }], - "compiler-version": ["error", ">=0.6.10"] + "compiler-version": ["error", "0.6.10"] } } diff --git a/contracts/interfaces/external/ISwapRouter.sol b/contracts/interfaces/external/ISwapRouter.sol new file mode 100644 index 000000000..c9ff10aec --- /dev/null +++ b/contracts/interfaces/external/ISwapRouter.sol @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/* +pragma solidity >=0.7.5; +pragma abicoder v2; +*/ + +pragma solidity 0.6.10; +pragma experimental "ABIEncoderV2"; + +import "@uniswap/v3-core/contracts/interfaces/callback/IUniswapV3SwapCallback.sol"; + +/// @title Router token swapping functionality +/// @notice Functions for swapping tokens via Uniswap V3 +interface ISwapRouter is IUniswapV3SwapCallback { + struct ExactInputSingleParams { + address tokenIn; + address tokenOut; + uint24 fee; + address recipient; + uint256 deadline; + uint256 amountIn; + uint256 amountOutMinimum; + uint160 sqrtPriceLimitX96; + } + + /// @notice Swaps `amountIn` of one token for as much as possible of another token + /// @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 deadline; + uint256 amountIn; + uint256 amountOutMinimum; + } + + /// @notice Swaps `amountIn` of one token for as much as possible of another along the specified path + /// @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 deadline; + uint256 amountOut; + uint256 amountInMaximum; + uint160 sqrtPriceLimitX96; + } + + /// @notice Swaps as little as possible of one token for `amountOut` of another token + /// @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 deadline; + uint256 amountOut; + uint256 amountInMaximum; + } + + /// @notice Swaps as little as possible of one token for `amountOut` of another along the specified path (reversed) + /// @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/contracts/lib/BytesLib.sol b/contracts/lib/BytesLib.sol new file mode 100644 index 000000000..e7d29cdfb --- /dev/null +++ b/contracts/lib/BytesLib.sol @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * @title Solidity Bytes Arrays Utils + * @author Gonçalo Sá + * + * @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity. + * The library lets you concatenate, slice and type cast bytes arrays both in memory and storage. + */ +pragma solidity 0.6.10; + +library BytesLib { + function slice( + bytes memory _bytes, + uint256 _start, + uint256 _length + ) internal pure returns (bytes memory) { + require(_length + 31 >= _length, "slice_overflow"); + require(_start + _length >= _start, "slice_overflow"); + require(_bytes.length >= _start + _length, "slice_outOfBounds"); + + bytes memory tempBytes; + + assembly { + switch iszero(_length) + case 0 { + // Get a location of some free memory and store it in tempBytes as + // Solidity does for memory variables. + tempBytes := mload(0x40) + + // The first word of the slice result is potentially a partial + // word read from the original array. To read it, we calculate + // the length of that partial word and start copying that many + // bytes into the array. The first word we copy will start with + // data we don't care about, but the last `lengthmod` bytes will + // land at the beginning of the contents of the new array. When + // we're done copying, we overwrite the full first word with + // the actual length of the slice. + let lengthmod := and(_length, 31) + + // The multiplication in the next line is necessary + // because when slicing multiples of 32 bytes (lengthmod == 0) + // the following copy loop was copying the origin's length + // and then ending prematurely not copying everything it should. + let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod))) + let end := add(mc, _length) + + for { + // The multiplication in the next line has the same exact purpose + // as the one above. + let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start) + } lt(mc, end) { + mc := add(mc, 0x20) + cc := add(cc, 0x20) + } { + mstore(mc, mload(cc)) + } + + mstore(tempBytes, _length) + + //update free-memory pointer + //allocating the array padded to 32 bytes like the compiler does now + mstore(0x40, and(add(mc, 31), not(31))) + } + //if we want a zero-length slice let's just return a zero-length array + default { + tempBytes := mload(0x40) + //zero out the 32 bytes slice we are about to return + //we need to do it because Solidity does not garbage collect + mstore(tempBytes, 0) + + mstore(0x40, add(tempBytes, 0x20)) + } + } + + return tempBytes; + } + + function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) { + require(_start + 20 >= _start, "toAddress_overflow"); + require(_bytes.length >= _start + 20, "toAddress_outOfBounds"); + address tempAddress; + + assembly { + tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000) + } + + return tempAddress; + } + + function toUint24(bytes memory _bytes, uint256 _start) internal pure returns (uint24) { + require(_start + 3 >= _start, "toUint24_overflow"); + require(_bytes.length >= _start + 3, "toUint24_outOfBounds"); + uint24 tempUint; + + assembly { + tempUint := mload(add(add(_bytes, 0x3), _start)) + } + + return tempUint; + } +} \ No newline at end of file diff --git a/contracts/protocol/integration/index-exchange/UniswapV3IndexExchangeAdapter.sol b/contracts/protocol/integration/index-exchange/UniswapV3IndexExchangeAdapter.sol index edeba0424..7fbd1d2ae 100644 --- a/contracts/protocol/integration/index-exchange/UniswapV3IndexExchangeAdapter.sol +++ b/contracts/protocol/integration/index-exchange/UniswapV3IndexExchangeAdapter.sol @@ -16,11 +16,11 @@ SPDX-License-Identifier: Apache License, Version 2.0 */ -pragma solidity >=0.7.5; -pragma abicoder v2; +pragma solidity 0.6.10; +pragma experimental "ABIEncoderV2"; -import { ISwapRouter } from "@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol"; -import { BytesLib } from "@uniswap/v3-periphery/contracts/libraries/BytesLib.sol"; +import { ISwapRouter } from "contracts/interfaces/external/ISwapRouter.sol"; +import { BytesLib } from "contracts/lib/BytesLib.sol"; import { IIndexExchangeAdapter } from "../../../interfaces/IIndexExchangeAdapter.sol"; @@ -39,6 +39,9 @@ contract UniswapV3IndexExchangeAdapter is IIndexExchangeAdapter { // Address of Uniswap V3 SwapRouter contract address public immutable router; + + /* ============ Constants ============ */ + // Uniswap router function string for swapping exact amount of input tokens for a minimum of output tokens string internal constant SWAP_EXACT_INPUT = "exactInput((bytes,address,uint256,uint256,uint256))"; // Uniswap router function string for swapping max amoutn of input tokens for an exact amount of output tokens @@ -51,7 +54,7 @@ contract UniswapV3IndexExchangeAdapter is IIndexExchangeAdapter { * * @param _router Address of Uniswap V3 SwapRouter contract */ - constructor(address _router) { + constructor(address _router) public { router = _router; } @@ -78,7 +81,7 @@ contract UniswapV3IndexExchangeAdapter is IIndexExchangeAdapter { * @param _sourceQuantity Fixed/Max amount of source token to sell * @param _destinationQuantity Min/Fixed amount of destination token to buy * @param _data Arbitrary bytes containing fees value, expressed in hundredths of a bip, - * used to determine the pool to trade among similar asset pools on Uniswap V3 + * used to determine the pool to trade among similar asset pools on Uniswap V3 * * @return address Target contract address * @return uint256 Call value @@ -121,17 +124,4 @@ contract UniswapV3IndexExchangeAdapter is IIndexExchangeAdapter { function getSpender() external view override returns (address) { return router; } - - /** - * Helper that returns the encoded data of Uniswap V3 trade path. - * - * @param _sourceToken Address of source token to be sold - * @param _fees Fees of the Uniswap V3 pool to be used, expressed in hundredths of a bip - * @param _destinationToken Address of destination token to buy - * - * @return bytes Encoded data used for trading on Uniswap - */ - function getEncodedTradePath(address _sourceToken, uint24 _fees, address _destinationToken) external pure returns (bytes memory) { - return abi.encodePacked(_sourceToken, _fees, _destinationToken); - } } \ No newline at end of file diff --git a/hardhat.config.ts b/hardhat.config.ts index e3adfe53e..d9891bebc 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -11,18 +11,10 @@ import "./tasks"; const config: HardhatUserConfig = { solidity: { - compilers: [ - { - version: "0.6.10", - settings: { - optimizer: { enabled: true, runs: 200 }, - }, - }, - { - version: "0.7.5", - } - ] - + version: "0.6.10", + settings: { + optimizer: { enabled: true, runs: 200 }, + }, }, namedAccounts: { deployer: 0, diff --git a/package.json b/package.json index ed6ab2f83..c62288134 100644 --- a/package.json +++ b/package.json @@ -85,7 +85,7 @@ "web3": "^1.2.9" }, "dependencies": { - "@uniswap/v3-periphery": "^1.0.0", + "@uniswap/v3-core": "^1.0.0", "fs-extra": "^5.0.0", "module-alias": "^2.2.2", "replace-in-file": "^6.1.0", diff --git a/test/protocol/integration/index-exchange/uniswapV3IndexExchangeAdapter.spec.ts b/test/protocol/integration/index-exchange/uniswapV3IndexExchangeAdapter.spec.ts index 7491adbfe..eab15d2e2 100644 --- a/test/protocol/integration/index-exchange/uniswapV3IndexExchangeAdapter.spec.ts +++ b/test/protocol/integration/index-exchange/uniswapV3IndexExchangeAdapter.spec.ts @@ -91,44 +91,13 @@ describe("UniswapV3IndexExchangeAdapter", () => { }); }); - - describe("getEncodedTradePath", async () => { - let subjectFees: BigNumber; - let subjectSourceToken: Address; - let subjectDestinationToken: Address; - - beforeEach(async () => { - subjectFees = BigNumber.from(10000); // 1% pool fees - subjectSourceToken = setup.wbtc.address; - subjectDestinationToken = setup.dai.address; - }); - - async function subject(): Promise { - return await uniswapV3ExchangeAdapter.getEncodedTradePath( - subjectSourceToken, - subjectFees, - subjectDestinationToken - ); - } - - it("should return the correct data", async () => { - const tradePathData = await subject(); - - const expectedTradePathData = solidityPack( - ["address", "uint24", "address"], - [subjectSourceToken, subjectFees, subjectDestinationToken] - ); - - expect(tradePathData).to.eq(expectedTradePathData); - }); - }); - describe("getTradeCalldata", async () => { let sourceToken: Address; let destinationToken: Address; let sourceQuantity: BigNumber; let destinationQuantity: BigNumber; let poolFeesPercentage: BigNumber; + let path: Bytes; let subjectMockSetToken: Address; let subjectSourceToken: Address; @@ -144,6 +113,10 @@ describe("UniswapV3IndexExchangeAdapter", () => { destinationToken = setup.dai.address; // DAI Address destinationQuantity = ether(50000); // Receive at least 50k DAI poolFeesPercentage = BigNumber.from(3000); // 0.3% fee + path = solidityPack( + ["address", "uint24", "address"], + [sourceToken, poolFeesPercentage, destinationToken] + ); subjectSourceToken = sourceToken; subjectDestinationToken = destinationToken; @@ -171,11 +144,6 @@ describe("UniswapV3IndexExchangeAdapter", () => { const [tragetAddress, ethValue, callData] = await subject(); const callTimestamp = await getLastBlockTimestamp(); - const path: Bytes = await uniswapV3ExchangeAdapter.getEncodedTradePath( - sourceToken, - poolFeesPercentage, - destinationToken - ); const expectedCallData = swapRouter.interface.encodeFunctionData("exactInput", [{ path: path, @@ -200,11 +168,6 @@ describe("UniswapV3IndexExchangeAdapter", () => { const [tragetAddress, ethValue, callData] = await subject(); const callTimestamp = await getLastBlockTimestamp(); - const path: Bytes = await uniswapV3ExchangeAdapter.getEncodedTradePath( - sourceToken, - poolFeesPercentage, - destinationToken - ); const expectedCallData = swapRouter.interface.encodeFunctionData("exactOutput", [{ path: path, diff --git a/yarn.lock b/yarn.lock index 03799a48a..28f23092e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -559,11 +559,6 @@ "@types/sinon-chai" "^3.2.3" "@types/web3" "1.0.19" -"@openzeppelin/contracts@3.4.1-solc-0.7-2": - version "3.4.1-solc-0.7-2" - resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-3.4.1-solc-0.7-2.tgz#371c67ebffe50f551c3146a9eec5fe6ffe862e92" - integrity sha512-tAG9LWg8+M2CMu7hIsqHPaTyG4uDzjr6mhvH96LvOpLZZj6tgzTluBt+LsCf1/QaYrlis6pITvpIaIhE+iZB+Q== - "@openzeppelin/contracts@^3.1.0": version "3.3.0" resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-3.3.0.tgz#ffdb693c5c349fc33bba420248dd3ac0a2d7c408" @@ -906,32 +901,11 @@ "@types/bn.js" "*" "@types/underscore" "*" -"@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": +"@uniswap/v3-core@^1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@uniswap/v3-core/-/v3-core-1.0.0.tgz#6c24adacc4c25dceee0ba3ca142b35adbd7e359d" integrity sha512-kSC4djMGKMHj7sLMYVnn61k9nu+lHjMIxgg9CDQT+s2QYLoA56GbSK9Oxr+qJXzzygbkrmuY6cwgP6cW2JXPFA== -"@uniswap/v3-periphery@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@uniswap/v3-periphery/-/v3-periphery-1.0.0.tgz#8e789dcd70bdd06e01e21dd75372dc76ab38ea47" - integrity sha512-kRqUrjnyh+X1wJdSENPDFr9sjRVebv2KyLtfqDOPij0dXJ69GspFU2qrZXjouc6LYdkWG7x3fagiTlw0eGniYQ== - dependencies: - "@openzeppelin/contracts" "3.4.1-solc-0.7-2" - "@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" @@ -1867,11 +1841,6 @@ base64-js@^1.3.1: resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== -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" From 33a934efe9b206157af7caaac4cacd00b17ddad4 Mon Sep 17 00:00:00 2001 From: alpha-guy Date: Fri, 4 Jun 2021 21:03:31 +0530 Subject: [PATCH 08/16] Use exactInputSingle and exactOutputSingle functions instead of exactInput and exactOutput --- .../UniswapV3IndexExchangeAdapter.sol | 30 +++++++++++++++---- .../uniswapV3IndexExchangeAdapter.spec.ts | 21 ++++++------- 2 files changed, 35 insertions(+), 16 deletions(-) diff --git a/contracts/protocol/integration/index-exchange/UniswapV3IndexExchangeAdapter.sol b/contracts/protocol/integration/index-exchange/UniswapV3IndexExchangeAdapter.sol index 7fbd1d2ae..027449899 100644 --- a/contracts/protocol/integration/index-exchange/UniswapV3IndexExchangeAdapter.sol +++ b/contracts/protocol/integration/index-exchange/UniswapV3IndexExchangeAdapter.sol @@ -43,9 +43,9 @@ contract UniswapV3IndexExchangeAdapter is IIndexExchangeAdapter { /* ============ Constants ============ */ // Uniswap router function string for swapping exact amount of input tokens for a minimum of output tokens - string internal constant SWAP_EXACT_INPUT = "exactInput((bytes,address,uint256,uint256,uint256))"; + string internal constant SWAP_EXACT_INPUT = "exactInputSingle((address,address,uint24,address,uint256,uint256,uint256,uint160))"; // Uniswap router function string for swapping max amoutn of input tokens for an exact amount of output tokens - string internal constant SWAP_EXACT_OUTPUT = "exactOutput((bytes,address,uint256,uint256,uint256))"; + string internal constant SWAP_EXACT_OUTPUT = "exactOutputSingle((address,address,uint24,address,uint256,uint256,uint256,uint160))"; /* ============ Constructor ============ */ @@ -101,16 +101,34 @@ contract UniswapV3IndexExchangeAdapter is IIndexExchangeAdapter { override returns (address, uint256, bytes memory) { - uint24 fees = _data.toUint24(0); - bytes memory path = abi.encodePacked(_sourceToken, fees, _destinationToken); + uint24 fee = _data.toUint24(0); + bytes memory path = abi.encodePacked(_sourceToken, fee, _destinationToken); bytes memory callData = _isSendTokenFixed ? abi.encodeWithSignature( SWAP_EXACT_INPUT, - ISwapRouter.ExactInputParams(path, _destinationAddress, block.timestamp, _sourceQuantity, _destinationQuantity) + ISwapRouter.ExactInputSingleParams( + _sourceToken, + _destinationToken, + fee, + _destinationAddress, + block.timestamp, + _sourceQuantity, + _destinationQuantity, + 0 + ) ) : abi.encodeWithSignature( SWAP_EXACT_OUTPUT, - ISwapRouter.ExactOutputParams(path, _destinationAddress, block.timestamp, _destinationQuantity, _sourceQuantity) + ISwapRouter.ExactOutputSingleParams( + _sourceToken, + _destinationToken, + fee, + _destinationAddress, + block.timestamp, + _destinationQuantity, + _sourceQuantity, + 0 + ) ); return (router, 0, callData); diff --git a/test/protocol/integration/index-exchange/uniswapV3IndexExchangeAdapter.spec.ts b/test/protocol/integration/index-exchange/uniswapV3IndexExchangeAdapter.spec.ts index eab15d2e2..c418c30b9 100644 --- a/test/protocol/integration/index-exchange/uniswapV3IndexExchangeAdapter.spec.ts +++ b/test/protocol/integration/index-exchange/uniswapV3IndexExchangeAdapter.spec.ts @@ -1,6 +1,6 @@ import "module-alias/register"; -import { hexlify, solidityPack, hexZeroPad } from "ethers/lib/utils"; +import { hexlify, hexZeroPad } from "ethers/lib/utils"; import { BigNumber } from "@ethersproject/bignumber"; import { Address, Bytes } from "@utils/types"; import { Account } from "@utils/test/types"; @@ -97,7 +97,6 @@ describe("UniswapV3IndexExchangeAdapter", () => { let sourceQuantity: BigNumber; let destinationQuantity: BigNumber; let poolFeesPercentage: BigNumber; - let path: Bytes; let subjectMockSetToken: Address; let subjectSourceToken: Address; @@ -113,10 +112,6 @@ describe("UniswapV3IndexExchangeAdapter", () => { destinationToken = setup.dai.address; // DAI Address destinationQuantity = ether(50000); // Receive at least 50k DAI poolFeesPercentage = BigNumber.from(3000); // 0.3% fee - path = solidityPack( - ["address", "uint24", "address"], - [sourceToken, poolFeesPercentage, destinationToken] - ); subjectSourceToken = sourceToken; subjectDestinationToken = destinationToken; @@ -145,12 +140,15 @@ describe("UniswapV3IndexExchangeAdapter", () => { const callTimestamp = await getLastBlockTimestamp(); - const expectedCallData = swapRouter.interface.encodeFunctionData("exactInput", [{ - path: path, + const expectedCallData = swapRouter.interface.encodeFunctionData("exactInputSingle", [{ + tokenIn: sourceToken, + tokenOut: destinationToken, + fee: poolFeesPercentage, recipient: subjectMockSetToken, deadline: callTimestamp, amountIn: sourceQuantity, amountOutMinimum: destinationQuantity, + sqrtPriceLimitX96: 0, }]); expect(tragetAddress).to.eq(swapRouter.address); @@ -169,12 +167,15 @@ describe("UniswapV3IndexExchangeAdapter", () => { const callTimestamp = await getLastBlockTimestamp(); - const expectedCallData = swapRouter.interface.encodeFunctionData("exactOutput", [{ - path: path, + const expectedCallData = swapRouter.interface.encodeFunctionData("exactOutputSingle", [{ + tokenIn: sourceToken, + tokenOut: destinationToken, + fee: poolFeesPercentage, recipient: subjectMockSetToken, deadline: callTimestamp, amountOut: destinationQuantity, amountInMaximum: sourceQuantity, + sqrtPriceLimitX96: 0, }]); expect(tragetAddress).to.eq(swapRouter.address); From 700820a3874e27eea90b91ab1c1e7577b702fb54 Mon Sep 17 00:00:00 2001 From: alpha-guy Date: Fri, 4 Jun 2021 22:22:39 +0530 Subject: [PATCH 09/16] Move BytesLib to external/contracts/uniswap/v3 --- .../index-exchange/UniswapV3IndexExchangeAdapter.sol | 2 +- {contracts => external/contracts/uniswap/v3}/lib/BytesLib.sol | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename {contracts => external/contracts/uniswap/v3}/lib/BytesLib.sol (100%) diff --git a/contracts/protocol/integration/index-exchange/UniswapV3IndexExchangeAdapter.sol b/contracts/protocol/integration/index-exchange/UniswapV3IndexExchangeAdapter.sol index 027449899..dfe403ddc 100644 --- a/contracts/protocol/integration/index-exchange/UniswapV3IndexExchangeAdapter.sol +++ b/contracts/protocol/integration/index-exchange/UniswapV3IndexExchangeAdapter.sol @@ -20,7 +20,7 @@ pragma solidity 0.6.10; pragma experimental "ABIEncoderV2"; import { ISwapRouter } from "contracts/interfaces/external/ISwapRouter.sol"; -import { BytesLib } from "contracts/lib/BytesLib.sol"; +import { BytesLib } from "external/contracts/uniswap/v3/lib/BytesLib.sol"; import { IIndexExchangeAdapter } from "../../../interfaces/IIndexExchangeAdapter.sol"; diff --git a/contracts/lib/BytesLib.sol b/external/contracts/uniswap/v3/lib/BytesLib.sol similarity index 100% rename from contracts/lib/BytesLib.sol rename to external/contracts/uniswap/v3/lib/BytesLib.sol From 283fca4809f2730fd3605d258572dedfe552c0b8 Mon Sep 17 00:00:00 2001 From: alpha-guy Date: Fri, 4 Jun 2021 23:27:09 +0530 Subject: [PATCH 10/16] Add Note to set exchange data in GIM --- .../index-exchange/UniswapV3IndexExchangeAdapter.sol | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/contracts/protocol/integration/index-exchange/UniswapV3IndexExchangeAdapter.sol b/contracts/protocol/integration/index-exchange/UniswapV3IndexExchangeAdapter.sol index dfe403ddc..a876b0adb 100644 --- a/contracts/protocol/integration/index-exchange/UniswapV3IndexExchangeAdapter.sol +++ b/contracts/protocol/integration/index-exchange/UniswapV3IndexExchangeAdapter.sol @@ -81,7 +81,9 @@ contract UniswapV3IndexExchangeAdapter is IIndexExchangeAdapter { * @param _sourceQuantity Fixed/Max amount of source token to sell * @param _destinationQuantity Min/Fixed amount of destination token to buy * @param _data Arbitrary bytes containing fees value, expressed in hundredths of a bip, - * used to determine the pool to trade among similar asset pools on Uniswap V3 + * used to determine the pool to trade among similar asset pools on Uniswap V3. + * Note: SetToken manager must set the appropriate pool fees via `setExchangeData` in GeneralIndexModule + * for each component that needs to be traded on UniswapV3 * * @return address Target contract address * @return uint256 Call value From 61e63674c00cd703a70fe2a3b6efb9ff59a5b46f Mon Sep 17 00:00:00 2001 From: alpha-guy Date: Sat, 5 Jun 2021 13:00:03 +0530 Subject: [PATCH 11/16] Remove @uniswap/v3-core dependency *Add suggested changes --- contracts/interfaces/IIndexExchangeAdapter.sol | 2 +- contracts/interfaces/external/ISwapRouter.sol | 4 +--- package.json | 1 - yarn.lock | 5 ----- 4 files changed, 2 insertions(+), 10 deletions(-) diff --git a/contracts/interfaces/IIndexExchangeAdapter.sol b/contracts/interfaces/IIndexExchangeAdapter.sol index ff22e32f1..c54130e4b 100644 --- a/contracts/interfaces/IIndexExchangeAdapter.sol +++ b/contracts/interfaces/IIndexExchangeAdapter.sol @@ -15,7 +15,7 @@ SPDX-License-Identifier: Apache License, Version 2.0 */ -pragma solidity >=0.6.10; +pragma solidity 0.6.10; interface IIndexExchangeAdapter { function getSpender() external view returns(address); diff --git a/contracts/interfaces/external/ISwapRouter.sol b/contracts/interfaces/external/ISwapRouter.sol index c9ff10aec..897408055 100644 --- a/contracts/interfaces/external/ISwapRouter.sol +++ b/contracts/interfaces/external/ISwapRouter.sol @@ -8,11 +8,9 @@ pragma abicoder v2; pragma solidity 0.6.10; pragma experimental "ABIEncoderV2"; -import "@uniswap/v3-core/contracts/interfaces/callback/IUniswapV3SwapCallback.sol"; - /// @title Router token swapping functionality /// @notice Functions for swapping tokens via Uniswap V3 -interface ISwapRouter is IUniswapV3SwapCallback { +interface ISwapRouter { struct ExactInputSingleParams { address tokenIn; address tokenOut; diff --git a/package.json b/package.json index 73e28ae58..207de7110 100644 --- a/package.json +++ b/package.json @@ -86,7 +86,6 @@ "web3": "^1.2.9" }, "dependencies": { - "@uniswap/v3-core": "^1.0.0", "@ethersproject/bignumber": "5.0.12", "@ethersproject/providers": "5.0.17", "ethers": "5.0.24", diff --git a/yarn.lock b/yarn.lock index 973311842..34740f90f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -971,11 +971,6 @@ "@types/bn.js" "*" "@types/underscore" "*" -"@uniswap/v3-core@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@uniswap/v3-core/-/v3-core-1.0.0.tgz#6c24adacc4c25dceee0ba3ca142b35adbd7e359d" - integrity sha512-kSC4djMGKMHj7sLMYVnn61k9nu+lHjMIxgg9CDQT+s2QYLoA56GbSK9Oxr+qJXzzygbkrmuY6cwgP6cW2JXPFA== - "@yarnpkg/lockfile@^1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31" From 9ce9ffe2d8dd3254814b72e96437b5a9e73d4300 Mon Sep 17 00:00:00 2001 From: alpha-guy Date: Tue, 8 Jun 2021 00:53:18 +0530 Subject: [PATCH 12/16] Add getEncodedFeeData function and add suggested changes --- .../UniswapV3IndexExchangeAdapter.sol | 25 +++++++++++++------ .../uniswapV3IndexExchangeAdapter.spec.ts | 19 ++++++++++++++ 2 files changed, 37 insertions(+), 7 deletions(-) diff --git a/contracts/protocol/integration/index-exchange/UniswapV3IndexExchangeAdapter.sol b/contracts/protocol/integration/index-exchange/UniswapV3IndexExchangeAdapter.sol index a876b0adb..61a254fd4 100644 --- a/contracts/protocol/integration/index-exchange/UniswapV3IndexExchangeAdapter.sol +++ b/contracts/protocol/integration/index-exchange/UniswapV3IndexExchangeAdapter.sol @@ -35,11 +35,6 @@ contract UniswapV3IndexExchangeAdapter is IIndexExchangeAdapter { using BytesLib for bytes; - /* ============ State Variables ============ */ - - // Address of Uniswap V3 SwapRouter contract - address public immutable router; - /* ============ Constants ============ */ // Uniswap router function string for swapping exact amount of input tokens for a minimum of output tokens @@ -47,6 +42,11 @@ contract UniswapV3IndexExchangeAdapter is IIndexExchangeAdapter { // Uniswap router function string for swapping max amoutn of input tokens for an exact amount of output tokens string internal constant SWAP_EXACT_OUTPUT = "exactOutputSingle((address,address,uint24,address,uint256,uint256,uint256,uint160))"; + /* ============ State Variables ============ */ + + // Address of Uniswap V3 SwapRouter contract + address public immutable router; + /* ============ Constructor ============ */ /** @@ -83,7 +83,8 @@ contract UniswapV3IndexExchangeAdapter is IIndexExchangeAdapter { * @param _data Arbitrary bytes containing fees value, expressed in hundredths of a bip, * used to determine the pool to trade among similar asset pools on Uniswap V3. * Note: SetToken manager must set the appropriate pool fees via `setExchangeData` in GeneralIndexModule - * for each component that needs to be traded on UniswapV3 + * for each component that needs to be traded on UniswapV3. This is different from UniswapV3ExchangeAdapter, + * where `_data` represents UniswapV3 trade path vs just the pool fees percentage. * * @return address Target contract address * @return uint256 Call value @@ -104,7 +105,6 @@ contract UniswapV3IndexExchangeAdapter is IIndexExchangeAdapter { returns (address, uint256, bytes memory) { uint24 fee = _data.toUint24(0); - bytes memory path = abi.encodePacked(_sourceToken, fee, _destinationToken); bytes memory callData = _isSendTokenFixed ? abi.encodeWithSignature( @@ -144,4 +144,15 @@ contract UniswapV3IndexExchangeAdapter is IIndexExchangeAdapter { function getSpender() external view override returns (address) { return router; } + + /** + * Helper that returns encoded fee value. + * + * @param fee UniswapV3 pool fee percentage, expressed in hundredths of a bip + * + * @return bytes Encoded fee value + */ + function getEncodedFeeData(uint24 fee) external view returns (bytes memory) { + return abi.encodePacked(fee); + } } \ No newline at end of file diff --git a/test/protocol/integration/index-exchange/uniswapV3IndexExchangeAdapter.spec.ts b/test/protocol/integration/index-exchange/uniswapV3IndexExchangeAdapter.spec.ts index c418c30b9..bf8669ff7 100644 --- a/test/protocol/integration/index-exchange/uniswapV3IndexExchangeAdapter.spec.ts +++ b/test/protocol/integration/index-exchange/uniswapV3IndexExchangeAdapter.spec.ts @@ -184,4 +184,23 @@ describe("UniswapV3IndexExchangeAdapter", () => { }); }); }); + + describe("getEncodedFeeData", async () => { + let subjectFee: BigNumber; + + beforeEach(async () => { + subjectFee = BigNumber.from(1000); + }); + + async function subject(): Promise { + return await uniswapV3ExchangeAdapter.getEncodedFeeData(subjectFee); + } + + it("Should return correct bytes encoded fee data", async () => { + const encodedFeeData = await subject(); + + const expectedEncodedFeeData = constructFeesData(subjectFee); + expect(encodedFeeData).to.eq(expectedEncodedFeeData); + }); + }); }); \ No newline at end of file From 7e8ab6abb4e7664f1f4b2af11e672fc1687840f8 Mon Sep 17 00:00:00 2001 From: alpha-guy Date: Sat, 19 Jun 2021 23:23:34 +0530 Subject: [PATCH 13/16] Refactor tests to use UniswapV3 Fixture --- .../contracts/uniswap/v3/lib/BytesLib.sol | 20 --------- .../uniswapV3IndexExchangeAdapter.spec.ts | 43 +++++++++++-------- utils/contracts/uniswap.ts | 6 +-- utils/deploys/deployExternal.ts | 17 -------- 4 files changed, 25 insertions(+), 61 deletions(-) diff --git a/external/contracts/uniswap/v3/lib/BytesLib.sol b/external/contracts/uniswap/v3/lib/BytesLib.sol index 8663a24e4..e7d29cdfb 100644 --- a/external/contracts/uniswap/v3/lib/BytesLib.sol +++ b/external/contracts/uniswap/v3/lib/BytesLib.sol @@ -6,11 +6,7 @@ * @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity. * The library lets you concatenate, slice and type cast bytes arrays both in memory and storage. */ -<<<<<<< HEAD pragma solidity 0.6.10; -======= -pragma solidity >=0.5.0 <0.8.0; ->>>>>>> master library BytesLib { function slice( @@ -18,15 +14,9 @@ library BytesLib { uint256 _start, uint256 _length ) internal pure returns (bytes memory) { -<<<<<<< HEAD require(_length + 31 >= _length, "slice_overflow"); require(_start + _length >= _start, "slice_overflow"); require(_bytes.length >= _start + _length, "slice_outOfBounds"); -======= - require(_length + 31 >= _length, 'slice_overflow'); - require(_start + _length >= _start, 'slice_overflow'); - require(_bytes.length >= _start + _length, 'slice_outOfBounds'); ->>>>>>> master bytes memory tempBytes; @@ -86,13 +76,8 @@ library BytesLib { } function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) { -<<<<<<< HEAD require(_start + 20 >= _start, "toAddress_overflow"); require(_bytes.length >= _start + 20, "toAddress_outOfBounds"); -======= - require(_start + 20 >= _start, 'toAddress_overflow'); - require(_bytes.length >= _start + 20, 'toAddress_outOfBounds'); ->>>>>>> master address tempAddress; assembly { @@ -103,13 +88,8 @@ library BytesLib { } function toUint24(bytes memory _bytes, uint256 _start) internal pure returns (uint24) { -<<<<<<< HEAD require(_start + 3 >= _start, "toUint24_overflow"); require(_bytes.length >= _start + 3, "toUint24_outOfBounds"); -======= - require(_start + 3 >= _start, 'toUint24_overflow'); - require(_bytes.length >= _start + 3, 'toUint24_outOfBounds'); ->>>>>>> master uint24 tempUint; assembly { diff --git a/test/protocol/integration/index-exchange/uniswapV3IndexExchangeAdapter.spec.ts b/test/protocol/integration/index-exchange/uniswapV3IndexExchangeAdapter.spec.ts index bf8669ff7..cc585956f 100644 --- a/test/protocol/integration/index-exchange/uniswapV3IndexExchangeAdapter.spec.ts +++ b/test/protocol/integration/index-exchange/uniswapV3IndexExchangeAdapter.spec.ts @@ -7,21 +7,20 @@ import { Account } from "@utils/test/types"; import { ZERO, } from "@utils/constants"; -import { SwapRouter, UniswapV3Factory } from "@utils/contracts/uniswap"; import { UniswapV3IndexExchangeAdapter } from "@utils/contracts"; import DeployHelper from "@utils/deploys"; -import { SystemFixture } from "@utils/fixtures"; -import { - ether, -} from "@utils/index"; +import { ether } from "@utils/index"; import { addSnapshotBeforeRestoreAfterEach, getAccounts, getSystemFixture, getWaffleExpect, - getLastBlockTimestamp + getLastBlockTimestamp, + getUniswapV3Fixture } from "@utils/test/index"; +import { SystemFixture, UniswapV3Fixture } from "@utils/fixtures"; + const expect = getWaffleExpect(); describe("UniswapV3IndexExchangeAdapter", () => { @@ -29,9 +28,8 @@ describe("UniswapV3IndexExchangeAdapter", () => { let mockSetToken: Account; let deployer: DeployHelper; let setup: SystemFixture; + let uniswapV3Fixture: UniswapV3Fixture; - let swapRouter: SwapRouter; - let factory: UniswapV3Factory; let uniswapV3ExchangeAdapter: UniswapV3IndexExchangeAdapter; function constructFeesData(_poolFeesPercentage: BigNumber): Bytes { @@ -49,10 +47,17 @@ describe("UniswapV3IndexExchangeAdapter", () => { setup = getSystemFixture(owner.address); await setup.initialize(); - factory = await deployer.external.deployUniswapV3Factory(); - swapRouter = await deployer.external.deploySwapRouter(factory.address, setup.weth.address); - - uniswapV3ExchangeAdapter = await deployer.adapters.deployUniswapV3IndexExchangeAdapter(swapRouter.address); + uniswapV3Fixture = getUniswapV3Fixture(owner.address); + await uniswapV3Fixture.initialize( + owner, + setup.weth, + 2500, + setup.wbtc, + 35000, + setup.dai + ); + + uniswapV3ExchangeAdapter = await deployer.adapters.deployUniswapV3IndexExchangeAdapter(uniswapV3Fixture.swapRouter.address); }); addSnapshotBeforeRestoreAfterEach(); @@ -61,7 +66,7 @@ describe("UniswapV3IndexExchangeAdapter", () => { let subjectRouterAddress: Address; beforeEach(async () => { - subjectRouterAddress = swapRouter.address; + subjectRouterAddress = uniswapV3Fixture.swapRouter.address; }); async function subject(): Promise { @@ -72,7 +77,7 @@ describe("UniswapV3IndexExchangeAdapter", () => { const deployedUniswapV3IndexExchangeAdapter = await subject(); const routerAddress = await deployedUniswapV3IndexExchangeAdapter.router(); - const expectedRouterAddress = subjectRouterAddress; + const expectedRouterAddress = uniswapV3Fixture.swapRouter.address; expect(routerAddress).to.eq(expectedRouterAddress); }); @@ -85,7 +90,7 @@ describe("UniswapV3IndexExchangeAdapter", () => { it("should return the correct spender address", async () => { const spender = await subject(); - const expectedSpender = swapRouter.address; + const expectedSpender = uniswapV3Fixture.swapRouter.address; expect(spender).to.eq(expectedSpender); }); @@ -140,7 +145,7 @@ describe("UniswapV3IndexExchangeAdapter", () => { const callTimestamp = await getLastBlockTimestamp(); - const expectedCallData = swapRouter.interface.encodeFunctionData("exactInputSingle", [{ + const expectedCallData = uniswapV3Fixture.swapRouter.interface.encodeFunctionData("exactInputSingle", [{ tokenIn: sourceToken, tokenOut: destinationToken, fee: poolFeesPercentage, @@ -151,7 +156,7 @@ describe("UniswapV3IndexExchangeAdapter", () => { sqrtPriceLimitX96: 0, }]); - expect(tragetAddress).to.eq(swapRouter.address); + expect(tragetAddress).to.eq(uniswapV3Fixture.swapRouter.address); expect(ethValue).to.eq(ZERO); expect(callData).to.eq(expectedCallData); }); @@ -167,7 +172,7 @@ describe("UniswapV3IndexExchangeAdapter", () => { const callTimestamp = await getLastBlockTimestamp(); - const expectedCallData = swapRouter.interface.encodeFunctionData("exactOutputSingle", [{ + const expectedCallData = uniswapV3Fixture.swapRouter.interface.encodeFunctionData("exactOutputSingle", [{ tokenIn: sourceToken, tokenOut: destinationToken, fee: poolFeesPercentage, @@ -178,7 +183,7 @@ describe("UniswapV3IndexExchangeAdapter", () => { sqrtPriceLimitX96: 0, }]); - expect(tragetAddress).to.eq(swapRouter.address); + expect(tragetAddress).to.eq(uniswapV3Fixture.swapRouter.address); expect(ethValue).to.eq(ZERO); expect(callData).to.eq(expectedCallData); }); diff --git a/utils/contracts/uniswap.ts b/utils/contracts/uniswap.ts index 6f0db3466..b2d879e0a 100644 --- a/utils/contracts/uniswap.ts +++ b/utils/contracts/uniswap.ts @@ -5,8 +5,4 @@ export { UniswapGovernorAlpha } from "../../typechain/UniswapGovernorAlpha"; export { UniswapTimelock } from "../../typechain/UniswapTimelock"; export { UniswapV2Factory } from "../../typechain/UniswapV2Factory"; export { UniswapV2Pair } from "../../typechain/UniswapV2Pair"; -export { UniswapV2Router02 } from "../../typechain/UniswapV2Router02"; - -// External Uniswap V3 contracts -export { SwapRouter } from "../../typechain/SwapRouter"; -export { UniswapV3Factory } from "../../typechain/UniswapV3Factory"; \ No newline at end of file +export { UniswapV2Router02 } from "../../typechain/UniswapV2Router02"; \ No newline at end of file diff --git a/utils/deploys/deployExternal.ts b/utils/deploys/deployExternal.ts index 3c1dd3ab1..de1ece93b 100644 --- a/utils/deploys/deployExternal.ts +++ b/utils/deploys/deployExternal.ts @@ -113,14 +113,6 @@ import { UniswapV2Factory__factory } from "../../typechain/factories/UniswapV2Fa import { UniswapV2Pair__factory } from "../../typechain/factories/UniswapV2Pair__factory"; import { UniswapV2Router02__factory } from "../../typechain/factories/UniswapV2Router02__factory"; -import { - SwapRouter, - UniswapV3Factory -} from "../contracts/uniswap"; - -import { SwapRouter__factory } from "../../typechain/factories/SwapRouter__factory"; -import { UniswapV3Factory__factory } from "../../typechain/factories/UniswapV3Factory__factory"; - import { BFactory, BRegistry, @@ -563,15 +555,6 @@ export default class DeployExternalContracts { return await new DelegateRegistry__factory(this._deployerSigner).deploy(); } - // UNISWAP V3 - public async deployUniswapV3Factory(): Promise { - return await new UniswapV3Factory__factory(this._deployerSigner).deploy(); - } - - public async deploySwapRouter(_factory: Address, _weth: Address): Promise { - return await new SwapRouter__factory(this._deployerSigner).deploy(_factory, _weth); - } - // YEARN public async deployVault(): Promise { return await new Vault__factory(this._deployerSigner).deploy(); From 3379a1d0982cf29e6ee7d17da9c059dbb1e7c7ae Mon Sep 17 00:00:00 2001 From: alpha-guy Date: Sun, 20 Jun 2021 00:20:36 +0530 Subject: [PATCH 14/16] Fix uniswap/v3/SwapRotuer ABI --- external/abi/uniswap/v3/SwapRouter.json | 506 +----------------------- 1 file changed, 4 insertions(+), 502 deletions(-) diff --git a/external/abi/uniswap/v3/SwapRouter.json b/external/abi/uniswap/v3/SwapRouter.json index 7e34a61f5..dd402416c 100644 --- a/external/abi/uniswap/v3/SwapRouter.json +++ b/external/abi/uniswap/v3/SwapRouter.json @@ -1,506 +1,8 @@ { - "_format": "hh-sol-artifact-1", "contractName": "SwapRouter", - "sourceName": "contracts/SwapRouter.sol", - "abi": [ - { - "inputs": [ - { - "internalType": "address", - "name": "_factory", - "type": "address" - }, - { - "internalType": "address", - "name": "_WETH9", - "type": "address" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [], - "name": "WETH9", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes", - "name": "path", - "type": "bytes" - }, - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "amountIn", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "amountOutMinimum", - "type": "uint256" - } - ], - "internalType": "struct ISwapRouter.ExactInputParams", - "name": "params", - "type": "tuple" - } - ], - "name": "exactInput", - "outputs": [ - { - "internalType": "uint256", - "name": "amountOut", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "address", - "name": "tokenIn", - "type": "address" - }, - { - "internalType": "address", - "name": "tokenOut", - "type": "address" - }, - { - "internalType": "uint24", - "name": "fee", - "type": "uint24" - }, - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "amountIn", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "amountOutMinimum", - "type": "uint256" - }, - { - "internalType": "uint160", - "name": "sqrtPriceLimitX96", - "type": "uint160" - } - ], - "internalType": "struct ISwapRouter.ExactInputSingleParams", - "name": "params", - "type": "tuple" - } - ], - "name": "exactInputSingle", - "outputs": [ - { - "internalType": "uint256", - "name": "amountOut", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "bytes", - "name": "path", - "type": "bytes" - }, - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "amountOut", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "amountInMaximum", - "type": "uint256" - } - ], - "internalType": "struct ISwapRouter.ExactOutputParams", - "name": "params", - "type": "tuple" - } - ], - "name": "exactOutput", - "outputs": [ - { - "internalType": "uint256", - "name": "amountIn", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { - "internalType": "address", - "name": "tokenIn", - "type": "address" - }, - { - "internalType": "address", - "name": "tokenOut", - "type": "address" - }, - { - "internalType": "uint24", - "name": "fee", - "type": "uint24" - }, - { - "internalType": "address", - "name": "recipient", - "type": "address" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "amountOut", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "amountInMaximum", - "type": "uint256" - }, - { - "internalType": "uint160", - "name": "sqrtPriceLimitX96", - "type": "uint160" - } - ], - "internalType": "struct ISwapRouter.ExactOutputSingleParams", - "name": "params", - "type": "tuple" - } - ], - "name": "exactOutputSingle", - "outputs": [ - { - "internalType": "uint256", - "name": "amountIn", - "type": "uint256" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [], - "name": "factory", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes[]", - "name": "data", - "type": "bytes[]" - } - ], - "name": "multicall", - "outputs": [ - { - "internalType": "bytes[]", - "name": "results", - "type": "bytes[]" - } - ], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "token", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "uint8", - "name": "v", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "r", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "s", - "type": "bytes32" - } - ], - "name": "selfPermit", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "token", - "type": "address" - }, - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "expiry", - "type": "uint256" - }, - { - "internalType": "uint8", - "name": "v", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "r", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "s", - "type": "bytes32" - } - ], - "name": "selfPermitAllowed", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "token", - "type": "address" - }, - { - "internalType": "uint256", - "name": "nonce", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "expiry", - "type": "uint256" - }, - { - "internalType": "uint8", - "name": "v", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "r", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "s", - "type": "bytes32" - } - ], - "name": "selfPermitAllowedIfNecessary", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "token", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "uint8", - "name": "v", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "r", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "s", - "type": "bytes32" - } - ], - "name": "selfPermitIfNecessary", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "token", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amountMinimum", - "type": "uint256" - }, - { - "internalType": "address", - "name": "recipient", - "type": "address" - } - ], - "name": "sweepToken", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "int256", - "name": "amount0Delta", - "type": "int256" - }, - { - "internalType": "int256", - "name": "amount1Delta", - "type": "int256" - }, - { - "internalType": "bytes", - "name": "_data", - "type": "bytes" - } - ], - "name": "uniswapV3SwapCallback", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "amountMinimum", - "type": "uint256" - }, - { - "internalType": "address", - "name": "recipient", - "type": "address" - } - ], - "name": "unwrapWETH9", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "stateMutability": "payable", - "type": "receive" - } - ], - "bytecode": "0x60c06040526000196000553480156200001757600080fd5b5060405162002b3238038062002b328339810160408190526200003a9162000076565b6001600160601b0319606092831b8116608052911b1660a052620000ad565b80516001600160a01b03811681146200007157600080fd5b919050565b6000806040838503121562000089578182fd5b620000948362000059565b9150620000a46020840162000059565b90509250929050565b60805160601c60a05160601c612a34620000fe6000398060fe5280610512528061064252806106dc52806117f5528061185852806118d9525080610b4b528061101952806119db5250612a346000f3fe6080604052600436106100e15760003560e01c8063c2e3140a1161007f578063df2ab5bb11610059578063df2ab5bb14610283578063f28c049814610296578063f3995c67146102a9578063fa461e33146102bc5761018c565b8063c2e3140a14610248578063c45a01551461025b578063db3e2198146102705761018c565b80634aa4a4fc116100bb5780634aa4a4fc146101e0578063a4a78f0c14610202578063ac9650d814610215578063c04b8d59146102355761018c565b8063414bf389146101915780634659a494146101ba57806349404b7c146101cd5761018c565b3661018c573373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461018a57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f4e6f742057455448390000000000000000000000000000000000000000000000604482015290519081900360640190fd5b005b600080fd5b6101a461019f36600461254f565b6102dc565b6040516101b191906128ff565b60405180910390f35b61018a6101c83660046122cd565b61044e565b61018a6101db366004612656565b61050e565b3480156101ec57600080fd5b506101f56106da565b6040516101b19190612745565b61018a6102103660046122cd565b6106fe565b61022861022336600461232d565b6107db565b6040516101b191906127b8565b6101a46102433660046124a4565b610935565b61018a6102563660046122cd565b610a94565b34801561026757600080fd5b506101f5610b49565b6101a461027e36600461254f565b610b6d565b61018a61029136600461228c565b610cfd565b6101a46102a436600461256b565b610e20565b61018a6102b73660046122cd565b610f54565b3480156102c857600080fd5b5061018a6102d73660046123bf565b610fec565b60008160800135806102ec61111b565b111561035957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f5472616e73616374696f6e20746f6f206f6c6400000000000000000000000000604482015290519081900360640190fd5b6103ff60a08401356103716080860160608701612269565b610382610100870160e08801612269565b604080518082019091528061039a60208a018a612269565b6103aa60608b0160408c01612633565b6103ba60408c0160208d01612269565b6040516020016103cc939291906126cf565b60405160208183030381529060405281526020013373ffffffffffffffffffffffffffffffffffffffff1681525061111f565b91508260c00135821015610448576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161043f90612880565b60405180910390fd5b50919050565b604080517f8fcbaf0c00000000000000000000000000000000000000000000000000000000815233600482015230602482015260448101879052606481018690526001608482015260ff851660a482015260c4810184905260e48101839052905173ffffffffffffffffffffffffffffffffffffffff881691638fcbaf0c9161010480830192600092919082900301818387803b1580156104ee57600080fd5b505af1158015610502573d6000803e3d6000fd5b50505050505050505050565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561059757600080fd5b505afa1580156105ab573d6000803e3d6000fd5b505050506040513d60208110156105c157600080fd5b50519050821561063a578281101561063a57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f496e73756666696369656e742057455448390000000000000000000000000000604482015290519081900360640190fd5b80156106d5577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632e1a7d4d826040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b1580156106b357600080fd5b505af11580156106c7573d6000803e3d6000fd5b505050506106d58282611285565b505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b604080517fdd62ed3e00000000000000000000000000000000000000000000000000000000815233600482015230602482015290517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9173ffffffffffffffffffffffffffffffffffffffff89169163dd62ed3e91604480820192602092909190829003018186803b15801561079357600080fd5b505afa1580156107a7573d6000803e3d6000fd5b505050506040513d60208110156107bd57600080fd5b505110156107d3576107d386868686868661044e565b505050505050565b60608167ffffffffffffffff811180156107f457600080fd5b5060405190808252806020026020018201604052801561082857816020015b60608152602001906001900390816108135790505b50905060005b8281101561092e576000803086868581811061084657fe5b90506020028101906108589190612908565b604051610866929190612735565b600060405180830381855af49150503d80600081146108a1576040519150601f19603f3d011682016040523d82523d6000602084013e6108a6565b606091505b50915091508161090c576044815110156108bf57600080fd5b600481019050808060200190518101906108d9919061243a565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161043f9190612836565b8084848151811061091957fe5b6020908102919091010152505060010161082e565b5092915050565b600081604001518061094561111b565b11156109b257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f5472616e73616374696f6e20746f6f206f6c6400000000000000000000000000604482015290519081900360640190fd5b335b60006109c385600001516113d3565b9050610a1c8560600151826109dc5786602001516109de565b305b600060405180604001604052806109f88b600001516113df565b81526020018773ffffffffffffffffffffffffffffffffffffffff1681525061111f565b60608601528015610a3c578451309250610a35906113f4565b8552610a49565b8460600151935050610a4f565b506109b4565b8360800151831015610a8d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161043f90612880565b5050919050565b604080517fdd62ed3e0000000000000000000000000000000000000000000000000000000081523360048201523060248201529051869173ffffffffffffffffffffffffffffffffffffffff89169163dd62ed3e91604480820192602092909190829003018186803b158015610b0957600080fd5b505afa158015610b1d573d6000803e3d6000fd5b505050506040513d6020811015610b3357600080fd5b505110156107d3576107d3868686868686610f54565b7f000000000000000000000000000000000000000000000000000000000000000081565b6000816080013580610b7d61111b565b1115610bea57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f5472616e73616374696f6e20746f6f206f6c6400000000000000000000000000604482015290519081900360640190fd5b610c9360a0840135610c026080860160608701612269565b610c13610100870160e08801612269565b6040518060400160405280886020016020810190610c319190612269565b610c4160608b0160408c01612633565b610c4e60208c018c612269565b604051602001610c60939291906126cf565b60405160208183030381529060405281526020013373ffffffffffffffffffffffffffffffffffffffff16815250611429565b91508260c00135821115610cd3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161043f90612849565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600055919050565b60008373ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015610d6657600080fd5b505afa158015610d7a573d6000803e3d6000fd5b505050506040513d6020811015610d9057600080fd5b505190508215610e095782811015610e0957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f496e73756666696369656e7420746f6b656e0000000000000000000000000000604482015290519081900360640190fd5b8015610e1a57610e1a8483836115c5565b50505050565b6000816040013580610e3061111b565b1115610e9d57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f5472616e73616374696f6e20746f6f206f6c6400000000000000000000000000604482015290519081900360640190fd5b610f106060840135610eb56040860160208701612269565b6040805180820190915260009080610ecd8980612908565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050509082525033602090910152611429565b5060005491508260800135821115610cd3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161043f90612849565b604080517fd505accf000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481018790526064810186905260ff8516608482015260a4810184905260c48101839052905173ffffffffffffffffffffffffffffffffffffffff88169163d505accf9160e480830192600092919082900301818387803b1580156104ee57600080fd5b6000610ffa828401846125a3565b9050600080600061100e84600001516117a1565b9250925092506110407f00000000000000000000000000000000000000000000000000000000000000008484846117d2565b5060008060008a13611081578473ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1610896110b2565b8373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16108a5b9150915081156110d1576110cc85876020015133846117f1565b610502565b85516110dc906113d3565b156111015785516110ec906113f4565b86526110fb8133600089611429565b50610502565b8060008190555083945061050285876020015133846117f1565b4290565b60008060008061113285600001516117a1565b9194509250905073ffffffffffffffffffffffffffffffffffffffff808316908416106000806111638686866119d4565b73ffffffffffffffffffffffffffffffffffffffff1663128acb088b856111898f611a12565b73ffffffffffffffffffffffffffffffffffffffff8e16156111ab578d6111d1565b876111ca5773fffd8963efd1fc6a506488495d951d5263988d256111d1565b6401000276a45b8d6040516020016111e291906128b7565b6040516020818303038152906040526040518663ffffffff1660e01b8152600401611211959493929190612766565b6040805180830381600087803b15801561122a57600080fd5b505af115801561123e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611262919061239c565b91509150826112715781611273565b805b6000039b9a5050505050505050505050565b6040805160008082526020820190925273ffffffffffffffffffffffffffffffffffffffff84169083906040518082805190602001908083835b602083106112fc57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016112bf565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d806000811461135e576040519150601f19603f3d011682016040523d82523d6000602084013e611363565b606091505b50509050806106d557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600360248201527f5354450000000000000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b8051604211155b919050565b60606113ee826000602b611a44565b92915050565b80516060906113ee9083906017907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe901611a44565b60008060008061143c85600001516117a1565b9194509250905073ffffffffffffffffffffffffffffffffffffffff8084169083161060008061146d8587866119d4565b73ffffffffffffffffffffffffffffffffffffffff1663128acb088b856114938f611a12565b60000373ffffffffffffffffffffffffffffffffffffffff8e16156114b8578d6114de565b876114d75773fffd8963efd1fc6a506488495d951d5263988d256114de565b6401000276a45b8d6040516020016114ef91906128b7565b6040516020818303038152906040526040518663ffffffff1660e01b815260040161151e959493929190612766565b6040805180830381600087803b15801561153757600080fd5b505af115801561154b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061156f919061239c565b9150915060008361158457818360000361158a565b82826000035b909850905073ffffffffffffffffffffffffffffffffffffffff8a166115b6578b81146115b657600080fd5b50505050505050949350505050565b6040805173ffffffffffffffffffffffffffffffffffffffff8481166024830152604480830185905283518084039091018152606490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001781529251825160009485949389169392918291908083835b6020831061169a57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161165d565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d80600081146116fc576040519150601f19603f3d011682016040523d82523d6000602084013e611701565b606091505b509150915081801561172f57508051158061172f575080806020019051602081101561172c57600080fd5b50515b61179a57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600260248201527f5354000000000000000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b5050505050565b600080806117af8482611c2b565b92506117bc846014611d2b565b90506117c9846017611c2b565b91509193909250565b60006117e8856117e3868686611e1b565b611e98565b95945050505050565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff161480156118515750814791508110155b1561199a577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b1580156118be57600080fd5b505af11580156118d2573d6000803e3d6000fd5b50505050507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb84846040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b15801561196857600080fd5b505af115801561197c573d6000803e3d6000fd5b505050506040513d602081101561199257600080fd5b5061179a9050565b73ffffffffffffffffffffffffffffffffffffffff84163014156119c8576119c38584846115c5565b61179a565b61179a85858585611ec8565b6000611a0a7f0000000000000000000000000000000000000000000000000000000000000000611a05868686611e1b565b6120a5565b949350505050565b60007f80000000000000000000000000000000000000000000000000000000000000008210611a4057600080fd5b5090565b60608182601f011015611ab857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f736c6963655f6f766572666c6f77000000000000000000000000000000000000604482015290519081900360640190fd5b828284011015611b2957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f736c6963655f6f766572666c6f77000000000000000000000000000000000000604482015290519081900360640190fd5b81830184511015611b9b57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f736c6963655f6f75744f66426f756e6473000000000000000000000000000000604482015290519081900360640190fd5b606082158015611bba5760405191506000825260208201604052611c22565b6040519150601f8416801560200281840101858101878315602002848b0101015b81831015611bf3578051835260209283019201611bdb565b5050858452601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016604052505b50949350505050565b600081826014011015611c9f57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f746f416464726573735f6f766572666c6f770000000000000000000000000000604482015290519081900360640190fd5b8160140183511015611d1257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f746f416464726573735f6f75744f66426f756e64730000000000000000000000604482015290519081900360640190fd5b5001602001516c01000000000000000000000000900490565b600081826003011015611d9f57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f746f55696e7432345f6f766572666c6f77000000000000000000000000000000604482015290519081900360640190fd5b8160030183511015611e1257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f746f55696e7432345f6f75744f66426f756e6473000000000000000000000000604482015290519081900360640190fd5b50016003015190565b611e236121db565b8273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161115611e5b579192915b506040805160608101825273ffffffffffffffffffffffffffffffffffffffff948516815292909316602083015262ffffff169181019190915290565b6000611ea483836120a5565b90503373ffffffffffffffffffffffffffffffffffffffff8216146113ee57600080fd5b6040805173ffffffffffffffffffffffffffffffffffffffff85811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd00000000000000000000000000000000000000000000000000000000178152925182516000948594938a169392918291908083835b60208310611fa557805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101611f68565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114612007576040519150601f19603f3d011682016040523d82523d6000602084013e61200c565b606091505b509150915081801561203a57508051158061203a575080806020019051602081101561203757600080fd5b50515b6107d357604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600360248201527f5354460000000000000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b6000816020015173ffffffffffffffffffffffffffffffffffffffff16826000015173ffffffffffffffffffffffffffffffffffffffff16106120e757600080fd5b508051602080830151604093840151845173ffffffffffffffffffffffffffffffffffffffff94851681850152939091168385015262ffffff166060808401919091528351808403820181526080840185528051908301207fff0000000000000000000000000000000000000000000000000000000000000060a085015294901b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660a183015260b58201939093527fa8180af292c6986c74fa300a542e049db8a89221e2452e431c3d8103b610c56860d5808301919091528251808303909101815260f5909101909152805191012090565b604080516060810182526000808252602082018190529181019190915290565b80356113da81612a02565b600082601f830112612216578081fd5b813561222961222482612996565b612972565b81815284602083860101111561223d578283fd5b816020850160208301379081016020019190915292915050565b60006101008284031215610448578081fd5b60006020828403121561227a578081fd5b813561228581612a02565b9392505050565b6000806000606084860312156122a0578182fd5b83356122ab81612a02565b92506020840135915060408401356122c281612a02565b809150509250925092565b60008060008060008060c087890312156122e5578182fd5b86356122f081612a02565b95506020870135945060408701359350606087013560ff81168114612313578283fd5b9598949750929560808101359460a0909101359350915050565b6000806020838503121561233f578182fd5b823567ffffffffffffffff80821115612356578384fd5b818501915085601f830112612369578384fd5b813581811115612377578485fd5b866020808302850101111561238a578485fd5b60209290920196919550909350505050565b600080604083850312156123ae578182fd5b505080516020909101519092909150565b600080600080606085870312156123d4578384fd5b8435935060208501359250604085013567ffffffffffffffff808211156123f9578384fd5b818701915087601f83011261240c578384fd5b81358181111561241a578485fd5b88602082850101111561242b578485fd5b95989497505060200194505050565b60006020828403121561244b578081fd5b815167ffffffffffffffff811115612461578182fd5b8201601f81018413612471578182fd5b805161247f61222482612996565b818152856020838501011115612493578384fd5b6117e88260208301602086016129d6565b6000602082840312156124b5578081fd5b813567ffffffffffffffff808211156124cc578283fd5b9083019060a082860312156124df578283fd5b60405160a0810181811083821117156124f457fe5b604052823582811115612505578485fd5b61251187828601612206565b825250612520602084016121fb565b602082015260408301356040820152606083013560608201526080830135608082015280935050505092915050565b60006101008284031215612561578081fd5b6122858383612257565b60006020828403121561257c578081fd5b813567ffffffffffffffff811115612592578182fd5b820160a08185031215612285578182fd5b6000602082840312156125b4578081fd5b813567ffffffffffffffff808211156125cb578283fd5b90830190604082860312156125de578283fd5b6040516040810181811083821117156125f357fe5b604052823582811115612604578485fd5b61261087828601612206565b8252506020830135925061262383612a02565b6020810192909252509392505050565b600060208284031215612644578081fd5b813562ffffff81168114612285578182fd5b60008060408385031215612668578182fd5b82359150602083013561267a81612a02565b809150509250929050565b6000815180845261269d8160208601602086016129d6565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b606093841b7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000908116825260e89390931b7fffffff0000000000000000000000000000000000000000000000000000000000166014820152921b166017820152602b0190565b6000828483379101908152919050565b73ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b600073ffffffffffffffffffffffffffffffffffffffff8088168352861515602084015285604084015280851660608401525060a060808301526127ad60a0830184612685565b979650505050505050565b6000602080830181845280855180835260408601915060408482028701019250838701855b82811015612829577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452612817858351612685565b945092850192908501906001016127dd565b5092979650505050505050565b6000602082526122856020830184612685565b60208082526012908201527f546f6f206d756368207265717565737465640000000000000000000000000000604082015260600190565b60208082526013908201527f546f6f206c6974746c6520726563656976656400000000000000000000000000604082015260600190565b6000602082528251604060208401526128d36060840182612685565b905073ffffffffffffffffffffffffffffffffffffffff60208501511660408401528091505092915050565b90815260200190565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261293c578283fd5b83018035915067ffffffffffffffff821115612956578283fd5b60200191503681900382131561296b57600080fd5b9250929050565b60405181810167ffffffffffffffff8111828210171561298e57fe5b604052919050565b600067ffffffffffffffff8211156129aa57fe5b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60005b838110156129f15781810151838201526020016129d9565b83811115610e1a5750506000910152565b73ffffffffffffffffffffffffffffffffffffffff81168114612a2457600080fd5b5056fea164736f6c6343000706000a", - "deployedBytecode": "0x6080604052600436106100e15760003560e01c8063c2e3140a1161007f578063df2ab5bb11610059578063df2ab5bb14610283578063f28c049814610296578063f3995c67146102a9578063fa461e33146102bc5761018c565b8063c2e3140a14610248578063c45a01551461025b578063db3e2198146102705761018c565b80634aa4a4fc116100bb5780634aa4a4fc146101e0578063a4a78f0c14610202578063ac9650d814610215578063c04b8d59146102355761018c565b8063414bf389146101915780634659a494146101ba57806349404b7c146101cd5761018c565b3661018c573373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461018a57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f4e6f742057455448390000000000000000000000000000000000000000000000604482015290519081900360640190fd5b005b600080fd5b6101a461019f36600461254f565b6102dc565b6040516101b191906128ff565b60405180910390f35b61018a6101c83660046122cd565b61044e565b61018a6101db366004612656565b61050e565b3480156101ec57600080fd5b506101f56106da565b6040516101b19190612745565b61018a6102103660046122cd565b6106fe565b61022861022336600461232d565b6107db565b6040516101b191906127b8565b6101a46102433660046124a4565b610935565b61018a6102563660046122cd565b610a94565b34801561026757600080fd5b506101f5610b49565b6101a461027e36600461254f565b610b6d565b61018a61029136600461228c565b610cfd565b6101a46102a436600461256b565b610e20565b61018a6102b73660046122cd565b610f54565b3480156102c857600080fd5b5061018a6102d73660046123bf565b610fec565b60008160800135806102ec61111b565b111561035957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f5472616e73616374696f6e20746f6f206f6c6400000000000000000000000000604482015290519081900360640190fd5b6103ff60a08401356103716080860160608701612269565b610382610100870160e08801612269565b604080518082019091528061039a60208a018a612269565b6103aa60608b0160408c01612633565b6103ba60408c0160208d01612269565b6040516020016103cc939291906126cf565b60405160208183030381529060405281526020013373ffffffffffffffffffffffffffffffffffffffff1681525061111f565b91508260c00135821015610448576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161043f90612880565b60405180910390fd5b50919050565b604080517f8fcbaf0c00000000000000000000000000000000000000000000000000000000815233600482015230602482015260448101879052606481018690526001608482015260ff851660a482015260c4810184905260e48101839052905173ffffffffffffffffffffffffffffffffffffffff881691638fcbaf0c9161010480830192600092919082900301818387803b1580156104ee57600080fd5b505af1158015610502573d6000803e3d6000fd5b50505050505050505050565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561059757600080fd5b505afa1580156105ab573d6000803e3d6000fd5b505050506040513d60208110156105c157600080fd5b50519050821561063a578281101561063a57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f496e73756666696369656e742057455448390000000000000000000000000000604482015290519081900360640190fd5b80156106d5577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632e1a7d4d826040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b1580156106b357600080fd5b505af11580156106c7573d6000803e3d6000fd5b505050506106d58282611285565b505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b604080517fdd62ed3e00000000000000000000000000000000000000000000000000000000815233600482015230602482015290517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9173ffffffffffffffffffffffffffffffffffffffff89169163dd62ed3e91604480820192602092909190829003018186803b15801561079357600080fd5b505afa1580156107a7573d6000803e3d6000fd5b505050506040513d60208110156107bd57600080fd5b505110156107d3576107d386868686868661044e565b505050505050565b60608167ffffffffffffffff811180156107f457600080fd5b5060405190808252806020026020018201604052801561082857816020015b60608152602001906001900390816108135790505b50905060005b8281101561092e576000803086868581811061084657fe5b90506020028101906108589190612908565b604051610866929190612735565b600060405180830381855af49150503d80600081146108a1576040519150601f19603f3d011682016040523d82523d6000602084013e6108a6565b606091505b50915091508161090c576044815110156108bf57600080fd5b600481019050808060200190518101906108d9919061243a565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161043f9190612836565b8084848151811061091957fe5b6020908102919091010152505060010161082e565b5092915050565b600081604001518061094561111b565b11156109b257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f5472616e73616374696f6e20746f6f206f6c6400000000000000000000000000604482015290519081900360640190fd5b335b60006109c385600001516113d3565b9050610a1c8560600151826109dc5786602001516109de565b305b600060405180604001604052806109f88b600001516113df565b81526020018773ffffffffffffffffffffffffffffffffffffffff1681525061111f565b60608601528015610a3c578451309250610a35906113f4565b8552610a49565b8460600151935050610a4f565b506109b4565b8360800151831015610a8d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161043f90612880565b5050919050565b604080517fdd62ed3e0000000000000000000000000000000000000000000000000000000081523360048201523060248201529051869173ffffffffffffffffffffffffffffffffffffffff89169163dd62ed3e91604480820192602092909190829003018186803b158015610b0957600080fd5b505afa158015610b1d573d6000803e3d6000fd5b505050506040513d6020811015610b3357600080fd5b505110156107d3576107d3868686868686610f54565b7f000000000000000000000000000000000000000000000000000000000000000081565b6000816080013580610b7d61111b565b1115610bea57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f5472616e73616374696f6e20746f6f206f6c6400000000000000000000000000604482015290519081900360640190fd5b610c9360a0840135610c026080860160608701612269565b610c13610100870160e08801612269565b6040518060400160405280886020016020810190610c319190612269565b610c4160608b0160408c01612633565b610c4e60208c018c612269565b604051602001610c60939291906126cf565b60405160208183030381529060405281526020013373ffffffffffffffffffffffffffffffffffffffff16815250611429565b91508260c00135821115610cd3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161043f90612849565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600055919050565b60008373ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015610d6657600080fd5b505afa158015610d7a573d6000803e3d6000fd5b505050506040513d6020811015610d9057600080fd5b505190508215610e095782811015610e0957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f496e73756666696369656e7420746f6b656e0000000000000000000000000000604482015290519081900360640190fd5b8015610e1a57610e1a8483836115c5565b50505050565b6000816040013580610e3061111b565b1115610e9d57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f5472616e73616374696f6e20746f6f206f6c6400000000000000000000000000604482015290519081900360640190fd5b610f106060840135610eb56040860160208701612269565b6040805180820190915260009080610ecd8980612908565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050509082525033602090910152611429565b5060005491508260800135821115610cd3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161043f90612849565b604080517fd505accf000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481018790526064810186905260ff8516608482015260a4810184905260c48101839052905173ffffffffffffffffffffffffffffffffffffffff88169163d505accf9160e480830192600092919082900301818387803b1580156104ee57600080fd5b6000610ffa828401846125a3565b9050600080600061100e84600001516117a1565b9250925092506110407f00000000000000000000000000000000000000000000000000000000000000008484846117d2565b5060008060008a13611081578473ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1610896110b2565b8373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16108a5b9150915081156110d1576110cc85876020015133846117f1565b610502565b85516110dc906113d3565b156111015785516110ec906113f4565b86526110fb8133600089611429565b50610502565b8060008190555083945061050285876020015133846117f1565b4290565b60008060008061113285600001516117a1565b9194509250905073ffffffffffffffffffffffffffffffffffffffff808316908416106000806111638686866119d4565b73ffffffffffffffffffffffffffffffffffffffff1663128acb088b856111898f611a12565b73ffffffffffffffffffffffffffffffffffffffff8e16156111ab578d6111d1565b876111ca5773fffd8963efd1fc6a506488495d951d5263988d256111d1565b6401000276a45b8d6040516020016111e291906128b7565b6040516020818303038152906040526040518663ffffffff1660e01b8152600401611211959493929190612766565b6040805180830381600087803b15801561122a57600080fd5b505af115801561123e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611262919061239c565b91509150826112715781611273565b805b6000039b9a5050505050505050505050565b6040805160008082526020820190925273ffffffffffffffffffffffffffffffffffffffff84169083906040518082805190602001908083835b602083106112fc57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016112bf565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d806000811461135e576040519150601f19603f3d011682016040523d82523d6000602084013e611363565b606091505b50509050806106d557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600360248201527f5354450000000000000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b8051604211155b919050565b60606113ee826000602b611a44565b92915050565b80516060906113ee9083906017907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe901611a44565b60008060008061143c85600001516117a1565b9194509250905073ffffffffffffffffffffffffffffffffffffffff8084169083161060008061146d8587866119d4565b73ffffffffffffffffffffffffffffffffffffffff1663128acb088b856114938f611a12565b60000373ffffffffffffffffffffffffffffffffffffffff8e16156114b8578d6114de565b876114d75773fffd8963efd1fc6a506488495d951d5263988d256114de565b6401000276a45b8d6040516020016114ef91906128b7565b6040516020818303038152906040526040518663ffffffff1660e01b815260040161151e959493929190612766565b6040805180830381600087803b15801561153757600080fd5b505af115801561154b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061156f919061239c565b9150915060008361158457818360000361158a565b82826000035b909850905073ffffffffffffffffffffffffffffffffffffffff8a166115b6578b81146115b657600080fd5b50505050505050949350505050565b6040805173ffffffffffffffffffffffffffffffffffffffff8481166024830152604480830185905283518084039091018152606490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001781529251825160009485949389169392918291908083835b6020831061169a57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161165d565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d80600081146116fc576040519150601f19603f3d011682016040523d82523d6000602084013e611701565b606091505b509150915081801561172f57508051158061172f575080806020019051602081101561172c57600080fd5b50515b61179a57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600260248201527f5354000000000000000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b5050505050565b600080806117af8482611c2b565b92506117bc846014611d2b565b90506117c9846017611c2b565b91509193909250565b60006117e8856117e3868686611e1b565b611e98565b95945050505050565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff161480156118515750814791508110155b1561199a577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b1580156118be57600080fd5b505af11580156118d2573d6000803e3d6000fd5b50505050507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb84846040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b15801561196857600080fd5b505af115801561197c573d6000803e3d6000fd5b505050506040513d602081101561199257600080fd5b5061179a9050565b73ffffffffffffffffffffffffffffffffffffffff84163014156119c8576119c38584846115c5565b61179a565b61179a85858585611ec8565b6000611a0a7f0000000000000000000000000000000000000000000000000000000000000000611a05868686611e1b565b6120a5565b949350505050565b60007f80000000000000000000000000000000000000000000000000000000000000008210611a4057600080fd5b5090565b60608182601f011015611ab857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f736c6963655f6f766572666c6f77000000000000000000000000000000000000604482015290519081900360640190fd5b828284011015611b2957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f736c6963655f6f766572666c6f77000000000000000000000000000000000000604482015290519081900360640190fd5b81830184511015611b9b57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f736c6963655f6f75744f66426f756e6473000000000000000000000000000000604482015290519081900360640190fd5b606082158015611bba5760405191506000825260208201604052611c22565b6040519150601f8416801560200281840101858101878315602002848b0101015b81831015611bf3578051835260209283019201611bdb565b5050858452601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016604052505b50949350505050565b600081826014011015611c9f57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f746f416464726573735f6f766572666c6f770000000000000000000000000000604482015290519081900360640190fd5b8160140183511015611d1257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f746f416464726573735f6f75744f66426f756e64730000000000000000000000604482015290519081900360640190fd5b5001602001516c01000000000000000000000000900490565b600081826003011015611d9f57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f746f55696e7432345f6f766572666c6f77000000000000000000000000000000604482015290519081900360640190fd5b8160030183511015611e1257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f746f55696e7432345f6f75744f66426f756e6473000000000000000000000000604482015290519081900360640190fd5b50016003015190565b611e236121db565b8273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161115611e5b579192915b506040805160608101825273ffffffffffffffffffffffffffffffffffffffff948516815292909316602083015262ffffff169181019190915290565b6000611ea483836120a5565b90503373ffffffffffffffffffffffffffffffffffffffff8216146113ee57600080fd5b6040805173ffffffffffffffffffffffffffffffffffffffff85811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd00000000000000000000000000000000000000000000000000000000178152925182516000948594938a169392918291908083835b60208310611fa557805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101611f68565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114612007576040519150601f19603f3d011682016040523d82523d6000602084013e61200c565b606091505b509150915081801561203a57508051158061203a575080806020019051602081101561203757600080fd5b50515b6107d357604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600360248201527f5354460000000000000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b6000816020015173ffffffffffffffffffffffffffffffffffffffff16826000015173ffffffffffffffffffffffffffffffffffffffff16106120e757600080fd5b508051602080830151604093840151845173ffffffffffffffffffffffffffffffffffffffff94851681850152939091168385015262ffffff166060808401919091528351808403820181526080840185528051908301207fff0000000000000000000000000000000000000000000000000000000000000060a085015294901b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660a183015260b58201939093527fa8180af292c6986c74fa300a542e049db8a89221e2452e431c3d8103b610c56860d5808301919091528251808303909101815260f5909101909152805191012090565b604080516060810182526000808252602082018190529181019190915290565b80356113da81612a02565b600082601f830112612216578081fd5b813561222961222482612996565b612972565b81815284602083860101111561223d578283fd5b816020850160208301379081016020019190915292915050565b60006101008284031215610448578081fd5b60006020828403121561227a578081fd5b813561228581612a02565b9392505050565b6000806000606084860312156122a0578182fd5b83356122ab81612a02565b92506020840135915060408401356122c281612a02565b809150509250925092565b60008060008060008060c087890312156122e5578182fd5b86356122f081612a02565b95506020870135945060408701359350606087013560ff81168114612313578283fd5b9598949750929560808101359460a0909101359350915050565b6000806020838503121561233f578182fd5b823567ffffffffffffffff80821115612356578384fd5b818501915085601f830112612369578384fd5b813581811115612377578485fd5b866020808302850101111561238a578485fd5b60209290920196919550909350505050565b600080604083850312156123ae578182fd5b505080516020909101519092909150565b600080600080606085870312156123d4578384fd5b8435935060208501359250604085013567ffffffffffffffff808211156123f9578384fd5b818701915087601f83011261240c578384fd5b81358181111561241a578485fd5b88602082850101111561242b578485fd5b95989497505060200194505050565b60006020828403121561244b578081fd5b815167ffffffffffffffff811115612461578182fd5b8201601f81018413612471578182fd5b805161247f61222482612996565b818152856020838501011115612493578384fd5b6117e88260208301602086016129d6565b6000602082840312156124b5578081fd5b813567ffffffffffffffff808211156124cc578283fd5b9083019060a082860312156124df578283fd5b60405160a0810181811083821117156124f457fe5b604052823582811115612505578485fd5b61251187828601612206565b825250612520602084016121fb565b602082015260408301356040820152606083013560608201526080830135608082015280935050505092915050565b60006101008284031215612561578081fd5b6122858383612257565b60006020828403121561257c578081fd5b813567ffffffffffffffff811115612592578182fd5b820160a08185031215612285578182fd5b6000602082840312156125b4578081fd5b813567ffffffffffffffff808211156125cb578283fd5b90830190604082860312156125de578283fd5b6040516040810181811083821117156125f357fe5b604052823582811115612604578485fd5b61261087828601612206565b8252506020830135925061262383612a02565b6020810192909252509392505050565b600060208284031215612644578081fd5b813562ffffff81168114612285578182fd5b60008060408385031215612668578182fd5b82359150602083013561267a81612a02565b809150509250929050565b6000815180845261269d8160208601602086016129d6565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b606093841b7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000908116825260e89390931b7fffffff0000000000000000000000000000000000000000000000000000000000166014820152921b166017820152602b0190565b6000828483379101908152919050565b73ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b600073ffffffffffffffffffffffffffffffffffffffff8088168352861515602084015285604084015280851660608401525060a060808301526127ad60a0830184612685565b979650505050505050565b6000602080830181845280855180835260408601915060408482028701019250838701855b82811015612829577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452612817858351612685565b945092850192908501906001016127dd565b5092979650505050505050565b6000602082526122856020830184612685565b60208082526012908201527f546f6f206d756368207265717565737465640000000000000000000000000000604082015260600190565b60208082526013908201527f546f6f206c6974746c6520726563656976656400000000000000000000000000604082015260600190565b6000602082528251604060208401526128d36060840182612685565b905073ffffffffffffffffffffffffffffffffffffffff60208501511660408401528091505092915050565b90815260200190565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261293c578283fd5b83018035915067ffffffffffffffff821115612956578283fd5b60200191503681900382131561296b57600080fd5b9250929050565b60405181810167ffffffffffffffff8111828210171561298e57fe5b604052919050565b600067ffffffffffffffff8211156129aa57fe5b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60005b838110156129f15781810151838201526020016129d9565b83811115610e1a5750506000910152565b73ffffffffffffffffffffffffffffffffffffffff81168114612a2457600080fd5b5056fea164736f6c6343000706000a", + "abi": [{"inputs":[{"internalType":"address","name":"_factory","type":"address"},{"internalType":"address","name":"_WETH9","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"WETH9","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes","name":"path","type":"bytes"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMinimum","type":"uint256"}],"internalType":"struct ISwapRouter.ExactInputParams","name":"params","type":"tuple"}],"name":"exactInput","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint24","name":"fee","type":"uint24"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMinimum","type":"uint256"},{"internalType":"uint160","name":"sqrtPriceLimitX96","type":"uint160"}],"internalType":"struct ISwapRouter.ExactInputSingleParams","name":"params","type":"tuple"}],"name":"exactInputSingle","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes","name":"path","type":"bytes"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMaximum","type":"uint256"}],"internalType":"struct ISwapRouter.ExactOutputParams","name":"params","type":"tuple"}],"name":"exactOutput","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint24","name":"fee","type":"uint24"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMaximum","type":"uint256"},{"internalType":"uint160","name":"sqrtPriceLimitX96","type":"uint160"}],"internalType":"struct ISwapRouter.ExactOutputSingleParams","name":"params","type":"tuple"}],"name":"exactOutputSingle","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"refundETH","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"selfPermit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"selfPermitAllowed","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"selfPermitAllowedIfNecessary","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"selfPermitIfNecessary","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"name":"sweepToken","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"feeBips","type":"uint256"},{"internalType":"address","name":"feeRecipient","type":"address"}],"name":"sweepTokenWithFee","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"int256","name":"amount0Delta","type":"int256"},{"internalType":"int256","name":"amount1Delta","type":"int256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"uniswapV3SwapCallback","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"name":"unwrapWETH9","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"feeBips","type":"uint256"},{"internalType":"address","name":"feeRecipient","type":"address"}],"name":"unwrapWETH9WithFee","outputs":[],"stateMutability":"payable","type":"function"},{"stateMutability":"payable","type":"receive"}], + "bytecode": "60c06040526000196000553480156200001757600080fd5b506040516200302f3803806200302f8339810160408190526200003a9162000076565b6001600160601b0319606092831b8116608052911b1660a052620000ad565b80516001600160a01b03811681146200007157600080fd5b919050565b6000806040838503121562000089578182fd5b620000948362000059565b9150620000a46020840162000059565b90509250929050565b60805160601c60a05160601c612f26620001096000398061012f528061058352806106ad5280610747528061078752806108b15280611c435280611ca35280611d24525080610dc6528061140c5280611e265250612f266000f3fe6080604052600436106101125760003560e01c8063c04b8d59116100a5578063df2ab5bb11610074578063f28c049811610059578063f28c0498146102f5578063f3995c6714610308578063fa461e331461031b576101bd565b8063df2ab5bb146102cf578063e0e189a0146102e2576101bd565b8063c04b8d5914610281578063c2e3140a14610294578063c45a0155146102a7578063db3e2198146102bc576101bd565b80634aa4a4fc116100e15780634aa4a4fc146102195780639b2c0a371461023b578063a4a78f0c1461024e578063ac9650d814610261576101bd565b806312210e8a146101c2578063414bf389146101ca5780634659a494146101f357806349404b7c14610206576101bd565b366101bd573373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146101bb57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f4e6f742057455448390000000000000000000000000000000000000000000000604482015290519081900360640190fd5b005b600080fd5b6101bb61033b565b6101dd6101d83660046129f8565b61034d565b6040516101ea9190612df1565b60405180910390f35b6101bb610201366004612776565b6104bf565b6101bb610214366004612aff565b61057f565b34801561022557600080fd5b5061022e610745565b6040516101ea9190612c37565b6101bb610249366004612b2e565b610769565b6101bb61025c366004612776565b610981565b61027461026f3660046127d6565b610a56565b6040516101ea9190612caa565b6101dd61028f36600461294d565b610bb0565b6101bb6102a2366004612776565b610d0f565b3480156102b357600080fd5b5061022e610dc4565b6101dd6102ca3660046129f8565b610de8565b6101bb6102dd3660046126d7565b610f78565b6101bb6102f0366004612718565b611095565b6101dd610303366004612a14565b6111fb565b6101bb610316366004612776565b61132f565b34801561032757600080fd5b506101bb610336366004612868565b6113c7565b471561034b5761034b334761150e565b565b600081608001358061035d61165c565b11156103ca57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f5472616e73616374696f6e20746f6f206f6c6400000000000000000000000000604482015290519081900360640190fd5b61047060a08401356103e260808601606087016126b4565b6103f3610100870160e088016126b4565b604080518082019091528061040b60208a018a6126b4565b61041b60608b0160408c01612adc565b61042b60408c0160208d016126b4565b60405160200161043d93929190612bc1565b60405160208183030381529060405281526020013373ffffffffffffffffffffffffffffffffffffffff16815250611660565b91508260c001358210156104b9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104b090612d72565b60405180910390fd5b50919050565b604080517f8fcbaf0c00000000000000000000000000000000000000000000000000000000815233600482015230602482015260448101879052606481018690526001608482015260ff851660a482015260c4810184905260e48101839052905173ffffffffffffffffffffffffffffffffffffffff881691638fcbaf0c9161010480830192600092919082900301818387803b15801561055f57600080fd5b505af1158015610573573d6000803e3d6000fd5b50505050505050505050565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561060857600080fd5b505afa15801561061c573d6000803e3d6000fd5b505050506040513d602081101561063257600080fd5b50519050828110156106a557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f496e73756666696369656e742057455448390000000000000000000000000000604482015290519081900360640190fd5b8015610740577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632e1a7d4d826040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b15801561071e57600080fd5b505af1158015610732573d6000803e3d6000fd5b50505050610740828261150e565b505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b60008211801561077a575060648211155b61078357600080fd5b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561080c57600080fd5b505afa158015610820573d6000803e3d6000fd5b505050506040513d602081101561083657600080fd5b50519050848110156108a957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f496e73756666696369656e742057455448390000000000000000000000000000604482015290519081900360640190fd5b801561097a577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632e1a7d4d826040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b15801561092257600080fd5b505af1158015610936573d6000803e3d6000fd5b50505050600061271061095285846117e690919063ffffffff16565b8161095957fe5b049050801561096c5761096c838261150e565b6109788582840361150e565b505b5050505050565b604080517fdd62ed3e00000000000000000000000000000000000000000000000000000000815233600482015230602482015290517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9173ffffffffffffffffffffffffffffffffffffffff89169163dd62ed3e91604480820192602092909190829003018186803b158015610a1657600080fd5b505afa158015610a2a573d6000803e3d6000fd5b505050506040513d6020811015610a4057600080fd5b50511015610978576109788686868686866104bf565b60608167ffffffffffffffff81118015610a6f57600080fd5b50604051908082528060200260200182016040528015610aa357816020015b6060815260200190600190039081610a8e5790505b50905060005b82811015610ba95760008030868685818110610ac157fe5b9050602002810190610ad39190612dfa565b604051610ae1929190612c27565b600060405180830381855af49150503d8060008114610b1c576040519150601f19603f3d011682016040523d82523d6000602084013e610b21565b606091505b509150915081610b8757604481511015610b3a57600080fd5b60048101905080806020019051810190610b5491906128e3565b6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104b09190612d28565b80848481518110610b9457fe5b60209081029190910101525050600101610aa9565b5092915050565b6000816040015180610bc061165c565b1115610c2d57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f5472616e73616374696f6e20746f6f206f6c6400000000000000000000000000604482015290519081900360640190fd5b335b6000610c3e8560000151611810565b9050610c97856060015182610c57578660200151610c59565b305b60006040518060400160405280610c738b6000015161181c565b81526020018773ffffffffffffffffffffffffffffffffffffffff16815250611660565b60608601528015610cb7578451309250610cb09061182b565b8552610cc4565b8460600151935050610cca565b50610c2f565b8360800151831015610d08576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104b090612d72565b5050919050565b604080517fdd62ed3e0000000000000000000000000000000000000000000000000000000081523360048201523060248201529051869173ffffffffffffffffffffffffffffffffffffffff89169163dd62ed3e91604480820192602092909190829003018186803b158015610d8457600080fd5b505afa158015610d98573d6000803e3d6000fd5b505050506040513d6020811015610dae57600080fd5b505110156109785761097886868686868661132f565b7f000000000000000000000000000000000000000000000000000000000000000081565b6000816080013580610df861165c565b1115610e6557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f5472616e73616374696f6e20746f6f206f6c6400000000000000000000000000604482015290519081900360640190fd5b610f0e60a0840135610e7d60808601606087016126b4565b610e8e610100870160e088016126b4565b6040518060400160405280886020016020810190610eac91906126b4565b610ebc60608b0160408c01612adc565b610ec960208c018c6126b4565b604051602001610edb93929190612bc1565b60405160208183030381529060405281526020013373ffffffffffffffffffffffffffffffffffffffff16815250611860565b91508260c00135821115610f4e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104b090612d3b565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600055919050565b60008373ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015610fe157600080fd5b505afa158015610ff5573d6000803e3d6000fd5b505050506040513d602081101561100b57600080fd5b505190508281101561107e57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f496e73756666696369656e7420746f6b656e0000000000000000000000000000604482015290519081900360640190fd5b801561108f5761108f848383611a1c565b50505050565b6000821180156110a6575060648211155b6110af57600080fd5b60008573ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561111857600080fd5b505afa15801561112c573d6000803e3d6000fd5b505050506040513d602081101561114257600080fd5b50519050848110156111b557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f496e73756666696369656e7420746f6b656e0000000000000000000000000000604482015290519081900360640190fd5b80156109785760006127106111ca83866117e6565b816111d157fe5b04905080156111e5576111e5878483611a1c565b6111f28786838503611a1c565b50505050505050565b600081604001358061120b61165c565b111561127857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f5472616e73616374696f6e20746f6f206f6c6400000000000000000000000000604482015290519081900360640190fd5b6112eb606084013561129060408601602087016126b4565b60408051808201909152600090806112a88980612dfa565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050509082525033602090910152611860565b5060005491508260800135821115610f4e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104b090612d3b565b604080517fd505accf000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481018790526064810186905260ff8516608482015260a4810184905260c48101839052905173ffffffffffffffffffffffffffffffffffffffff88169163d505accf9160e480830192600092919082900301818387803b15801561055f57600080fd5b60008413806113d65750600083135b6113df57600080fd5b60006113ed82840184612a4c565b905060008060006114018460000151611bf1565b9250925092506114337f0000000000000000000000000000000000000000000000000000000000000000848484611c22565b5060008060008a13611474578473ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1610896114a5565b8373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16108a5b9150915081156114c4576114bf8587602001513384611c41565b610573565b85516114cf90611810565b156114f45785516114df9061182b565b86526114ee8133600089611860565b50610573565b806000819055508394506105738587602001513384611c41565b6040805160008082526020820190925273ffffffffffffffffffffffffffffffffffffffff84169083906040518082805190602001908083835b6020831061158557805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101611548565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d80600081146115e7576040519150601f19603f3d011682016040523d82523d6000602084013e6115ec565b606091505b505090508061074057604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600360248201527f5354450000000000000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b4290565b600073ffffffffffffffffffffffffffffffffffffffff8416611681573093505b60008060006116938560000151611bf1565b9194509250905073ffffffffffffffffffffffffffffffffffffffff808316908416106000806116c4868686611e1f565b73ffffffffffffffffffffffffffffffffffffffff1663128acb088b856116ea8f611e5d565b73ffffffffffffffffffffffffffffffffffffffff8e161561170c578d611732565b8761172b5773fffd8963efd1fc6a506488495d951d5263988d25611732565b6401000276a45b8d6040516020016117439190612da9565b6040516020818303038152906040526040518663ffffffff1660e01b8152600401611772959493929190612c58565b6040805180830381600087803b15801561178b57600080fd5b505af115801561179f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117c39190612845565b91509150826117d257816117d4565b805b6000039b9a5050505050505050505050565b6000821580611801575050818102818382816117fe57fe5b04145b61180a57600080fd5b92915050565b8051604211155b919050565b606061180a826000602b611e8f565b805160609061180a9083906017907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe901611e8f565b600073ffffffffffffffffffffffffffffffffffffffff8416611881573093505b60008060006118938560000151611bf1565b9194509250905073ffffffffffffffffffffffffffffffffffffffff808416908316106000806118c4858786611e1f565b73ffffffffffffffffffffffffffffffffffffffff1663128acb088b856118ea8f611e5d565b60000373ffffffffffffffffffffffffffffffffffffffff8e161561190f578d611935565b8761192e5773fffd8963efd1fc6a506488495d951d5263988d25611935565b6401000276a45b8d6040516020016119469190612da9565b6040516020818303038152906040526040518663ffffffff1660e01b8152600401611975959493929190612c58565b6040805180830381600087803b15801561198e57600080fd5b505af11580156119a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119c69190612845565b915091506000836119db5781836000036119e1565b82826000035b909850905073ffffffffffffffffffffffffffffffffffffffff8a16611a0d578b8114611a0d57600080fd5b50505050505050949350505050565b6040805173ffffffffffffffffffffffffffffffffffffffff8481166024830152604480830185905283518084039091018152606490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001781529251825160009485949389169392918291908083835b60208310611af157805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101611ab4565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114611b53576040519150601f19603f3d011682016040523d82523d6000602084013e611b58565b606091505b5091509150818015611b86575080511580611b865750808060200190516020811015611b8357600080fd5b50515b61097a57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600260248201527f5354000000000000000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b60008080611bff8482612076565b9250611c0c846014612176565b9050611c19846017612076565b91509193909250565b6000611c3885611c33868686612266565b6122e3565b95945050505050565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16148015611c9c5750804710155b15611de5577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015611d0957600080fd5b505af1158015611d1d573d6000803e3d6000fd5b50505050507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663a9059cbb83836040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b158015611db357600080fd5b505af1158015611dc7573d6000803e3d6000fd5b505050506040513d6020811015611ddd57600080fd5b5061108f9050565b73ffffffffffffffffffffffffffffffffffffffff8316301415611e1357611e0e848383611a1c565b61108f565b61108f84848484612313565b6000611e557f0000000000000000000000000000000000000000000000000000000000000000611e50868686612266565b6124f0565b949350505050565b60007f80000000000000000000000000000000000000000000000000000000000000008210611e8b57600080fd5b5090565b60608182601f011015611f0357604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f736c6963655f6f766572666c6f77000000000000000000000000000000000000604482015290519081900360640190fd5b828284011015611f7457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f736c6963655f6f766572666c6f77000000000000000000000000000000000000604482015290519081900360640190fd5b81830184511015611fe657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f736c6963655f6f75744f66426f756e6473000000000000000000000000000000604482015290519081900360640190fd5b606082158015612005576040519150600082526020820160405261206d565b6040519150601f8416801560200281840101858101878315602002848b0101015b8183101561203e578051835260209283019201612026565b5050858452601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016604052505b50949350505050565b6000818260140110156120ea57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f746f416464726573735f6f766572666c6f770000000000000000000000000000604482015290519081900360640190fd5b816014018351101561215d57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f746f416464726573735f6f75744f66426f756e64730000000000000000000000604482015290519081900360640190fd5b5001602001516c01000000000000000000000000900490565b6000818260030110156121ea57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f746f55696e7432345f6f766572666c6f77000000000000000000000000000000604482015290519081900360640190fd5b816003018351101561225d57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f746f55696e7432345f6f75744f66426f756e6473000000000000000000000000604482015290519081900360640190fd5b50016003015190565b61226e612626565b8273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1611156122a6579192915b506040805160608101825273ffffffffffffffffffffffffffffffffffffffff948516815292909316602083015262ffffff169181019190915290565b60006122ef83836124f0565b90503373ffffffffffffffffffffffffffffffffffffffff82161461180a57600080fd5b6040805173ffffffffffffffffffffffffffffffffffffffff85811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd00000000000000000000000000000000000000000000000000000000178152925182516000948594938a169392918291908083835b602083106123f057805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016123b3565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114612452576040519150601f19603f3d011682016040523d82523d6000602084013e612457565b606091505b5091509150818015612485575080511580612485575080806020019051602081101561248257600080fd5b50515b61097857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600360248201527f5354460000000000000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b6000816020015173ffffffffffffffffffffffffffffffffffffffff16826000015173ffffffffffffffffffffffffffffffffffffffff161061253257600080fd5b508051602080830151604093840151845173ffffffffffffffffffffffffffffffffffffffff94851681850152939091168385015262ffffff166060808401919091528351808403820181526080840185528051908301207fff0000000000000000000000000000000000000000000000000000000000000060a085015294901b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660a183015260b58201939093527fe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b5460d5808301919091528251808303909101815260f5909101909152805191012090565b604080516060810182526000808252602082018190529181019190915290565b803561181781612ef4565b600082601f830112612661578081fd5b813561267461266f82612e88565b612e64565b818152846020838601011115612688578283fd5b816020850160208301379081016020019190915292915050565b600061010082840312156104b9578081fd5b6000602082840312156126c5578081fd5b81356126d081612ef4565b9392505050565b6000806000606084860312156126eb578182fd5b83356126f681612ef4565b925060208401359150604084013561270d81612ef4565b809150509250925092565b600080600080600060a0868803121561272f578081fd5b853561273a81612ef4565b945060208601359350604086013561275181612ef4565b925060608601359150608086013561276881612ef4565b809150509295509295909350565b60008060008060008060c0878903121561278e578081fd5b863561279981612ef4565b95506020870135945060408701359350606087013560ff811681146127bc578182fd5b9598949750929560808101359460a0909101359350915050565b600080602083850312156127e8578182fd5b823567ffffffffffffffff808211156127ff578384fd5b818501915085601f830112612812578384fd5b813581811115612820578485fd5b8660208083028501011115612833578485fd5b60209290920196919550909350505050565b60008060408385031215612857578182fd5b505080516020909101519092909150565b6000806000806060858703121561287d578182fd5b8435935060208501359250604085013567ffffffffffffffff808211156128a2578384fd5b818701915087601f8301126128b5578384fd5b8135818111156128c3578485fd5b8860208285010111156128d4578485fd5b95989497505060200194505050565b6000602082840312156128f4578081fd5b815167ffffffffffffffff81111561290a578182fd5b8201601f8101841361291a578182fd5b805161292861266f82612e88565b81815285602083850101111561293c578384fd5b611c38826020830160208601612ec8565b60006020828403121561295e578081fd5b813567ffffffffffffffff80821115612975578283fd5b9083019060a08286031215612988578283fd5b60405160a08101818110838211171561299d57fe5b6040528235828111156129ae578485fd5b6129ba87828601612651565b8252506129c960208401612646565b602082015260408301356040820152606083013560608201526080830135608082015280935050505092915050565b60006101008284031215612a0a578081fd5b6126d083836126a2565b600060208284031215612a25578081fd5b813567ffffffffffffffff811115612a3b578182fd5b820160a081850312156126d0578182fd5b600060208284031215612a5d578081fd5b813567ffffffffffffffff80821115612a74578283fd5b9083019060408286031215612a87578283fd5b604051604081018181108382111715612a9c57fe5b604052823582811115612aad578485fd5b612ab987828601612651565b82525060208301359250612acc83612ef4565b6020810192909252509392505050565b600060208284031215612aed578081fd5b813562ffffff811681146126d0578182fd5b60008060408385031215612b11578182fd5b823591506020830135612b2381612ef4565b809150509250929050565b60008060008060808587031215612b43578182fd5b843593506020850135612b5581612ef4565b9250604085013591506060850135612b6c81612ef4565b939692955090935050565b60008151808452612b8f816020860160208601612ec8565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b606093841b7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000908116825260e89390931b7fffffff0000000000000000000000000000000000000000000000000000000000166014820152921b166017820152602b0190565b6000828483379101908152919050565b73ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b600073ffffffffffffffffffffffffffffffffffffffff8088168352861515602084015285604084015280851660608401525060a06080830152612c9f60a0830184612b77565b979650505050505050565b6000602080830181845280855180835260408601915060408482028701019250838701855b82811015612d1b577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452612d09858351612b77565b94509285019290850190600101612ccf565b5092979650505050505050565b6000602082526126d06020830184612b77565b60208082526012908201527f546f6f206d756368207265717565737465640000000000000000000000000000604082015260600190565b60208082526013908201527f546f6f206c6974746c6520726563656976656400000000000000000000000000604082015260600190565b600060208252825160406020840152612dc56060840182612b77565b905073ffffffffffffffffffffffffffffffffffffffff60208501511660408401528091505092915050565b90815260200190565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112612e2e578283fd5b83018035915067ffffffffffffffff821115612e48578283fd5b602001915036819003821315612e5d57600080fd5b9250929050565b60405181810167ffffffffffffffff81118282101715612e8057fe5b604052919050565b600067ffffffffffffffff821115612e9c57fe5b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60005b83811015612ee3578181015183820152602001612ecb565b8381111561108f5750506000910152565b73ffffffffffffffffffffffffffffffffffffffff81168114612f1657600080fd5b5056fea164736f6c6343000706000a", + "deployedBytecode": "", "linkReferences": {}, "deployedLinkReferences": {} -} +} \ No newline at end of file From 464f71f0d18b9733c547ef52ca43407ff784d497 Mon Sep 17 00:00:00 2001 From: alpha-guy Date: Sun, 20 Jun 2021 16:20:49 +0530 Subject: [PATCH 15/16] Add integration tests with GIM * Trade DAI for WETH on UniswapV3 during rebalance * Trade WETH for WBTC on UniswapV3 during rebalance --- .../modules/generalIndexModule.spec.ts | 188 ++++++++++++++++-- 1 file changed, 172 insertions(+), 16 deletions(-) diff --git a/test/protocol/modules/generalIndexModule.spec.ts b/test/protocol/modules/generalIndexModule.spec.ts index c63045390..dc7865fa0 100644 --- a/test/protocol/modules/generalIndexModule.spec.ts +++ b/test/protocol/modules/generalIndexModule.spec.ts @@ -1,10 +1,17 @@ import "module-alias/register"; import { BigNumber } from "@ethersproject/bignumber"; +import { hexlify, hexZeroPad } from "ethers/lib/utils"; import { Address, StreamingFeeState } from "@utils/types"; import { Account } from "@utils/test/types"; import { ADDRESS_ZERO, MAX_UINT_256, PRECISE_UNIT, THREE, ZERO, ONE_DAY_IN_SECONDS } from "@utils/constants"; -import { BalancerV1IndexExchangeAdapter, ContractCallerMock, GeneralIndexModule, SetToken, UniswapV2IndexExchangeAdapter } from "@utils/contracts"; +import { + BalancerV1IndexExchangeAdapter, + ContractCallerMock, + GeneralIndexModule, + SetToken, + UniswapV2IndexExchangeAdapter, + UniswapV3IndexExchangeAdapter } from "@utils/contracts"; import DeployHelper from "@utils/deploys"; import { bitcoin, @@ -23,9 +30,10 @@ import { getRandomAddress, getSystemFixture, getUniswapFixture, + getUniswapV3Fixture, getWaffleExpect } from "@utils/test/index"; -import { BalancerFixture, SystemFixture, UniswapFixture } from "@utils/fixtures"; +import { BalancerFixture, SystemFixture, UniswapFixture, UniswapV3Fixture } from "@utils/fixtures"; import { ContractTransaction } from "ethers"; const expect = getWaffleExpect(); @@ -40,17 +48,21 @@ describe("GeneralIndexModule", () => { let uniswapSetup: UniswapFixture; let sushiswapSetup: UniswapFixture; let balancerSetup: BalancerFixture; + let uniswapV3Setup: UniswapV3Fixture; let index: SetToken; let indexWithWeth: SetToken; let indexModule: GeneralIndexModule; - let balancerExchangeAdapter: BalancerV1IndexExchangeAdapter; let balancerAdapterName: string; - let sushiswapExchangeAdapter: UniswapV2IndexExchangeAdapter; let sushiswapAdapterName: string; - let uniswapExchangeAdapter: UniswapV2IndexExchangeAdapter; let uniswapAdapterName: string; + let uniswapV3AdapterName: string; + + let balancerExchangeAdapter: BalancerV1IndexExchangeAdapter; + let sushiswapExchangeAdapter: UniswapV2IndexExchangeAdapter; + let uniswapExchangeAdapter: UniswapV2IndexExchangeAdapter; + let uniswapV3ExchangeAdapter: UniswapV3IndexExchangeAdapter; let indexComponents: Address[]; let indexUnits: BigNumber[]; @@ -71,11 +83,20 @@ describe("GeneralIndexModule", () => { uniswapSetup = getUniswapFixture(owner.address); sushiswapSetup = getUniswapFixture(owner.address); balancerSetup = getBalancerFixture(owner.address); + uniswapV3Setup = getUniswapV3Fixture(owner.address); await setup.initialize(); await uniswapSetup.initialize(owner, setup.weth.address, setup.wbtc.address, setup.dai.address); await sushiswapSetup.initialize(owner, setup.weth.address, setup.wbtc.address, setup.dai.address); await balancerSetup.initialize(owner, setup.weth, setup.wbtc, setup.dai); + await uniswapV3Setup.initialize( + owner, + setup.weth, + 230, + setup.wbtc, + 9000, + setup.dai + ); indexModule = await deployer.modules.deployGeneralIndexModule( setup.controller.address, @@ -87,19 +108,22 @@ describe("GeneralIndexModule", () => { balancerExchangeAdapter = await deployer.adapters.deployBalancerV1IndexExchangeAdapter(balancerSetup.exchange.address); sushiswapExchangeAdapter = await deployer.adapters.deployUniswapV2IndexExchangeAdapter(sushiswapSetup.router.address); uniswapExchangeAdapter = await deployer.adapters.deployUniswapV2IndexExchangeAdapter(uniswapSetup.router.address); + uniswapV3ExchangeAdapter = await deployer.adapters.deployUniswapV3IndexExchangeAdapter(uniswapV3Setup.swapRouter.address); balancerAdapterName = "BALANCER"; sushiswapAdapterName = "SUSHISWAP"; uniswapAdapterName = "UNISWAP"; + uniswapV3AdapterName = "UNISWAPV3"; await setup.integrationRegistry.batchAddIntegration( - [indexModule.address, indexModule.address, indexModule.address], - [balancerAdapterName, sushiswapAdapterName, uniswapAdapterName], + [indexModule.address, indexModule.address, indexModule.address, indexModule.address], + [balancerAdapterName, sushiswapAdapterName, uniswapAdapterName, uniswapV3AdapterName], [ balancerExchangeAdapter.address, sushiswapExchangeAdapter.address, uniswapExchangeAdapter.address, + uniswapV3ExchangeAdapter.address, ] ); }); @@ -142,21 +166,21 @@ describe("GeneralIndexModule", () => { await setup.streamingFeeModule.initialize(indexWithWeth.address, feeSettingsForIndexWithWeth); await setup.issuanceModule.initialize(indexWithWeth.address, ADDRESS_ZERO); - await setup.weth.connect(owner.wallet).approve(uniswapSetup.router.address, ether(2000)); - await uniswapSetup.uni.connect(owner.wallet).approve(uniswapSetup.router.address, ether(400000)); + await setup.weth.connect(owner.wallet).approve(uniswapSetup.router.address, ether(1000)); + await uniswapSetup.uni.connect(owner.wallet).approve(uniswapSetup.router.address, ether(200000)); await uniswapSetup.router.connect(owner.wallet).addLiquidity( setup.weth.address, uniswapSetup.uni.address, - ether(2000), - ether(400000), - ether(1485), - ether(173000), + ether(1000), + ether(200000), + ether(999), + ether(199000), owner.address, MAX_UINT_256 ); await setup.weth.connect(owner.wallet).approve(sushiswapSetup.router.address, ether(1000)); - await setup.wbtc.connect(owner.wallet).approve(sushiswapSetup.router.address, ether(26)); + await setup.wbtc.connect(owner.wallet).approve(sushiswapSetup.router.address, bitcoin(26)); await sushiswapSetup.router.addLiquidity( setup.weth.address, setup.wbtc.address, @@ -167,6 +191,28 @@ describe("GeneralIndexModule", () => { owner.address, MAX_UINT_256 ); + + await setup.weth.connect(owner.wallet).approve(uniswapV3Setup.nftPositionManager.address, ether(1000)); + await setup.wbtc.connect(owner.wallet).approve(uniswapV3Setup.nftPositionManager.address, bitcoin(26)); + await uniswapV3Setup.addLiquidityWide( + setup.weth, + setup.wbtc, + 3000, + ether(1000), + bitcoin(26), + owner.address + ); + + await setup.weth.connect(owner.wallet).approve(uniswapV3Setup.nftPositionManager.address, ether(100)); + await setup.dai.connect(owner.wallet).approve(uniswapV3Setup.nftPositionManager.address, bitcoin(23000)); + await uniswapV3Setup.addLiquidityWide( + setup.weth, + setup.dai, + 3000, + ether(100), + bitcoin(23000), + owner.address + ); }); describe("#constructor", async () => { @@ -914,13 +960,13 @@ describe("GeneralIndexModule", () => { describe("when the component is being bought using Sushiswap", async () => { beforeEach(async () => { - await subject(); + await subject(); // sell DAI for ETH, next use ETH to buy WBTC on sushiswap subjectComponent = setup.wbtc.address; subjectEthQuantityLimit = MAX_UINT_256; }); - it("the position units and lastTradeTimestamp should be set as expected", async () => {0; + it("the position units and lastTradeTimestamp should be set as expected", async () => { const [expectedIn, expectedOut] = await sushiswapSetup.router.getAmountsIn( bitcoin(.1), [setup.weth.address, setup.wbtc.address] @@ -969,6 +1015,116 @@ describe("GeneralIndexModule", () => { }); }); + describe("when exchange is Uniswap V3", async () => { + describe("when component is beling sold using UniswapV3", async () => { + beforeEach(async () => { + await indexModule.setExchanges(subjectSetToken.address, [setup.dai.address], [uniswapV3AdapterName]); + await indexModule.setExchangeData(subjectSetToken.address, [setup.dai.address], [hexZeroPad(hexlify(3000), 3)]); + + expectedOut = await uniswapV3Setup.quoter.callStatic.quoteExactInputSingle( + setup.dai.address, + setup.weth.address, + 3000, + ether(1000), + 0 + ); + + subjectEthQuantityLimit = expectedOut; + }); + + afterEach(async () => { + await indexModule.setExchanges(subjectSetToken.address, [setup.dai.address], [sushiswapAdapterName]); + }); + + it("the position units and lastTradeTimestamp should be set as expected", async () => { + const currentDaiAmount = await setup.dai.balanceOf(subjectSetToken.address); + const currentWethAmount = await setup.weth.balanceOf(subjectSetToken.address); + const totalSupply = await subjectSetToken.totalSupply(); + + await subject(); + + const lastBlockTimestamp = await getLastBlockTimestamp(); + + const expectedWethPositionUnits = preciseDiv(currentWethAmount.add(expectedOut), totalSupply); + const expectedDaiPositionUnits = preciseDiv(currentDaiAmount.sub(ether(1000)), totalSupply); + + const wethPositionUnits = await subjectSetToken.getDefaultPositionRealUnit(setup.weth.address); + const daiPositionUnits = await subjectSetToken.getDefaultPositionRealUnit(setup.dai.address); + + const lastTrade = (await indexModule.executionInfo(subjectSetToken.address, setup.dai.address)).lastTradeTimestamp; + + expect(wethPositionUnits).to.eq(expectedWethPositionUnits); + expect(daiPositionUnits).to.eq(expectedDaiPositionUnits); + expect(lastTrade).to.eq(lastBlockTimestamp); + }); + + it("emits the correct TradeExecuted event", async () => { + await expect(subject()).to.emit(indexModule, "TradeExecuted").withArgs( + subjectSetToken.address, + setup.dai.address, + setup.weth.address, + uniswapV3ExchangeAdapter.address, + trader.address, + ether(1000), + expectedOut, + ZERO + ); + }); + }); + + describe("when component is being bought using UniswapV3", async () => { + beforeEach(async () => { + await subject(); // sell DAI for ETH on Balancer, as we would need ETH to buy WBTC on UniswapV3 + + await indexModule.setExchanges(subjectSetToken.address, [setup.wbtc.address], [uniswapV3AdapterName]); + await indexModule.setExchangeData(subjectSetToken.address, [setup.wbtc.address], [hexZeroPad(hexlify(3000), 3)]); + + subjectComponent = setup.wbtc.address; + subjectEthQuantityLimit = MAX_UINT_256; + }); + + afterEach(async () => { + await indexModule.setExchanges(subjectSetToken.address, [setup.wbtc.address], [sushiswapAdapterName]); + }); + + it("the position units and lastTradeTimestamp should be set as expected", async () => { + const amountOut = bitcoin(0.1); + const expectedIn = await uniswapV3Setup.quoter.callStatic.quoteExactOutputSingle( + setup.weth.address, + setup.wbtc.address, + 3000, + amountOut, + 0 + ); + + const currentWbtcAmount = await setup.wbtc.balanceOf(subjectSetToken.address); + const currentWethAmount = await setup.weth.balanceOf(subjectSetToken.address); + + const wethUnit = await subjectSetToken.getDefaultPositionRealUnit(setup.weth.address); + const wbtcUnit = await subjectSetToken.getDefaultPositionRealUnit(setup.wbtc.address); + const totalSupply = await subjectSetToken.totalSupply(); + + await subject(); + + const lastBlockTimestamp = await getLastBlockTimestamp(); + + const wbtcExcess = currentWbtcAmount.sub(preciseMul(totalSupply, wbtcUnit)); + const wethExcess = currentWethAmount.sub(preciseMul(totalSupply, wethUnit)); + + const expectedWethPositionUnits = preciseDiv(currentWethAmount.sub(expectedIn).sub(wethExcess), totalSupply); + const expectedWbtcPositionUnits = preciseDiv(currentWbtcAmount.add(amountOut).sub(wbtcExcess), totalSupply); + + const wethPositionUnits = await subjectSetToken.getDefaultPositionRealUnit(setup.weth.address); + const wbtcPositionUnits = await subjectSetToken.getDefaultPositionRealUnit(setup.wbtc.address); + const lastTrade = (await indexModule.executionInfo(subjectSetToken.address, setup.wbtc.address)).lastTradeTimestamp; + + expect(wbtcPositionUnits).to.eq(expectedWbtcPositionUnits); + expect(wethPositionUnits).to.eq(expectedWethPositionUnits); + expect(lastTrade).to.eq(lastBlockTimestamp); + }); + }); + }); + describe("when exchange doesn't return minimum receive eth amount, while selling component", async () => { beforeEach(async () => { expectedOut = (await balancerSetup.exchange.viewSplitExactIn( From 78b26d525639b3bc3a3d387cf97797113df61afa Mon Sep 17 00:00:00 2001 From: alpha-guy Date: Sun, 20 Jun 2021 16:24:12 +0530 Subject: [PATCH 16/16] Fix comment --- test/protocol/modules/generalIndexModule.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/protocol/modules/generalIndexModule.spec.ts b/test/protocol/modules/generalIndexModule.spec.ts index dc7865fa0..dd38150c3 100644 --- a/test/protocol/modules/generalIndexModule.spec.ts +++ b/test/protocol/modules/generalIndexModule.spec.ts @@ -960,7 +960,7 @@ describe("GeneralIndexModule", () => { describe("when the component is being bought using Sushiswap", async () => { beforeEach(async () => { - await subject(); // sell DAI for ETH, next use ETH to buy WBTC on sushiswap + await subject(); // sell DAI for ETH on Balancer, as we would need ETH to buy WBTC on Sushiswap subjectComponent = setup.wbtc.address; subjectEthQuantityLimit = MAX_UINT_256;