From 695df38fa0cf226bcd0f9d21b98e0e7048bcbed3 Mon Sep 17 00:00:00 2001 From: Poli Paul Date: Tue, 13 Jul 2021 20:51:28 +0200 Subject: [PATCH 01/33] Add PancakeMasterChefRouter --- assets/bsc/PancakeMasterChef.json | 277 +++++++++++ assets/bsc/PancakeSyrupPool.json | 307 ++++++++++++ contracts/interfaces/IPancakeMasterChef.sol | 13 + contracts/interfaces/sushi/IMasterChefV1.sol | 11 + .../AbstractMasterChefIndexRouter.sol | 98 ++++ .../MasterChefPowerIndexRouter.sol | 61 +++ .../PancakeMasterChefPowerIndexRouter.sol | 61 +++ .../test/sushi/MockPancakeMasterChef.sol | 13 + test/helpers/builders.js | 6 + test/helpers/index.js | 18 +- .../PancakeMasterChefRouter.unit.js | 437 ++++++++++++++++++ 11 files changed, 1299 insertions(+), 3 deletions(-) create mode 100644 assets/bsc/PancakeMasterChef.json create mode 100644 assets/bsc/PancakeSyrupPool.json create mode 100644 contracts/interfaces/IPancakeMasterChef.sol create mode 100644 contracts/interfaces/sushi/IMasterChefV1.sol create mode 100644 contracts/powerindex-router/implementations/AbstractMasterChefIndexRouter.sol create mode 100644 contracts/powerindex-router/implementations/MasterChefPowerIndexRouter.sol create mode 100644 contracts/powerindex-router/implementations/PancakeMasterChefPowerIndexRouter.sol create mode 100644 contracts/test/sushi/MockPancakeMasterChef.sol create mode 100644 test/router/implementations/PancakeMasterChefRouter.unit.js diff --git a/assets/bsc/PancakeMasterChef.json b/assets/bsc/PancakeMasterChef.json new file mode 100644 index 00000000..cba04452 --- /dev/null +++ b/assets/bsc/PancakeMasterChef.json @@ -0,0 +1,277 @@ +{ + "bytecode": "60806040526001600555600060095534801561001a57600080fd5b506040516125b73803806125b7833981810160405260a081101561003d57600080fd5b5080516020820151604083015160608401516080909401519293919290919060006100666101e0565b600080546001600160a01b0319166001600160a01b0383169081178255604051929350917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a350600180546001600160a01b03199081166001600160a01b03978816908117835560028054831697891697909717909655600380548216958816959095179094556004928355600a829055604080516080810182529586526103e86020870181815291870193845260006060880181815260078054958601815590915296517fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c688939095029283018054909616949097169390931790935590517fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c689830155517fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c68a82015590517fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c68b909101556009556101e4565b3390565b6123c4806101f36000396000f3fe608060405234801561001057600080fd5b50600436106101cf5760003560e01c80635ffe6146116101045780638d88a90e116100a2578063d49e77cd11610071578063d49e77cd146104b1578063dce17484146104b9578063e2bbb158146104c1578063f2fde38b146104e4576101cf565b80638d88a90e1461041b5780638da5cb5b146104415780638dbb1e3a1461044957806393f1a40b1461046c576101cf565b8063715018a6116100de578063715018a6146103df5780637cd07e47146103e757806386a952c41461040b5780638aa2855014610413576101cf565b80635ffe61461461038f578063630b5ba1146103ac57806364482f79146103b4576101cf565b806323cf311811610171578063454b06081161014b578063454b06081461033057806348cd4cb11461034d57806351eb05a6146103555780635312ea8e14610372576101cf565b806323cf3118146102ca57806341441d3b146102f0578063441a3e701461030d576101cf565b80631175a1dd116101ad5780631175a1dd146102155780631526fe271461024157806317caf6f11461028e5780631eaaa04514610296576101cf565b80630755e0b6146101d4578063081e3eda146101ee5780631058d281146101f6575b600080fd5b6101dc61050a565b60408051918252519081900360200190f35b6101dc610510565b6102136004803603602081101561020c57600080fd5b5035610516565b005b6101dc6004803603604081101561022b57600080fd5b50803590602001356001600160a01b031661071e565b61025e6004803603602081101561025757600080fd5b50356108a1565b604080516001600160a01b0390951685526020850193909352838301919091526060830152519081900360800190f35b6101dc6108e2565b610213600480360360608110156102ac57600080fd5b508035906001600160a01b03602082013516906040013515156108e8565b610213600480360360208110156102e057600080fd5b50356001600160a01b0316610a98565b6102136004803603602081101561030657600080fd5b5035610b3c565b6102136004803603604081101561032357600080fd5b5080359060200135610ce9565b6102136004803603602081101561034657600080fd5b5035610e99565b6101dc611172565b6102136004803603602081101561036b57600080fd5b5035611178565b6102136004803603602081101561038857600080fd5b50356113d0565b610213600480360360208110156103a557600080fd5b503561146b565b6102136114da565b610213600480360360608110156103ca57600080fd5b508035906020810135906040013515156114fd565b61021361160d565b6103ef6116d9565b604080516001600160a01b039092168252519081900360200190f35b6103ef6116e8565b6101dc6116f7565b6102136004803603602081101561043157600080fd5b50356001600160a01b03166116fd565b6103ef611796565b6101dc6004803603604081101561045f57600080fd5b50803590602001356117a5565b6104986004803603604081101561048257600080fd5b50803590602001356001600160a01b03166117c0565b6040805192835260208301919091528051918290030190f35b6103ef6117e4565b6103ef6117f3565b610213600480360360408110156104d757600080fd5b5080359060200135611802565b610213600480360360208110156104fa57600080fd5b50356001600160a01b0316611966565b60045481565b60075490565b6000600760008154811061052657fe5b600091825260208083203384527f5eff886ea0ce6ca488a3d6e336d6c0f75f46d19b42c06ce5ee98e42c96d256c790915260409092208054600490920290920192508311156105bc576040805162461bcd60e51b815260206004820152601260248201527f77697468647261773a206e6f7420676f6f640000000000000000000000000000604482015290519081900360640190fd5b6105c66000611178565b600061060082600101546105fa64e8d4a510006105f4876003015487600001546119d990919063ffffffff16565b90611a32565b90611a74565b90508015610612576106123382611ab6565b831561063c5781546106249085611a74565b8255825461063c906001600160a01b03163386611b40565b600383015482546106579164e8d4a51000916105f4916119d9565b6001830155600254604080517f9dc29fac0000000000000000000000000000000000000000000000000000000081523360048201526024810187905290516001600160a01b0390921691639dc29fac9160448082019260009290919082900301818387803b1580156106c857600080fd5b505af11580156106dc573d6000803e3d6000fd5b5050604080518781529051600093503392507ff279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b5689181900360200190a350505050565b6000806007848154811061072e57fe5b600091825260208083208784526008825260408085206001600160a01b03898116875290845281862060049586029093016003810154815484517f70a082310000000000000000000000000000000000000000000000000000000081523098810198909852935191985093969395939492909116926370a08231926024808301939192829003018186803b1580156107c557600080fd5b505afa1580156107d9573d6000803e3d6000fd5b505050506040513d60208110156107ef57600080fd5b505160028501549091504311801561080657508015155b1561086c57600061081b8560020154436117a5565b905060006108486009546105f48860010154610842600454876119d990919063ffffffff16565b906119d9565b9050610867610860846105f48464e8d4a510006119d9565b8590611bc5565b935050505b61089483600101546105fa64e8d4a510006105f48688600001546119d990919063ffffffff16565b9450505050505b92915050565b600781815481106108ae57fe5b600091825260209091206004909102018054600182015460028301546003909301546001600160a01b039092169350919084565b60095481565b6108f0611c1f565b6000546001600160a01b03908116911614610952576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b8015610960576109606114da565b6000600a54431161097357600a54610975565b435b6009549091506109859085611bc5565b600955604080516080810182526001600160a01b0385811682526020820187815292820184815260006060840181815260078054600181018255925293517fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c688600490920291820180547fffffffffffffffffffffffff000000000000000000000000000000000000000016919094161790925592517fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c68982015591517fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c68a830155517fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c68b90910155610a92611c23565b50505050565b610aa0611c1f565b6000546001600160a01b03908116911614610b02576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b600680547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b60006007600081548110610b4c57fe5b600091825260208083203384527f5eff886ea0ce6ca488a3d6e336d6c0f75f46d19b42c06ce5ee98e42c96d256c790915260408320600490920201925090610b9390611178565b805415610bdc576000610bc882600101546105fa64e8d4a510006105f4876003015487600001546119d990919063ffffffff16565b90508015610bda57610bda3382611ab6565b505b8215610c08578154610bf9906001600160a01b0316333086611cc5565b8054610c059084611bc5565b81555b60038201548154610c239164e8d4a51000916105f4916119d9565b6001820155600254604080517f40c10f190000000000000000000000000000000000000000000000000000000081523360048201526024810186905290516001600160a01b03909216916340c10f199160448082019260009290919082900301818387803b158015610c9457600080fd5b505af1158015610ca8573d6000803e3d6000fd5b5050604080518681529051600093503392507f90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a159181900360200190a3505050565b81610d3b576040805162461bcd60e51b815260206004820152601a60248201527f77697468647261772043414b4520627920756e7374616b696e67000000000000604482015290519081900360640190fd5b600060078381548110610d4a57fe5b600091825260208083208684526008825260408085203386529092529220805460049092029092019250831115610dc8576040805162461bcd60e51b815260206004820152601260248201527f77697468647261773a206e6f7420676f6f640000000000000000000000000000604482015290519081900360640190fd5b610dd184611178565b6000610dff82600101546105fa64e8d4a510006105f4876003015487600001546119d990919063ffffffff16565b90508015610e1157610e113382611ab6565b8315610e3b578154610e239085611a74565b82558254610e3b906001600160a01b03163386611b40565b60038301548254610e569164e8d4a51000916105f4916119d9565b6001830155604080518581529051869133917ff279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b5689181900360200190a35050505050565b6006546001600160a01b0316610ef6576040805162461bcd60e51b815260206004820152601460248201527f6d6967726174653a206e6f206d69677261746f72000000000000000000000000604482015290519081900360640190fd5b600060078281548110610f0557fe5b600091825260208083206004928302018054604080517f70a082310000000000000000000000000000000000000000000000000000000081523095810195909552519195506001600160a01b0316939284926370a0823192602480840193829003018186803b158015610f7757600080fd5b505afa158015610f8b573d6000803e3d6000fd5b505050506040513d6020811015610fa157600080fd5b5051600654909150610fc0906001600160a01b03848116911683611d4d565b600654604080517fce5494bb0000000000000000000000000000000000000000000000000000000081526001600160a01b0385811660048301529151600093929092169163ce5494bb9160248082019260209290919082900301818787803b15801561102b57600080fd5b505af115801561103f573d6000803e3d6000fd5b505050506040513d602081101561105557600080fd5b5051604080517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015290519192506001600160a01b038316916370a0823191602480820192602092909190829003018186803b1580156110ba57600080fd5b505afa1580156110ce573d6000803e3d6000fd5b505050506040513d60208110156110e457600080fd5b50518214611139576040805162461bcd60e51b815260206004820152600c60248201527f6d6967726174653a206261640000000000000000000000000000000000000000604482015290519081900360640190fd5b83547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b039190911617909255505050565b600a5481565b60006007828154811061118757fe5b90600052602060002090600402019050806002015443116111a857506113cd565b8054604080517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015290516000926001600160a01b0316916370a08231916024808301926020929190829003018186803b15801561120b57600080fd5b505afa15801561121f573d6000803e3d6000fd5b505050506040513d602081101561123557600080fd5b505190508061124b5750436002909101556113cd565b600061125b8360020154436117a5565b905060006112826009546105f48660010154610842600454876119d990919063ffffffff16565b6001546003549192506001600160a01b03908116916340c10f1991166112a984600a611a32565b6040518363ffffffff1660e01b815260040180836001600160a01b0316815260200182815260200192505050600060405180830381600087803b1580156112ef57600080fd5b505af1158015611303573d6000803e3d6000fd5b5050600154600254604080517f40c10f190000000000000000000000000000000000000000000000000000000081526001600160a01b0392831660048201526024810187905290519190921693506340c10f199250604480830192600092919082900301818387803b15801561137857600080fd5b505af115801561138c573d6000803e3d6000fd5b505050506113ba6113af846105f464e8d4a51000856119d990919063ffffffff16565b600386015490611bc5565b6003850155505043600290920191909155505b50565b6000600782815481106113df57fe5b60009182526020808320858452600882526040808520338087529352909320805460049093029093018054909450611424926001600160a01b03919091169190611b40565b80546040805191825251849133917fbb757047c2b5f3974fe26b7c10f732e7bce710b0952a71082702781e62ae05959181900360200190a360008082556001909101555050565b611473611c1f565b6000546001600160a01b039081169116146114d5576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b600555565b60075460005b818110156114f9576114f181611178565b6001016114e0565b5050565b611505611c1f565b6000546001600160a01b03908116911614611567576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b8015611575576115756114da565b6115b2826115ac6007868154811061158957fe5b906000526020600020906004020160010154600954611a7490919063ffffffff16565b90611bc5565b6009819055506000600784815481106115c757fe5b906000526020600020906004020160010154905082600785815481106115e957fe5b906000526020600020906004020160010181905550828114610a9257610a92611c23565b611615611c1f565b6000546001600160a01b03908116911614611677576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b600080546040516001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055565b6006546001600160a01b031681565b6002546001600160a01b031681565b60055481565b6003546001600160a01b0316331461175c576040805162461bcd60e51b815260206004820152600960248201527f6465763a207775743f0000000000000000000000000000000000000000000000604482015290519081900360640190fd5b600380547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b6000546001600160a01b031690565b6005546000906117b9906108428486611a74565b9392505050565b60086020908152600092835260408084209091529082529020805460019091015482565b6003546001600160a01b031681565b6001546001600160a01b031681565b81611854576040805162461bcd60e51b815260206004820152601760248201527f6465706f7369742043414b45206279207374616b696e67000000000000000000604482015290519081900360640190fd5b60006007838154811061186357fe5b6000918252602080832086845260088252604080852033865290925292206004909102909101915061189484611178565b8054156118dd5760006118c982600101546105fa64e8d4a510006105f4876003015487600001546119d990919063ffffffff16565b905080156118db576118db3382611ab6565b505b82156119095781546118fa906001600160a01b0316333086611cc5565b80546119069084611bc5565b81555b600382015481546119249164e8d4a51000916105f4916119d9565b6001820155604080518481529051859133917f90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a159181900360200190a350505050565b61196e611c1f565b6000546001600160a01b039081169116146119d0576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6113cd81611ea7565b6000826119e85750600061089b565b828202828482816119f557fe5b04146117b95760405162461bcd60e51b81526004018080602001828103825260218152602001806123386021913960400191505060405180910390fd5b60006117b983836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250611f5f565b60006117b983836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250612001565b600254604080517fa2e6ddcc0000000000000000000000000000000000000000000000000000000081526001600160a01b038581166004830152602482018590529151919092169163a2e6ddcc91604480830192600092919082900301818387803b158015611b2457600080fd5b505af1158015611b38573d6000803e3d6000fd5b505050505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052611bc090849061205b565b505050565b6000828201838110156117b9576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b3390565b600754600060015b82811015611c6e57611c6460078281548110611c4357fe5b90600052602060002090600402016001015483611bc590919063ffffffff16565b9150600101611c2b565b5080156114f957611c80816003611a32565b9050611c97816115ac600760008154811061158957fe5b600981905550806007600081548110611cac57fe5b9060005260206000209060040201600101819055505050565b604080516001600160a01b0380861660248301528416604482015260648082018490528251808303909101815260849091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd00000000000000000000000000000000000000000000000000000000179052610a9290859061205b565b801580611dec5750604080517fdd62ed3e0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b03848116602483015291519185169163dd62ed3e91604480820192602092909190829003018186803b158015611dbe57600080fd5b505afa158015611dd2573d6000803e3d6000fd5b505050506040513d6020811015611de857600080fd5b5051155b611e275760405162461bcd60e51b81526004018080602001828103825260368152602001806123596036913960400191505060405180910390fd5b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b300000000000000000000000000000000000000000000000000000000179052611bc090849061205b565b6001600160a01b038116611eec5760405162461bcd60e51b81526004018080602001828103825260268152602001806123126026913960400191505060405180910390fd5b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b60008183611feb5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015611fb0578181015183820152602001611f98565b50505050905090810190601f168015611fdd5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b506000838581611ff757fe5b0495945050505050565b600081848411156120535760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315611fb0578181015183820152602001611f98565b505050900390565b60606120b0826040518060400160405280602081526020017f5361666542455032303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661210c9092919063ffffffff16565b805190915015611bc0578080602001905160208110156120cf57600080fd5b5051611bc05760405162461bcd60e51b815260040180806020018281038252602a8152602001806122e8602a913960400191505060405180910390fd5b606061211b8484600085612123565b949350505050565b606061212e856122ae565b61217f576040805162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015290519081900360640190fd5b60006060866001600160a01b031685876040518082805190602001908083835b602083106121dc57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161219f565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d806000811461223e576040519150601f19603f3d011682016040523d82523d6000602084013e612243565b606091505b5091509150811561225757915061211b9050565b8051156122675780518082602001fd5b60405162461bcd60e51b8152602060048201818152865160248401528651879391928392604401919085019080838360008315611fb0578181015183820152602001611f98565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47081811480159061211b57505015159291505056fe5361666542455032303a204245503230206f7065726174696f6e20646964206e6f7420737563636565644f776e61626c653a206e6577206f776e657220697320746865207a65726f2061646472657373536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f775361666542455032303a20617070726f76652066726f6d206e6f6e2d7a65726f20746f206e6f6e2d7a65726f20616c6c6f77616e6365a2646970667358221220077495f6efd1597cf54586cb058707bf146388300d17c943ece392463f56203964736f6c634300060c0033", + "abi": [ + { + "inputs": [ + { "internalType": "contract CakeToken", "name": "_cake", "type": "address" }, + { "internalType": "contract SyrupBar", "name": "_syrup", "type": "address" }, + { "internalType": "address", "name": "_devaddr", "type": "address" }, + { "internalType": "uint256", "name": "_cakePerBlock", "type": "uint256" }, + { "internalType": "uint256", "name": "_startBlock", "type": "uint256" } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "user", "type": "address" }, + { "indexed": true, "internalType": "uint256", "name": "pid", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "Deposit", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "user", "type": "address" }, + { "indexed": true, "internalType": "uint256", "name": "pid", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "EmergencyWithdraw", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "previousOwner", "type": "address" }, + { "indexed": true, "internalType": "address", "name": "newOwner", "type": "address" } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "user", "type": "address" }, + { "indexed": true, "internalType": "uint256", "name": "pid", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "Withdraw", + "type": "event" + }, + { + "inputs": [], + "name": "BONUS_MULTIPLIER", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "_allocPoint", "type": "uint256" }, + { "internalType": "contract IBEP20", "name": "_lpToken", "type": "address" }, + { "internalType": "bool", "name": "_withUpdate", "type": "bool" } + ], + "name": "add", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "cake", + "outputs": [{ "internalType": "contract CakeToken", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "cakePerBlock", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "_pid", "type": "uint256" }, + { "internalType": "uint256", "name": "_amount", "type": "uint256" } + ], + "name": "deposit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "_devaddr", "type": "address" }], + "name": "dev", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "devaddr", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint256", "name": "_pid", "type": "uint256" }], + "name": "emergencyWithdraw", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint256", "name": "_amount", "type": "uint256" }], + "name": "enterStaking", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "_from", "type": "uint256" }, + { "internalType": "uint256", "name": "_to", "type": "uint256" } + ], + "name": "getMultiplier", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint256", "name": "_amount", "type": "uint256" }], + "name": "leaveStaking", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { "inputs": [], "name": "massUpdatePools", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [{ "internalType": "uint256", "name": "_pid", "type": "uint256" }], + "name": "migrate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "migrator", + "outputs": [{ "internalType": "contract IMigratorChef", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "_pid", "type": "uint256" }, + { "internalType": "address", "name": "_user", "type": "address" } + ], + "name": "pendingCake", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "name": "poolInfo", + "outputs": [ + { "internalType": "contract IBEP20", "name": "lpToken", "type": "address" }, + { "internalType": "uint256", "name": "allocPoint", "type": "uint256" }, + { "internalType": "uint256", "name": "lastRewardBlock", "type": "uint256" }, + { "internalType": "uint256", "name": "accCakePerShare", "type": "uint256" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "poolLength", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { "inputs": [], "name": "renounceOwnership", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { "internalType": "uint256", "name": "_pid", "type": "uint256" }, + { "internalType": "uint256", "name": "_allocPoint", "type": "uint256" }, + { "internalType": "bool", "name": "_withUpdate", "type": "bool" } + ], + "name": "set", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "contract IMigratorChef", "name": "_migrator", "type": "address" }], + "name": "setMigrator", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "startBlock", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "syrup", + "outputs": [{ "internalType": "contract SyrupBar", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalAllocPoint", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "newOwner", "type": "address" }], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint256", "name": "multiplierNumber", "type": "uint256" }], + "name": "updateMultiplier", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint256", "name": "_pid", "type": "uint256" }], + "name": "updatePool", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "", "type": "uint256" }, + { "internalType": "address", "name": "", "type": "address" } + ], + "name": "userInfo", + "outputs": [ + { "internalType": "uint256", "name": "amount", "type": "uint256" }, + { "internalType": "uint256", "name": "rewardDebt", "type": "uint256" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "_pid", "type": "uint256" }, + { "internalType": "uint256", "name": "_amount", "type": "uint256" } + ], + "name": "withdraw", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ] +} diff --git a/assets/bsc/PancakeSyrupPool.json b/assets/bsc/PancakeSyrupPool.json new file mode 100644 index 00000000..5da4722a --- /dev/null +++ b/assets/bsc/PancakeSyrupPool.json @@ -0,0 +1,307 @@ +{ + "bytecode": "60806040523480156200001157600080fd5b50604051620022e9380380620022e9833981810160405260208110156200003757600080fd5b5051604080518082018252600e81526d29bcb93ab82130b9102a37b5b2b760911b60208281019190915282518084019093526005835264053595255560dc1b908301529060006200008762000136565b600080546001600160a01b0319166001600160a01b0383169081178255604051929350917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a3508151620000e69060049060208501906200013a565b508051620000fc9060059060208401906200013a565b5050600680546001600160a01b0390931661010002610100600160a81b031960ff19909416601217939093169290921790915550620001d6565b3390565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106200017d57805160ff1916838001178555620001ad565b82800160010185558215620001ad579182015b82811115620001ad57825182559160200191906001019062000190565b50620001bb929150620001bf565b5090565b5b80821115620001bb5760008155600101620001c0565b61210380620001e66000396000f3fe608060405234801561001057600080fd5b50600436106101da5760003560e01c8063893d20e811610104578063a9059cbb116100a2578063dd62ed3e11610071578063dd62ed3e146105ed578063e7a324dc1461061b578063f1127ed814610623578063f2fde38b14610675576101da565b8063a9059cbb1461054c578063b4b5ea5714610578578063c3cda5201461059e578063dce17484146105e5576101da565b80639dc29fac116100de5780639dc29fac146104ab578063a0712d68146104d7578063a2e6ddcc146104f4578063a457c2d714610520576101da565b8063893d20e8146104935780638da5cb5b1461049b57806395d89b41146104a3576101da565b806340c10f191161017c57806370a082311161014b57806370a0823114610413578063715018a614610439578063782d6fe1146104415780637ecebe001461046d576101da565b806340c10f191461033e578063587cde1e1461036c5780635c19a95c146103ae5780636fcfff45146103d4576101da565b806320606b70116101b857806320606b70146102b657806323b872dd146102be578063313ce567146102f45780633950935114610312576101da565b806306fdde03146101df578063095ea7b31461025c57806318160ddd1461029c575b600080fd5b6101e761069b565b6040805160208082528351818301528351919283929083019185019080838360005b83811015610221578181015183820152602001610209565b50505050905090810190601f16801561024e5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6102886004803603604081101561027257600080fd5b506001600160a01b038135169060200135610731565b604080519115158252519081900360200190f35b6102a461074f565b60408051918252519081900360200190f35b6102a4610755565b610288600480360360608110156102d457600080fd5b506001600160a01b03813581169160208101359091169060400135610779565b6102fc610800565b6040805160ff9092168252519081900360200190f35b6102886004803603604081101561032857600080fd5b506001600160a01b038135169060200135610809565b61036a6004803603604081101561035457600080fd5b506001600160a01b038135169060200135610857565b005b6103926004803603602081101561038257600080fd5b50356001600160a01b03166108f4565b604080516001600160a01b039092168252519081900360200190f35b61036a600480360360208110156103c457600080fd5b50356001600160a01b0316610912565b6103fa600480360360208110156103ea57600080fd5b50356001600160a01b031661091f565b6040805163ffffffff9092168252519081900360200190f35b6102a46004803603602081101561042957600080fd5b50356001600160a01b0316610937565b61036a610952565b6102a46004803603604081101561045757600080fd5b506001600160a01b038135169060200135610a1e565b6102a46004803603602081101561048357600080fd5b50356001600160a01b0316610c26565b610392610c38565b610392610c47565b6101e7610c56565b61036a600480360360408110156104c157600080fd5b506001600160a01b038135169060200135610cb7565b610288600480360360208110156104ed57600080fd5b5035610d2b565b61036a6004803603604081101561050a57600080fd5b506001600160a01b038135169060200135610db0565b6102886004803603604081101561053657600080fd5b506001600160a01b038135169060200135611007565b6102886004803603604081101561056257600080fd5b506001600160a01b03813516906020013561106f565b6102a46004803603602081101561058e57600080fd5b50356001600160a01b0316611083565b61036a600480360360c08110156105b457600080fd5b506001600160a01b038135169060208101359060408101359060ff6060820135169060808101359060a001356110e7565b6103926113b1565b6102a46004803603604081101561060357600080fd5b506001600160a01b03813581169160200135166113c5565b6102a46113f0565b6106556004803603604081101561063957600080fd5b5080356001600160a01b0316906020013563ffffffff16611414565b6040805163ffffffff909316835260208301919091528051918290030190f35b61036a6004803603602081101561068b57600080fd5b50356001600160a01b0316611441565b60048054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156107275780601f106106fc57610100808354040283529160200191610727565b820191906000526020600020905b81548152906001019060200180831161070a57829003601f168201915b5050505050905090565b600061074561073e6114b4565b84846114b8565b5060015b92915050565b60035490565b7f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a86681565b60006107868484846115a4565b6107f6846107926114b4565b6107f185604051806060016040528060288152602001611f30602891396001600160a01b038a166000908152600260205260408120906107d06114b4565b6001600160a01b0316815260208101919091526040016000205491906116f6565b6114b8565b5060019392505050565b60065460ff1690565b60006107456108166114b4565b846107f185600260006108276114b4565b6001600160a01b03908116825260208083019390935260409182016000908120918c16815292529020549061178d565b61085f6114b4565b6000546001600160a01b039081169116146108c1576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6108cb82826117e7565b6001600160a01b038083166000908152600760205260408120546108f09216836118cd565b5050565b6001600160a01b039081166000908152600760205260409020541690565b61091c3382611a0a565b50565b60096020526000908152604090205463ffffffff1681565b6001600160a01b031660009081526001602052604090205490565b61095a6114b4565b6000546001600160a01b039081169116146109bc576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b600080546040516001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055565b6000438210610a5e5760405162461bcd60e51b8152600401808060200182810382526027815260200180611fb26027913960400191505060405180910390fd5b6001600160a01b03831660009081526009602052604090205463ffffffff1680610a8c576000915050610749565b6001600160a01b038416600090815260086020908152604080832063ffffffff600019860181168552925290912054168310610afb576001600160a01b03841660009081526008602090815260408083206000199490940163ffffffff16835292905220600101549050610749565b6001600160a01b038416600090815260086020908152604080832083805290915290205463ffffffff16831015610b36576000915050610749565b600060001982015b8163ffffffff168163ffffffff161115610bef57600282820363ffffffff16048103610b68611e83565b506001600160a01b038716600090815260086020908152604080832063ffffffff808616855290835292819020815180830190925280549093168082526001909301549181019190915290871415610bca576020015194506107499350505050565b805163ffffffff16871115610be157819350610be8565b6001820392505b5050610b3e565b506001600160a01b038516600090815260086020908152604080832063ffffffff9094168352929052206001015491505092915050565b600a6020526000908152604090205481565b6000610c42610c47565b905090565b6000546001600160a01b031690565b60058054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156107275780601f106106fc57610100808354040283529160200191610727565b610cbf6114b4565b6000546001600160a01b03908116911614610d21576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6108cb8282611ab7565b6000610d356114b4565b6000546001600160a01b03908116911614610d97576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b610da8610da26114b4565b836117e7565b506001919050565b610db86114b4565b6000546001600160a01b03908116911614610e1a576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b600654604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905160009261010090046001600160a01b0316916370a08231916024808301926020929190829003018186803b158015610e8357600080fd5b505afa158015610e97573d6000803e3d6000fd5b505050506040513d6020811015610ead57600080fd5b5051905080821115610f6057600654604080517fa9059cbb0000000000000000000000000000000000000000000000000000000081526001600160a01b0386811660048301526024820185905291516101009093049091169163a9059cbb916044808201926020929091908290030181600087803b158015610f2e57600080fd5b505af1158015610f42573d6000803e3d6000fd5b505050506040513d6020811015610f5857600080fd5b506110029050565b600654604080517fa9059cbb0000000000000000000000000000000000000000000000000000000081526001600160a01b0386811660048301526024820186905291516101009093049091169163a9059cbb916044808201926020929091908290030181600087803b158015610fd557600080fd5b505af1158015610fe9573d6000803e3d6000fd5b505050506040513d6020811015610fff57600080fd5b50505b505050565b60006107456110146114b4565b846107f185604051806060016040528060258152602001612044602591396002600061103e6114b4565b6001600160a01b03908116825260208083019390935260409182016000908120918d168152925290205491906116f6565b600061074561107c6114b4565b84846115a4565b6001600160a01b03811660009081526009602052604081205463ffffffff16806110ae5760006110e0565b6001600160a01b038316600090815260086020908152604080832063ffffffff60001986011684529091529020600101545b9392505050565b60007f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a86661111261069b565b80519060200120611121611ba7565b60408051602080820195909552808201939093526060830191909152306080808401919091528151808403909101815260a0830182528051908401207fe48329057bfd03d55e49b547132e39cffd9c1820ad7b9d4c5307691425d15adf60c08401526001600160a01b038b1660e084015261010083018a90526101208084018a905282518085039091018152610140840183528051908501207f19010000000000000000000000000000000000000000000000000000000000006101608501526101628401829052610182808501829052835180860390910181526101a285018085528151918701919091206000918290526101c2860180865281905260ff8b166101e287015261020286018a905261022286018990529351929650909492939092600192610242808401937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08301929081900390910190855afa15801561128d573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001519150506001600160a01b0381166112fd5760405162461bcd60e51b8152600401808060200182810382526026815260200180611f586026913960400191505060405180910390fd5b6001600160a01b0381166000908152600a60205260409020805460018101909155891461135b5760405162461bcd60e51b8152600401808060200182810382526022815260200180611fff6022913960400191505060405180910390fd5b8742111561139a5760405162461bcd60e51b8152600401808060200182810382526026815260200180611f0a6026913960400191505060405180910390fd5b6113a4818b611a0a565b505050505b505050505050565b60065461010090046001600160a01b031681565b6001600160a01b03918216600090815260026020908152604080832093909416825291909152205490565b7fe48329057bfd03d55e49b547132e39cffd9c1820ad7b9d4c5307691425d15adf81565b60086020908152600092835260408084209091529082529020805460019091015463ffffffff9091169082565b6114496114b4565b6000546001600160a01b039081169116146114ab576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b61091c81611bab565b3390565b6001600160a01b0383166114fd5760405162461bcd60e51b8152600401808060200182810382526024815260200180611ec06024913960400191505060405180910390fd5b6001600160a01b0382166115425760405162461bcd60e51b81526004018080602001828103825260228152602001806120ac6022913960400191505060405180910390fd5b6001600160a01b03808416600081815260026020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b6001600160a01b0383166115e95760405162461bcd60e51b8152600401808060200182810382526025815260200180611e9b6025913960400191505060405180910390fd5b6001600160a01b03821661162e5760405162461bcd60e51b81526004018080602001828103825260238152602001806120216023913960400191505060405180910390fd5b61166b81604051806060016040528060268152602001611fd9602691396001600160a01b03861660009081526001602052604090205491906116f6565b6001600160a01b03808516600090815260016020526040808220939093559084168152205461169a908261178d565b6001600160a01b0380841660008181526001602090815260409182902094909455805185815290519193928716927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a3505050565b600081848411156117855760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561174a578181015183820152602001611732565b50505050905090810190601f1680156117775780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b6000828201838110156110e0576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b6001600160a01b038216611842576040805162461bcd60e51b815260206004820152601f60248201527f42455032303a206d696e7420746f20746865207a65726f206164647265737300604482015290519081900360640190fd5b60035461184f908261178d565b6003556001600160a01b038216600090815260016020526040902054611875908261178d565b6001600160a01b03831660008181526001602090815260408083209490945583518581529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35050565b816001600160a01b0316836001600160a01b0316141580156118ef5750600081115b15611002576001600160a01b03831615611981576001600160a01b03831660009081526009602052604081205463ffffffff16908161192f576000611961565b6001600160a01b038516600090815260086020908152604080832063ffffffff60001987011684529091529020600101545b9050600061196f8285611c63565b905061197d86848484611ca5565b5050505b6001600160a01b03821615611002576001600160a01b03821660009081526009602052604081205463ffffffff1690816119bc5760006119ee565b6001600160a01b038416600090815260086020908152604080832063ffffffff60001987011684529091529020600101545b905060006119fc828561178d565b90506113a985848484611ca5565b6001600160a01b0380831660009081526007602052604081205490911690611a3184610937565b6001600160a01b0385811660008181526007602052604080822080547fffffffffffffffffffffffff000000000000000000000000000000000000000016898616908117909155905194955093928616927f3134e8a2e6d97e929a7e54011ea5485d7d196dd5f0ba4d4ef95803e8e3fc257f9190a4611ab18284836118cd565b50505050565b6001600160a01b038216611afc5760405162461bcd60e51b81526004018080602001828103825260218152602001806120696021913960400191505060405180910390fd5b611b398160405180606001604052806022815260200161208a602291396001600160a01b03851660009081526001602052604090205491906116f6565b6001600160a01b038316600090815260016020526040902055600354611b5f9082611c63565b6003556040805182815290516000916001600160a01b038516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9181900360200190a35050565b4690565b6001600160a01b038116611bf05760405162461bcd60e51b8152600401808060200182810382526026815260200180611ee46026913960400191505060405180910390fd5b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b60006110e083836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506116f6565b6000611cc943604051806060016040528060348152602001611f7e60349139611e25565b905060008463ffffffff16118015611d1257506001600160a01b038516600090815260086020908152604080832063ffffffff6000198901811685529252909120548282169116145b15611d4f576001600160a01b038516600090815260086020908152604080832063ffffffff60001989011684529091529020600101829055611ddb565b60408051808201825263ffffffff808416825260208083018681526001600160a01b038a166000818152600884528681208b861682528452868120955186549086167fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000918216178755925160019687015590815260099092529390208054928801909116919092161790555b604080518481526020810184905281516001600160a01b038816927fdec2bacdd2f05b59de34da9b523dff8be42e5e38e818c82fdb0bae774387a724928290030190a25050505050565b6000816401000000008410611e7b5760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561174a578181015183820152602001611732565b509192915050565b60408051808201909152600080825260208201529056fe42455032303a207472616e736665722066726f6d20746865207a65726f206164647265737342455032303a20617070726f76652066726f6d20746865207a65726f20616464726573734f776e61626c653a206e6577206f776e657220697320746865207a65726f206164647265737343414b453a3a64656c656761746542795369673a207369676e6174757265206578706972656442455032303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e636543414b453a3a64656c656761746542795369673a20696e76616c6964207369676e617475726543414b453a3a5f7772697465436865636b706f696e743a20626c6f636b206e756d6265722065786365656473203332206269747343414b453a3a6765745072696f72566f7465733a206e6f74207965742064657465726d696e656442455032303a207472616e7366657220616d6f756e7420657863656564732062616c616e636543414b453a3a64656c656761746542795369673a20696e76616c6964206e6f6e636542455032303a207472616e7366657220746f20746865207a65726f206164647265737342455032303a2064656372656173656420616c6c6f77616e63652062656c6f77207a65726f42455032303a206275726e2066726f6d20746865207a65726f206164647265737342455032303a206275726e20616d6f756e7420657863656564732062616c616e636542455032303a20617070726f766520746f20746865207a65726f2061646472657373a26469706673582212208e1251749b2805dbee8f76b47e87700a5c69c99919dfd051acf418587cc69d6064736f6c634300060c0033", + "abi": [ + { + "inputs": [{ "internalType": "contract CakeToken", "name": "_cake", "type": "address" }], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "owner", "type": "address" }, + { "indexed": true, "internalType": "address", "name": "spender", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "value", "type": "uint256" } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "delegator", "type": "address" }, + { "indexed": true, "internalType": "address", "name": "fromDelegate", "type": "address" }, + { "indexed": true, "internalType": "address", "name": "toDelegate", "type": "address" } + ], + "name": "DelegateChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "delegate", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "previousBalance", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "newBalance", "type": "uint256" } + ], + "name": "DelegateVotesChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "previousOwner", "type": "address" }, + { "indexed": true, "internalType": "address", "name": "newOwner", "type": "address" } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "from", "type": "address" }, + { "indexed": true, "internalType": "address", "name": "to", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "value", "type": "uint256" } + ], + "name": "Transfer", + "type": "event" + }, + { + "inputs": [], + "name": "DELEGATION_TYPEHASH", + "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "DOMAIN_TYPEHASH", + "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "owner", "type": "address" }, + { "internalType": "address", "name": "spender", "type": "address" } + ], + "name": "allowance", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "spender", "type": "address" }, + { "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "approve", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "account", "type": "address" }], + "name": "balanceOf", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "_from", "type": "address" }, + { "internalType": "uint256", "name": "_amount", "type": "uint256" } + ], + "name": "burn", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "cake", + "outputs": [{ "internalType": "contract CakeToken", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "", "type": "address" }, + { "internalType": "uint32", "name": "", "type": "uint32" } + ], + "name": "checkpoints", + "outputs": [ + { "internalType": "uint32", "name": "fromBlock", "type": "uint32" }, + { "internalType": "uint256", "name": "votes", "type": "uint256" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "decimals", + "outputs": [{ "internalType": "uint8", "name": "", "type": "uint8" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "spender", "type": "address" }, + { "internalType": "uint256", "name": "subtractedValue", "type": "uint256" } + ], + "name": "decreaseAllowance", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "delegatee", "type": "address" }], + "name": "delegate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "delegatee", "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": "delegateBySig", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "delegator", "type": "address" }], + "name": "delegates", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "account", "type": "address" }], + "name": "getCurrentVotes", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getOwner", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "account", "type": "address" }, + { "internalType": "uint256", "name": "blockNumber", "type": "uint256" } + ], + "name": "getPriorVotes", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "spender", "type": "address" }, + { "internalType": "uint256", "name": "addedValue", "type": "uint256" } + ], + "name": "increaseAllowance", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "_to", "type": "address" }, + { "internalType": "uint256", "name": "_amount", "type": "uint256" } + ], + "name": "mint", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint256", "name": "amount", "type": "uint256" }], + "name": "mint", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [{ "internalType": "string", "name": "", "type": "string" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "", "type": "address" }], + "name": "nonces", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "", "type": "address" }], + "name": "numCheckpoints", + "outputs": [{ "internalType": "uint32", "name": "", "type": "uint32" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { "inputs": [], "name": "renounceOwnership", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { "internalType": "address", "name": "_to", "type": "address" }, + { "internalType": "uint256", "name": "_amount", "type": "uint256" } + ], + "name": "safeCakeTransfer", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [{ "internalType": "string", "name": "", "type": "string" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "recipient", "type": "address" }, + { "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "transfer", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "sender", "type": "address" }, + { "internalType": "address", "name": "recipient", "type": "address" }, + { "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "transferFrom", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "newOwner", "type": "address" }], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ] +} diff --git a/contracts/interfaces/IPancakeMasterChef.sol b/contracts/interfaces/IPancakeMasterChef.sol new file mode 100644 index 00000000..70174a26 --- /dev/null +++ b/contracts/interfaces/IPancakeMasterChef.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.6.12; + +interface IPancakeMasterChef { + function userInfo(uint256 _pid, address _user) external view returns (uint256 amount, uint256 rewardDebt); + + function pendingCake(uint256 _pid, address _user) external view returns (uint256); + + function enterStaking(uint256 _amount) external; + + function leaveStaking(uint256 _amount) external; +} diff --git a/contracts/interfaces/sushi/IMasterChefV1.sol b/contracts/interfaces/sushi/IMasterChefV1.sol new file mode 100644 index 00000000..5d77e825 --- /dev/null +++ b/contracts/interfaces/sushi/IMasterChefV1.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.6.12; + +interface IMasterChefV1 { + function userInfo(uint256 _pid, address _user) external view returns (uint256 amount, uint256 rewardDebt); + + function deposit(uint256 _pid, uint256 _amount) external; + + function withdraw(uint256 _pid, uint256 _amount) external; +} diff --git a/contracts/powerindex-router/implementations/AbstractMasterChefIndexRouter.sol b/contracts/powerindex-router/implementations/AbstractMasterChefIndexRouter.sol new file mode 100644 index 00000000..6ee32172 --- /dev/null +++ b/contracts/powerindex-router/implementations/AbstractMasterChefIndexRouter.sol @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.6.12; +pragma experimental ABIEncoderV2; + +import "../../interfaces/sushi/IMasterChefV1.sol"; +import "../PowerIndexBasicRouter.sol"; + +abstract contract AbstractMasterChefIndexRouter is PowerIndexBasicRouter { + event Stake(address indexed sender, uint256 amount); + event Redeem(address indexed sender, uint256 amount); + event IgnoreDueMissingStaking(); + event ClaimRewards(address indexed sender, uint256 earned); + event DistributeRewards( + address indexed sender, + uint256 tokenReward, + uint256 pvpReward, + uint256 poolRewardsUnderlying, + uint256 poolRewardsPi, + address[] pools + ); + + IERC20 internal immutable TOKEN; + + constructor(address _token) public { + TOKEN = IERC20(_token); + } + + /*** PERMISSIONLESS REWARD CLAIMING AND DISTRIBUTION ***/ + + /** + * @notice Withdraws the extra staked TOKEN as a reward and transfers it to the router + */ + function _claimRewards() internal override { + // Step #1. Claim TOKEN reward from MasterChef governance pool + uint256 piTokenBalanceBefore = TOKEN.balanceOf(address(piToken)); + _rewards(); + uint256 earned = TOKEN.balanceOf(address(piToken)).sub(piTokenBalanceBefore); + require(earned > 0, "NOTHING_EARNED"); + + // Step #2. Transfer yCrv reward to the router + piToken.callExternal(address(TOKEN), TOKEN.transfer.selector, abi.encode(address(this), earned), 0); + + emit ClaimRewards(msg.sender, earned); + } + + /** + * @notice Wraps the router's underlying balance into piTokens and transfers them + * to the pools proportionally their token balances + */ + function _distributeRewards() internal override { + uint256 pendingReward = TOKEN.balanceOf(address(this)); + require(pendingReward > 0, "NO_PENDING_REWARD"); + + // Step #1. Distribute pvpReward + (uint256 pvpReward, uint256 poolRewardsUnderlying) = _distributeRewardToPvp(pendingReward, TOKEN); + require(poolRewardsUnderlying > 0, "NO_POOL_REWARDS_UNDERLYING"); + + // Step #2. Wrap token into piToken + TOKEN.approve(address(piToken), poolRewardsUnderlying); + piToken.deposit(poolRewardsUnderlying); + + // Step #3. Distribute piToken over the pools + (uint256 poolRewardsPi, address[] memory pools) = _distributePiRemainderToPools(piToken); + + emit DistributeRewards(msg.sender, pendingReward, pvpReward, poolRewardsUnderlying, poolRewardsPi, pools); + } + + /*** OWNER METHODS ***/ + + function stake(uint256 _amount) external onlyOwner { + _stake(_amount); + } + + function redeem(uint256 _amount) external onlyOwner { + _redeem(_amount); + } + + /*** POKE FUNCTION ***/ + + function _rebalancePoke(ReserveStatus reserveStatus, uint256 diff) internal override { + require(staking != address(0), "STAKING_IS_NULL"); + + if (reserveStatus == ReserveStatus.SHORTAGE) { + _redeem(diff); + } else if (reserveStatus == ReserveStatus.EXCESS) { + _stake(diff); + } + } + + /*** INTERNALS ***/ + + function _rewards() internal virtual; + + function _stake(uint256 _amount) internal virtual; + + function _redeem(uint256 _amount) internal virtual; +} diff --git a/contracts/powerindex-router/implementations/MasterChefPowerIndexRouter.sol b/contracts/powerindex-router/implementations/MasterChefPowerIndexRouter.sol new file mode 100644 index 00000000..be83b3d2 --- /dev/null +++ b/contracts/powerindex-router/implementations/MasterChefPowerIndexRouter.sol @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.6.12; +pragma experimental ABIEncoderV2; + +import "../../interfaces/sushi/IMasterChefV1.sol"; +import "./AbstractMasterChefIndexRouter.sol"; + +/** + * Compatible with: + * - MDEX: https://bscscan.com/address/0x6aee12e5eb987b3be1ba8e621be7c4804925ba68, pending rewards via pending(pid, user) + * - Bakery: https://bscscan.com/address/0x20ec291bb8459b6145317e7126532ce7ece5056f, pending rewards via pendingBake(pid, user) + * - Auto: https://bscscan.com/address/0x763a05bdb9f8946d8c3fa72d1e0d3f5e68647e5c, pending rewards via stakedWantTokens(pid, user) + */ +contract MasterChefPowerIndexRouter is AbstractMasterChefIndexRouter { + uint256 internal immutable MASTER_CHEF_PID; + + struct MasterChefConfig { + address token; + uint256 masterChefPid; + } + + constructor( + address _piToken, + BasicConfig memory _basicConfig, + MasterChefConfig memory _masterChefConfig + ) public AbstractMasterChefIndexRouter(_masterChefConfig.token) PowerIndexBasicRouter(_piToken, _basicConfig) { + MASTER_CHEF_PID = _masterChefConfig.masterChefPid; + } + + /*** OVERRIDES ***/ + + function _getUnderlyingStaked() internal view override returns (uint256) { + if (staking == address(0)) { + return 0; + } + (uint256 amount, ) = IMasterChefV1(staking).userInfo(MASTER_CHEF_PID, address(piToken)); + return amount; + } + + function _rewards() internal override { + _callStaking(IMasterChefV1.deposit.selector, abi.encode(MASTER_CHEF_PID, 0)); + } + + function _stake(uint256 _amount) internal override { + require(_amount > 0, "CANT_STAKE_0"); + + piToken.approveUnderlying(staking, _amount); + _callStaking(IMasterChefV1.deposit.selector, abi.encode(MASTER_CHEF_PID, _amount)); + + emit Stake(msg.sender, _amount); + } + + function _redeem(uint256 _amount) internal override { + require(_amount > 0, "CANT_REDEEM_0"); + + _callStaking(IMasterChefV1.withdraw.selector, abi.encode(MASTER_CHEF_PID, _amount)); + + emit Redeem(msg.sender, _amount); + } +} diff --git a/contracts/powerindex-router/implementations/PancakeMasterChefPowerIndexRouter.sol b/contracts/powerindex-router/implementations/PancakeMasterChefPowerIndexRouter.sol new file mode 100644 index 00000000..84c406a5 --- /dev/null +++ b/contracts/powerindex-router/implementations/PancakeMasterChefPowerIndexRouter.sol @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.6.12; +pragma experimental ABIEncoderV2; + +import "../../interfaces/IPancakeMasterChef.sol"; +import "./AbstractMasterChefIndexRouter.sol"; + +/** + * Compatible with: + * - Pancake: https://bscscan.com/address/0x73feaa1ee314f8c655e354234017be2193c9e24e + * To get pending rewards use IPancakeStaking(0x73feaa1ee314f8c655e354234017be2193c9e24e).pendingCake(0, piToken). + */ +contract PancakeMasterChefIndexRouter is AbstractMasterChefIndexRouter { + struct PancakeMasterChefConfig { + address cake; + } + + constructor( + address _piToken, + BasicConfig memory _basicConfig, + PancakeMasterChefConfig memory _masterChefConfig + ) public AbstractMasterChefIndexRouter(_masterChefConfig.cake) PowerIndexBasicRouter(_piToken, _basicConfig) {} + + /*** VIEWERS ***/ + + function getPendingRewards() public view returns (uint256 amount) { + return IPancakeMasterChef(staking).pendingCake(0, address(piToken)); + } + + /*** OVERRIDES ***/ + + function _getUnderlyingStaked() internal view override returns (uint256) { + if (staking == address(0)) { + return 0; + } + (uint256 amount, ) = IPancakeMasterChef(staking).userInfo(0, address(piToken)); + return amount; + } + + function _rewards() internal override { + _callStaking(IPancakeMasterChef.leaveStaking.selector, abi.encode(0)); + } + + function _stake(uint256 _amount) internal override { + require(_amount > 0, "CANT_STAKE_0"); + + piToken.approveUnderlying(staking, _amount); + _callStaking(IPancakeMasterChef.enterStaking.selector, abi.encode(_amount)); + + emit Stake(msg.sender, _amount); + } + + function _redeem(uint256 _amount) internal override { + require(_amount > 0, "CANT_REDEEM_0"); + + _callStaking(IPancakeMasterChef.leaveStaking.selector, abi.encode(_amount)); + + emit Redeem(msg.sender, _amount); + } +} diff --git a/contracts/test/sushi/MockPancakeMasterChef.sol b/contracts/test/sushi/MockPancakeMasterChef.sol new file mode 100644 index 00000000..9bd38aea --- /dev/null +++ b/contracts/test/sushi/MockPancakeMasterChef.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.6.12; + +contract MockPancakeMasterChef { + function enterStaking(uint256) external {} + + function leaveStaking(uint256) external {} + + function userInfo(uint256, address) external view returns (uint256 amount, uint256 rewardDebt) { + return (0, 0); + } +} diff --git a/test/helpers/builders.js b/test/helpers/builders.js index 43081d42..e966cd77 100644 --- a/test/helpers/builders.js +++ b/test/helpers/builders.js @@ -40,6 +40,11 @@ function buildSushiRouterConfig(SUSHI) { return { SUSHI }; } +// PANCAKE MASTER CHEF +function buildPancakeMasterChefRouterConfig(cake) { + return { cake }; +} + const BasicConfig = { poolRestrictions: 'address', @@ -121,6 +126,7 @@ module.exports = { buildBasicRouterConfig, buildAaveRouterConfig, buildSushiRouterConfig, + buildPancakeMasterChefRouterConfig, buildAaveAssetConfigInput, buildBasicRouterArgs, buildYearnRouterArgs, diff --git a/test/helpers/index.js b/test/helpers/index.js index a0025031..77c20785 100644 --- a/test/helpers/index.js +++ b/test/helpers/index.js @@ -228,9 +228,18 @@ const { BN } = web3.utils; const increaseTime = buildEndpoint('evm_increaseTime'); -async function latestBlock () { +async function latestBlockTimestamp () { + const block = await web3.eth.getBlock('latest'); + return block.timestamp; +} + +async function latestBlockNumber () { const block = await web3.eth.getBlock('latest'); - return new BN(block.timestamp); + return block.number; +} + +async function latestBlock () { + return await web3.eth.getBlock('latest'); } async function increaseTimeTo (target) { @@ -238,7 +247,7 @@ async function increaseTimeTo (target) { target = new BN(target); } - const now = (await latestBlock()); + const now = new BN(await latestBlockTimestamp()); if (target.lt(now)) throw Error(`Cannot increase current time (${now}) to a moment in the past (${target})`); const diff = target.sub(now); @@ -405,6 +414,9 @@ module.exports = { artifactFromBytecode, toEvmBytes32, advanceBlocks, + latestBlock, + latestBlockNumber, + latestBlockTimestamp, splitPayload, fetchLogs, ether, diff --git a/test/router/implementations/PancakeMasterChefRouter.unit.js b/test/router/implementations/PancakeMasterChefRouter.unit.js new file mode 100644 index 00000000..ff8fcb9d --- /dev/null +++ b/test/router/implementations/PancakeMasterChefRouter.unit.js @@ -0,0 +1,437 @@ +const { time, constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { ether, artifactFromBytecode, latestBlockNumber } = require('../../helpers'); +const { buildBasicRouterConfig, buildPancakeMasterChefRouterConfig } = require('../../helpers/builders'); +const assert = require('chai').assert; +const MockERC20 = artifacts.require('MockERC20'); +const PancakeMasterChefIndexRouter = artifacts.require('PancakeMasterChefIndexRouter'); +const WrappedPiErc20 = artifacts.require('WrappedPiErc20'); +const PoolRestrictions = artifacts.require('PoolRestrictions'); +const MockPancakeMasterChef = artifacts.require('MockPancakeMasterChef'); +const MockGulpingBPool = artifacts.require('MockGulpingBPool'); +const MockPoke = artifacts.require('MockPoke'); + +const PancakeMasterChef = artifactFromBytecode('bsc/PancakeMasterChef'); +const PancakeSyrupPool = artifactFromBytecode('bsc/PancakeSyrupPool'); + +MockERC20.numberFormat = 'String'; +PancakeMasterChefIndexRouter.numberFormat = 'String'; +WrappedPiErc20.numberFormat = 'String'; + +const { web3 } = MockERC20; + +describe('PancakeMasterChefRouter Tests', () => { + let deployer, bob, alice, piGov, stub, pvp, pool1, pool2; + + before(async function() { + [deployer, bob, alice, piGov, stub, pvp, pool1, pool2] = await web3.eth.getAccounts(); + }); + + let myToken, syrupPool, masterChef, poolRestrictions, piMyToken, myRouter, poke; + + beforeEach(async function() { + myToken = await MockERC20.new('My Staking Token', 'MST', '18', ether('10000000')); + + // 0x009cf7bc57584b7998236eff51b98a168dcea9b0 + syrupPool = await PancakeSyrupPool.new(myToken.address); + // 0x73feaa1ee314f8c655e354234017be2193c9e24e + masterChef = await PancakeMasterChef.new( + myToken.address, + syrupPool.address, + deployer, + ether(40), + await latestBlockNumber(), + ); + + poolRestrictions = await PoolRestrictions.new(); + piMyToken = await WrappedPiErc20.new(myToken.address, stub, 'Wrapped My Staking Token', 'piMST'); + + poke = await MockPoke.new(true); + myRouter = await PancakeMasterChefIndexRouter.new( + piMyToken.address, + buildBasicRouterConfig( + poolRestrictions.address, + poke.address, + constants.ZERO_ADDRESS, + masterChef.address, + ether('0.2'), + ether('0.02'), + '0', + pvp, + ether('0.15'), + [pool1, pool2], + ), + buildPancakeMasterChefRouterConfig(myToken.address), + ); + + await syrupPool.transferOwnership(masterChef.address); + await piMyToken.changeRouter(myRouter.address, { from: stub }); + await masterChef.add(20306, myToken.address, false); + await myRouter.transferOwnership(piGov); + + assert.equal(await myRouter.owner(), piGov); + }); + + describe('owner methods', async () => { + beforeEach(async () => { + await myRouter.transferOwnership(piGov, { from: piGov }); + }); + + describe('stake()/redeem()', () => { + beforeEach(async () => { + await myToken.transfer(alice, ether('10000')); + await myToken.approve(piMyToken.address, ether('10000'), { from: alice }); + await piMyToken.deposit(ether('10000'), { from: alice }); + + await myRouter.poke(false); + + assert.equal(await myToken.balanceOf(piMyToken.address), ether(2000)); + assert.equal(await myToken.balanceOf(masterChef.address), ether(8000)); + assert.equal((await masterChef.userInfo(0, piMyToken.address)).amount, ether(8000)); + }); + + describe('stake()', () => { + it('should allow the owner staking any amount of reserve tokens', async () => { + const res = await myRouter.stake(ether(2000), { from: piGov }); + expectEvent(res, 'Stake', { + sender: piGov, + amount: ether(2000), + }); + assert.equal(await myToken.balanceOf(piMyToken.address), ether('9.999261280000000000')); + assert.equal(await myToken.balanceOf(masterChef.address), ether(10000)); + const userInfo = await masterChef.userInfo(0, piMyToken.address); + assert.equal(userInfo.amount, ether(10000)); + }); + + it('should deny staking 0', async () => { + await expectRevert(myRouter.stake(ether(0), { from: piGov }), 'CANT_STAKE_0'); + }); + + it('should deny non-owner staking any amount of reserve tokens', async () => { + await expectRevert(myRouter.stake(ether(1), { from: alice }), 'Ownable: caller is not the owner'); + }); + }); + + describe('redeem()', () => { + it('should allow the owner redeeming any amount of reserve tokens', async () => { + const res = await myRouter.redeem(ether(3000), { from: piGov }); + expectEvent(res, 'Redeem', { + sender: piGov, + amount: ether(3000), + }); + assert.equal(await myToken.balanceOf(piMyToken.address), '5009999261280000000000'); + const userInfo = await masterChef.userInfo(0, piMyToken.address); + assert.equal(userInfo.amount, ether(5000)); + }); + + it('should deny staking 0', async () => { + await expectRevert(myRouter.redeem(ether(0), { from: piGov }), 'CANT_REDEEM_0'); + }); + + it('should deny non-owner staking any amount of reserve tokens', async () => { + await expectRevert(myRouter.redeem(ether(1), { from: alice }), 'Ownable: caller is not the owner'); + }); + }); + }); + + describe('setRewardPools()', () => { + it('should allow the owner setting a new reward pool', async () => { + const res = await myRouter.setRewardPools([alice, bob], { from: piGov }); + expectEvent(res, 'SetRewardPools', { + len: '2', + rewardPools: [alice, bob], + }); + }); + + it('should deny setting an empty reward pool', async () => { + await expectRevert(myRouter.setRewardPools([], { from: piGov }), 'AT_LEAST_ONE_EXPECTED'); + }); + + it('should deny non-owner setting a new reward pool', async () => { + await expectRevert(myRouter.setRewardPools([alice, bob], { from: alice }), 'Ownable: caller is not the owner'); + }); + }); + + describe('setPvpFee()', () => { + it('should allow the owner setting a new pvpFee', async () => { + const res = await myRouter.setPvpFee(ether('0.1'), { from: piGov }); + expectEvent(res, 'SetPvpFee', { + pvpFee: ether('0.1'), + }); + }); + + it('should deny setting a fee greater or equal 100%', async () => { + await expectRevert(myRouter.setPvpFee(ether('1'), { from: piGov }), 'PVP_FEE_OVER_THE_LIMIT'); + }); + + it('should deny non-owner setting a new pvpFee', async () => { + await expectRevert(myRouter.setPvpFee(ether('0'), { from: alice }), 'Ownable: caller is not the owner'); + }); + }); + }); + + describe('reserve management', () => { + beforeEach(async () => { + // alice + await myToken.transfer(alice, ether('20000')); + await myToken.approve(piMyToken.address, ether('10000'), { from: alice }); + await piMyToken.deposit(ether('10000'), { from: alice }); + + // bob + await myToken.transfer(bob, ether('42000')); + await myToken.approve(masterChef.address, ether('42000'), { from: bob }); + await masterChef.enterStaking(ether('42000'), { from: bob }); + + await myRouter.poke(false); + + assert.equal(await myToken.balanceOf(masterChef.address), ether(50000)); + assert.equal(await myToken.balanceOf(piMyToken.address), ether(2000)); + }); + + it('should increase reserve on deposit', async () => { + assert.equal(await piMyToken.balanceOf(alice), ether(10000)); + await myToken.approve(piMyToken.address, ether(1000), { from: alice }); + await piMyToken.deposit(ether(1000), { from: alice }); + await myRouter.poke(false); + + assert.equal(await piMyToken.balanceOf(alice), ether(11000)); + assert.equal(await myToken.balanceOf(masterChef.address), ether(50800)); + assert.equal(await myToken.balanceOf(piMyToken.address), ether('2204.799645416000000000')); + assert.equal(await myRouter.getUnderlyingStaked(), ether(8800)); + assert.equal((await masterChef.userInfo(0, piMyToken.address)).amount, ether(8800)); + }); + + it('should decrease reserve on withdrawal', async () => { + assert.equal(await piMyToken.balanceOf(alice), ether(10000)); + + await piMyToken.withdraw(ether(1000), { from: alice }); + await myRouter.poke(false); + + assert.equal(await piMyToken.balanceOf(alice), ether(9000)); + assert.equal(await myToken.balanceOf(masterChef.address), ether(49200)); + assert.equal(await myToken.balanceOf(piMyToken.address), ether('1803.199763608000000000')); + assert.equal(await myRouter.getUnderlyingStaked(), ether(7200)); + assert.equal((await masterChef.userInfo(0, piMyToken.address)).amount, ether(7200)); + }); + + it('should ignore rebalancing if the staking address is 0', async () => { + await myRouter.redeem(ether(8000), { from: piGov }); + await myRouter.setVotingAndStaking(masterChef.address, constants.ZERO_ADDRESS, { from: piGov }); + + assert.equal(await myToken.balanceOf(masterChef.address), ether(42000)); + assert.equal(await myToken.balanceOf(piMyToken.address), ether('10001.599881800000000000')); + assert.equal(await piMyToken.balanceOf(alice), ether(10000)); + assert.equal(await piMyToken.totalSupply(), ether(10000)); + await piMyToken.withdraw(ether(1000), { from: alice }); + await expectRevert(myRouter.poke(false), 'STAKING_IS_NULL'); + }); + + describe('when interval enabled', () => { + beforeEach(async () => { + await myRouter.setReserveConfig(ether('0.2'), time.duration.hours(1), { from: piGov }); + await poke.setMinMaxReportIntervals(time.duration.hours(1), time.duration.hours(2), { from: piGov }); + }); + + it('should DO rebalance by pokeFromReporter if the rebalancing interval has passed', async () => { + await time.increase(time.duration.minutes(61)); + + await myToken.approve(piMyToken.address, ether(1000), { from: alice }); + await piMyToken.deposit(ether(1000), { from: alice }); + await expectRevert(myRouter.pokeFromSlasher(0, false, '0x'), 'MAX_INTERVAL_NOT_REACHED'); + }); + + it('should DO rebalance by pokeFromSlasher if the rebalancing interval has passed', async () => { + await time.increase(time.duration.minutes(121)); + + await myToken.approve(piMyToken.address, ether(1000), { from: alice }); + await piMyToken.deposit(ether(1000), { from: alice }); + await myRouter.pokeFromSlasher(0, false, '0x'); + + assert.equal(await myToken.balanceOf(masterChef.address), ether(50800)); + assert.equal((await masterChef.userInfo(0, piMyToken.address)).amount, ether(8800)); + assert.equal(await myToken.balanceOf(piMyToken.address), ether('2209.599290832000000000')); + }); + + it('should DO rebalance on withdrawal if the rebalancing interval has passed', async () => { + await time.increase(time.duration.minutes(61)); + + await piMyToken.withdraw(ether(1000), { from: alice }); + await myRouter.poke(false); + + assert.equal(await myToken.balanceOf(masterChef.address), ether(49200)); + assert.equal((await masterChef.userInfo(0, piMyToken.address)).amount, ether(7200)); + assert.equal(await myToken.balanceOf(piMyToken.address), ether('1807.999409024000000000')); + }); + + it('should NOT rebalance by pokeFromReporter if the rebalancing interval has passed', async () => { + await time.increase(time.duration.minutes(50)); + + await myToken.approve(piMyToken.address, ether(1000), { from: alice }); + await piMyToken.deposit(ether(1000), { from: alice }); + await expectRevert(myRouter.pokeFromReporter(0, false, '0x'), 'MIN_INTERVAL_NOT_REACHED'); + await expectRevert(myRouter.pokeFromSlasher(0, false, '0x'), 'MAX_INTERVAL_NOT_REACHED'); + }); + + it('should NOT rebalance by pokeFromSlasher if the rebalancing interval has passed', async () => { + await time.increase(time.duration.minutes(70)); + + await myToken.approve(piMyToken.address, ether(1000), { from: alice }); + await piMyToken.deposit(ether(1000), { from: alice }); + await expectRevert(myRouter.pokeFromSlasher(0, false, '0x'), 'MAX_INTERVAL_NOT_REACHED'); + }); + }); + + describe('on poke', async () => { + it('should do nothing when nothing has changed', async () => { + await myRouter.poke(false, { from: bob }); + + assert.equal(await myToken.balanceOf(masterChef.address), ether(50000)); + assert.equal((await masterChef.userInfo(0, piMyToken.address)).amount, ether(8000)); + assert.equal(await myToken.balanceOf(piMyToken.address), ether(2000)); + }); + + it('should increase reserve if required', async () => { + await myToken.transfer(piMyToken.address, ether(1000), { from: alice }); + + assert.equal(await myToken.balanceOf(masterChef.address), ether(50000)); + assert.equal((await masterChef.userInfo(0, piMyToken.address)).amount, ether(8000)); + assert.equal(await myToken.balanceOf(piMyToken.address), ether(3000)); + + await myRouter.poke(false, { from: bob }); + + assert.equal(await myToken.balanceOf(masterChef.address), ether(50800)); + assert.equal((await masterChef.userInfo(0, piMyToken.address)).amount, ether(8800)); + assert.equal(await myToken.balanceOf(piMyToken.address), ether('2203.199763608000000000')); + }); + }); + + it('should stake all the underlying tokens with 0 RR', async () => { + await myRouter.setReserveConfig(ether(0), 0, { from: piGov }); + + await myRouter.poke(false, { from: bob }); + assert.equal(await myToken.balanceOf(masterChef.address), ether(52000)); + assert.equal(await myToken.balanceOf(piMyToken.address), ether('3.199763608000000000')); + }); + + it('should keep all the underlying tokens on piToken with 1 RR', async () => { + await myRouter.setReserveConfig(ether(1), 0, { from: piGov }); + + await myRouter.poke(false, { from: bob }); + assert.equal(await myToken.balanceOf(masterChef.address), ether(42000)); + assert.equal(await myToken.balanceOf(piMyToken.address), ether('10003.199763608000000000')); + }); + }); + + describe('reward distribution', async () => { + let poolA, poolB, poolC, poolD; + + beforeEach(async function() { + poolA = await MockGulpingBPool.new(); + poolB = await MockGulpingBPool.new(); + poolC = await MockGulpingBPool.new(); + poolD = await MockGulpingBPool.new(); + await myRouter.setRewardPools([poolA.address, poolB.address, poolC.address], { from: piGov }); + + await poolRestrictions.setVotingAllowedForSenders(masterChef.address, [alice], [true]); + + await myToken.transfer(syrupPool.address, ether(12000)); + await myToken.transfer(alice, ether('10000')); + await myToken.approve(piMyToken.address, ether('10000'), { from: alice }); + await piMyToken.deposit(ether('10000'), { from: alice }); + + await myRouter.poke(false); + + assert.equal(await piMyToken.totalSupply(), ether('10000')); + assert.equal(await piMyToken.balanceOf(alice), ether('10000')); + + await piMyToken.transfer(poolA.address, 10, { from: alice }); + await piMyToken.transfer(poolB.address, 20, { from: alice }); + }); + + it('should allow withdrawing rewards from the masterChef', async () => { + await myToken.transfer(masterChef.address, ether(2000)); + + await masterChef.massUpdatePools(); + await time.increase(time.duration.days(8)); + await masterChef.massUpdatePools(); + const latest = await latestBlockNumber(); + assert.equal(await myToken.balanceOf(piMyToken.address), ether(2000)); + assert.equal(await myRouter.getUnderlyingStaked(), ether(8000)); + assert.equal(await myRouter.getPendingRewards(), ether('47.996454152000000000')); + + let res = await myRouter.poke(true, { from: bob }); + expectEvent(res, 'ClaimRewards', { + sender: bob, + earned: ether('55.995863176000000000'), + }); + + expectEvent(res, 'DistributeRewards', { + sender: bob, + tokenReward: ether('55.995863176000000000'), + pvpReward: ether('8.399379476400000000'), + poolRewardsUnderlying: ether('47.596483699600000000'), + poolRewardsPi: ether('47.596483699600000000'), + pools: [poolA.address, poolB.address, poolC.address], + }); + + assert.equal(await myToken.balanceOf(piMyToken.address), ether('2047.596483699600000000')); + assert.equal(await myToken.balanceOf(myRouter.address), '0'); + + assert.isTrue(parseInt(res.logs[3].args.poolRewardsUnderlying) > 1); + assert.isTrue(parseInt(res.logs[3].args.poolRewardsPi.length) > 1); + + await expectEvent.inTransaction(res.tx, poolA, 'Gulp'); + await expectEvent.inTransaction(res.tx, poolB, 'Gulp'); + await expectEvent.notEmitted.inTransaction(res.tx, poolC, 'Gulp'); + await expectEvent.notEmitted.inTransaction(res.tx, poolD, 'Gulp'); + + assert.equal(res.logs.length, 4); + assert.equal(res.logs[1].args.pool, poolA.address); + assert.equal(res.logs[1].args.amount, '15865494566533333333'); + assert.equal(res.logs[2].args.pool, poolB.address); + assert.equal(res.logs[2].args.amount, '31730989133066666666'); + + assert.equal(await piMyToken.balanceOf(poolA.address), 15865494566533333343); + assert.equal(await piMyToken.balanceOf(poolB.address), 31730989133066666686); + assert.equal(await piMyToken.balanceOf(poolC.address), '0'); + assert.equal(await piMyToken.balanceOf(poolD.address), '0'); + + assert.equal(await myToken.balanceOf(myRouter.address), '0'); + assert.equal(await myToken.balanceOf(myRouter.address), '0'); + }); + + it('should revert poke if there is nothing released', async () => { + const dishonestChef = await MockPancakeMasterChef.new(myToken.address); + await myRouter.setReserveConfig(ether(1), 0, { from: piGov }); + await myRouter.poke(false); + await myRouter.setVotingAndStaking(constants.ZERO_ADDRESS, dishonestChef.address, { from: piGov }); + await myRouter.setReserveConfig(ether('0.2'), 0, { from: piGov }); + await myRouter.poke(false); + await myToken.transfer(dishonestChef.address, ether(1000)); + await expectRevert(myRouter.poke(true, { from: alice }), 'NOTHING_EARNED'); + }); + + it('should revert distributing rewards when missing reward pools config', async () => { + poke = await MockPoke.new(true); + const router = await PancakeMasterChefIndexRouter.new( + piMyToken.address, + buildBasicRouterConfig( + poolRestrictions.address, + poke.address, + masterChef.address, + masterChef.address, + ether('0.2'), + ether('0.02'), + '0', + pvp, + ether('0.2'), + [], + ), + buildPancakeMasterChefRouterConfig(myToken.address), + ); + await myRouter.migrateToNewRouter(piMyToken.address, router.address, [], { from: piGov }); + await myToken.transfer(masterChef.address, ether(2000)); + await time.increase(1); + await expectRevert(router.poke(true, { from: bob }), 'MISSING_REWARD_POOLS'); + }); + }); +}); From 0c9e1324122aed6dd67984834df565d8462e2a75 Mon Sep 17 00:00:00 2001 From: Poli Paul Date: Tue, 13 Jul 2021 21:42:22 +0200 Subject: [PATCH 02/33] Fix liniter errors --- .../implementations/MasterChefPowerIndexRouter.sol | 9 ++++++--- .../implementations/PancakeMasterChefRouter.unit.js | 1 - 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/contracts/powerindex-router/implementations/MasterChefPowerIndexRouter.sol b/contracts/powerindex-router/implementations/MasterChefPowerIndexRouter.sol index be83b3d2..39ea0687 100644 --- a/contracts/powerindex-router/implementations/MasterChefPowerIndexRouter.sol +++ b/contracts/powerindex-router/implementations/MasterChefPowerIndexRouter.sol @@ -8,9 +8,12 @@ import "./AbstractMasterChefIndexRouter.sol"; /** * Compatible with: - * - MDEX: https://bscscan.com/address/0x6aee12e5eb987b3be1ba8e621be7c4804925ba68, pending rewards via pending(pid, user) - * - Bakery: https://bscscan.com/address/0x20ec291bb8459b6145317e7126532ce7ece5056f, pending rewards via pendingBake(pid, user) - * - Auto: https://bscscan.com/address/0x763a05bdb9f8946d8c3fa72d1e0d3f5e68647e5c, pending rewards via stakedWantTokens(pid, user) + * - MDEX: https://bscscan.com/address/0x6aee12e5eb987b3be1ba8e621be7c4804925ba68, + * pending rewards via pending(pid, user) + * - Bakery: https://bscscan.com/address/0x20ec291bb8459b6145317e7126532ce7ece5056f, + * pending rewards via pendingBake(pid, user) + * - Auto: https://bscscan.com/address/0x763a05bdb9f8946d8c3fa72d1e0d3f5e68647e5c, + * pending rewards via stakedWantTokens(pid, user) */ contract MasterChefPowerIndexRouter is AbstractMasterChefIndexRouter { uint256 internal immutable MASTER_CHEF_PID; diff --git a/test/router/implementations/PancakeMasterChefRouter.unit.js b/test/router/implementations/PancakeMasterChefRouter.unit.js index ff8fcb9d..74038152 100644 --- a/test/router/implementations/PancakeMasterChefRouter.unit.js +++ b/test/router/implementations/PancakeMasterChefRouter.unit.js @@ -353,7 +353,6 @@ describe('PancakeMasterChefRouter Tests', () => { await masterChef.massUpdatePools(); await time.increase(time.duration.days(8)); await masterChef.massUpdatePools(); - const latest = await latestBlockNumber(); assert.equal(await myToken.balanceOf(piMyToken.address), ether(2000)); assert.equal(await myRouter.getUnderlyingStaked(), ether(8000)); assert.equal(await myRouter.getPendingRewards(), ether('47.996454152000000000')); From f25e117a58cd4b0cf7aa7f52895003da36dde966 Mon Sep 17 00:00:00 2001 From: Poli Paul Date: Thu, 22 Jul 2021 18:01:08 +0200 Subject: [PATCH 03/33] Add BakeryChef router; Modify PancakeChef router --- assets/bsc/BakeryMasterChef.json | 307 +++++++++++++ assets/bsc/BakeryToken.json | 275 +++++++++++ contracts/interfaces/IBakeryMasterChef.sol | 13 + .../PowerIndexBasicRouter.sol | 12 +- .../implementations/AavePowerIndexRouter.sol | 2 +- .../AbstractMasterChefIndexRouter.sol | 53 ++- .../BakeryChefPowerIndexRouter.sol | 49 ++ .../MasterChefPowerIndexRouter.sol | 23 +- .../PancakeMasterChefPowerIndexRouter.sol | 17 +- .../implementations/SushiPowerIndexRouter.sol | 2 +- .../implementations/YearnPowerIndexRouter.sol | 2 +- contracts/test/MockBakeryMasterChef.sol | 17 + contracts/test/MockERC20.sol | 2 + .../test/sushi/MockPancakeMasterChef.sol | 12 +- test/helpers/builders.js | 9 + .../BakeryMasterChefRouter.unit.js | 432 ++++++++++++++++++ .../PancakeMasterChefRouter.unit.js | 139 +++--- .../implementations/SushiRouter.unit.js | 2 +- 18 files changed, 1229 insertions(+), 139 deletions(-) create mode 100644 assets/bsc/BakeryMasterChef.json create mode 100644 assets/bsc/BakeryToken.json create mode 100644 contracts/interfaces/IBakeryMasterChef.sol create mode 100644 contracts/powerindex-router/implementations/BakeryChefPowerIndexRouter.sol create mode 100644 contracts/test/MockBakeryMasterChef.sol create mode 100644 test/router/implementations/BakeryMasterChefRouter.unit.js diff --git a/assets/bsc/BakeryMasterChef.json b/assets/bsc/BakeryMasterChef.json new file mode 100644 index 00000000..44aec446 --- /dev/null +++ b/assets/bsc/BakeryMasterChef.json @@ -0,0 +1,307 @@ +{ + "bytecode": "6080604052600060025564e8d4a51000600b553480156200001f57600080fd5b5060405162002a4238038062002a4283398181016040526101008110156200004657600080fd5b508051602082015160408301516060840151608085015160a086015160c087015160e09097015195969495939492939192909160006200008e6001600160e01b036200028516565b600080546001600160a01b0319166001600160a01b0383169081178255604051929350917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a350600c80546001600160a01b03199081166001600160a01b038b811691909117909255600d805490911691891691909117905560018690556003859055600484905560058390556009829055600a81905562000140848662000289602090811b620019ec17901c565b600681905550620001ff600654620001ac6200016f600554600654620002dc60201b62001b151790919060201c565b620001d4600554620001d4620001e8600954620001d46001620001c0600554620001ac6003546004546200028960201b620019ec1790919060201c565b620002dc60201b62001b151790919060201c565b6200028960201b620019ec1790919060201c565b6200032660201b62001aa21790919060201c565b6001546200028960201b620019ec1790919060201c565b600781905550620002736200025c62000245600162000231600a54600754620002dc60201b62001b151790919060201c565b6200038460201b62001a2e1790919060201c565b6006546200032660201b62001aa21790919060201c565b6003546200038460201b62001a2e1790919060201c565b60085550620004e39650505050505050565b3390565b6000620002d383836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250620003df60201b60201c565b90505b92915050565b6000620002d383836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f0000000000008152506200047a60201b60201c565b6000826200033757506000620002d6565b828202828482816200034557fe5b0414620002d35760405162461bcd60e51b815260040180806020018281038252602181526020018062002a216021913960400191505060405180910390fd5b600082820183811015620002d3576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b60008184841115620004725760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015620004365781810151838201526020016200041c565b50505050905090810190601f168015620004645780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b60008183620004cc5760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315620004365781810151838201526020016200041c565b506000838581620004d957fe5b0495945050505050565b61252e80620004f36000396000f3fe608060405234801561001057600080fd5b50600436106101f05760003560e01c8063715018a61161010f578063b0de262e116100a2578063ebfe436311610071578063ebfe43631461058f578063f2fde38b14610597578063f3fef3a3146105ca578063feb21b9c14610603576101f0565b8063b0de262e1461056f578063c97ab21a14610577578063cedbcf271461057f578063da09c72c14610587576101f0565b806393190c96116100de57806393190c9614610522578063a2edfe3c1461052a578063a55b920714610532578063a5f8d4e614610567576101f0565b8063715018a6146104835780637b46c54f1461048b5780638d88a90e146104be5780638da5cb5b146104f1576101f0565b8063349e2cc61161018757806361235c7b1161015657806361235c7b146103c6578063630b5ba11461040d5780636cc75a0c146104155780636ff1c9bc14610450576101f0565b8063349e2cc61461030e57806334ace4171461033157806347e7ef241461038557806348cd4cb1146103be576101f0565b806317caf6f1116101c357806317caf6f1146102b55780631aed6553146102bd5780631eaaa045146102c55780632d3f7fcb14610306576101f0565b8063081e3eda146101f55780630b1391941461020f578063114b338b146102525780631218c5981461025a575b600080fd5b6101fd610620565b60408051918252519081900360200190f35b6102506004803603606081101561022557600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81351690602081013590604001351515610626565b005b6101fd61078e565b61028d6004803603602081101561027057600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16610794565b6040805194855260208501939093528383019190915215156060830152519081900360800190f35b6101fd6107be565b6101fd6107c4565b610250600480360360608110156102db57600080fd5b5080359073ffffffffffffffffffffffffffffffffffffffff602082013516906040013515156107ca565b6101fd6109e8565b6101fd6004803603604081101561032457600080fd5b50803590602001356109ee565b61036c6004803603604081101561034757600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020013516610a65565b6040805192835260208301919091528051918290030190f35b6102506004803603604081101561039b57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135169060200135610a89565b6101fd610bd8565b6103f9600480360360208110156103dc57600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16610bde565b604080519115158252519081900360200190f35b610250610c0c565b6101fd6004803603604081101561042b57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81358116916020013516610c5d565b6102506004803603602081101561046657600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16610e45565b610250610ee7565b610250600480360360208110156104a157600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16610fe7565b610250600480360360208110156104d457600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166112b3565b6104f9611380565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b6101fd61139c565b6101fd6113a2565b6101fd600480360360a081101561054857600080fd5b50803590602081013590604081013590606081013590608001356113a8565b6101fd611723565b6104f9611729565b6101fd611745565b6101fd61174b565b6104f9611751565b6101fd61176d565b610250600480360360208110156105ad57600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16611773565b610250600480360360408110156105e057600080fd5b5073ffffffffffffffffffffffffffffffffffffffff813516906020013561180d565b6104f96004803603602081101561061957600080fd5b50356119b4565b600e5490565b61062e6119e8565b60005473ffffffffffffffffffffffffffffffffffffffff9081169116146106b757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b80156106c5576106c5610c0c565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600f60205260409020600381015460ff1661075d57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f706f6f6c206e6f74206578697374730000000000000000000000000000000000604482015290519081900360640190fd5b80546002546107839185916107779163ffffffff6119ec16565b9063ffffffff611a2e16565b600255919091555050565b600a5481565b600f6020526000908152604090208054600182015460028301546003909301549192909160ff1684565b60025481565b60045481565b6107d26119e8565b60005473ffffffffffffffffffffffffffffffffffffffff90811691161461085b57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b801561086957610869610c0c565b73ffffffffffffffffffffffffffffffffffffffff82166000908152600f60205260409020600381015460ff161561090257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f706f6f6c20616c72656164792065786973747300000000000000000000000000604482015290519081900360640190fd5b6000600354431161091557600354610917565b435b60025490915061092d908663ffffffff611a2e16565b60029081559482556001808301919091556000948201859055600390910180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001682179055600e80549182018155909352507fbb7b4a454dc3493923482f07822329ed19e8244eff582cc204f8554c3620c3fd90910180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909216919091179055565b60055481565b60006004548211610a1357610a0c83836001546005546009546113a8565b9050610a5f565b6004548310610a2f57610a0c8383600754600654600a546113a8565b610a5c610a4760045484600754600654600a546113a8565b610777856004546001546005546009546113a8565b90505b92915050565b60106020908152600092835260408084209091529082529020805460019091015482565b73ffffffffffffffffffffffffffffffffffffffff82166000908152600f6020908152604080832060108352818420338552909252909120610aca84610fe7565b805415610b28576000610b148260010154610b08600b54610afc87600201548760000154611aa290919063ffffffff16565b9063ffffffff611b1516565b9063ffffffff6119ec16565b90508015610b2657610b263382611b57565b505b610b5073ffffffffffffffffffffffffffffffffffffffff851633308663ffffffff611d5a16565b8054610b62908463ffffffff611a2e16565b808255600b546002840154610b8092610afc9163ffffffff611aa216565b600182015560408051848152905173ffffffffffffffffffffffffffffffffffffffff86169133917f5548c837ab068cf56a2c2479df0882a4922fd203edb7517321831d95078c5f629181900360200190a350505050565b60035481565b73ffffffffffffffffffffffffffffffffffffffff166000908152600f602052604090206003015460ff1690565b600e5460005b81811015610c5957610c51600e8281548110610c2a57fe5b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff16610fe7565b600101610c12565b5050565b6000610c6761245d565b5073ffffffffffffffffffffffffffffffffffffffff83166000908152600f602090815260409182902082516080810184528154815260018201549281019290925260028101549282019290925260039091015460ff16151560608201819052610cd5576000915050610a5f565b73ffffffffffffffffffffffffffffffffffffffff808516600081815260106020908152604080832094881683529381528382208585015185517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152955191959094926370a0823192602480840193829003018186803b158015610d5f57600080fd5b505afa158015610d73573d6000803e3d6000fd5b505050506040513d6020811015610d8957600080fd5b5051602085015190915043118015610da057508015155b8015610db157506008548460200151105b15610e17576000610dc68560200151436109ee565b90506000610de7600254610afc886000015185611aa290919063ffffffff16565b9050610e12610e0584610afc600b5485611aa290919063ffffffff16565b859063ffffffff611a2e16565b935050505b6001830154600b548454610e3a9291610b0891610afc908763ffffffff611aa216565b979650505050505050565b73ffffffffffffffffffffffffffffffffffffffff8116600081815260106020908152604080832033808552925290912080549092610e8b92909163ffffffff611df516565b8054604080519182525173ffffffffffffffffffffffffffffffffffffffff84169133917ff24ef89f38eadc1bde50701ad6e4d6d11a2dc24f7cf834a486991f38833285049181900360200190a3600080825560019091015550565b610eef6119e8565b60005473ffffffffffffffffffffffffffffffffffffffff908116911614610f7857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6000805460405173ffffffffffffffffffffffffffffffffffffffff909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600f60205260409020600381015460ff161580611024575080600101544311155b1561102f57506112b0565b604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905160009173ffffffffffffffffffffffffffffffffffffffff8516916370a0823191602480820192602092909190829003018186803b15801561109f57600080fd5b505afa1580156110b3573d6000803e3d6000fd5b505050506040513d60208110156110c957600080fd5b50519050806110df5750436001909101556112b0565b6008548260010154106110f35750506112b0565b60006111038360010154436109ee565b90506000611124600254610afc866000015485611aa290919063ffffffff16565b600c54600d5491925073ffffffffffffffffffffffffffffffffffffffff9081169163449a52f8911661115e84606463ffffffff611b1516565b6040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050600060405180830381600087803b1580156111c757600080fd5b505af11580156111db573d6000803e3d6000fd5b5050600c54604080517f449a52f800000000000000000000000000000000000000000000000000000000815230600482015260248101869052905173ffffffffffffffffffffffffffffffffffffffff909216935063449a52f8925060448082019260009290919082900301818387803b15801561125857600080fd5b505af115801561126c573d6000803e3d6000fd5b5050505061129d61128c84610afc600b5485611aa290919063ffffffff16565b60028601549063ffffffff611a2e16565b6002850155505043600190920191909155505b50565b600d5473ffffffffffffffffffffffffffffffffffffffff16331461133957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f6465763a207775743f0000000000000000000000000000000000000000000000604482015290519081900360640190fd5b600d80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60005473ffffffffffffffffffffffffffffffffffffffff1690565b60075481565b600b5481565b6000600354851115806113bd57508560085411155b156113ca5750600061171a565b6003548610156113da5760035495505b8460085410156113ea5760085494505b600061144160006114168661140a6003548b6119ec90919063ffffffff16565b9063ffffffff611e8216565b11611422576000611425565b60015b60ff1661077786610afc6003548b6119ec90919063ffffffff16565b90506001811015611450575060015b600061149b60006114708761140a6003548d6119ec90919063ffffffff16565b1161147c57600061147f565b60015b60ff1661077787610afc6003548d6119ec90919063ffffffff16565b905060018110156114aa575060015b818114156114ff576114f66114e66114d9866114cd86600163ffffffff6119ec16565b9063ffffffff611aa216565b889063ffffffff6119ec16565b6114cd898b63ffffffff6119ec16565b9250505061171a565b6000611523611514878463ffffffff611aa216565b6003549063ffffffff611a2e16565b9050600061154b61151461153e86600163ffffffff6119ec16565b899063ffffffff611aa216565b9050898961159661157761156a8a6114cd8a600163ffffffff6119ec16565b8c9063ffffffff6119ec16565b6114cd8585116115875785611589565b845b849063ffffffff6119ec16565b965081841180156115a75750808411155b15611606576116036115f66115e6600088116115c45760006115d9565b6115d98b6114cd8a600163ffffffff6119ec16565b8d9063ffffffff6119ec16565b6114cd878663ffffffff6119ec16565b889063ffffffff611a2e16565b96505b508890508787848411156117125783600061162b84610afc848a63ffffffff6119ec16565b905060018111156116e157600061166861165b6114d987610afc886114cd6003548f6119ec90919063ffffffff16565b869063ffffffff611aa216565b905060006116ae6116a1611694876114cd6001610b088c610afc6003548d6119ec90919063ffffffff16565b899063ffffffff6119ec16565b879063ffffffff611aa216565b90506116d86116cb6002610afc6116a1868663ffffffff611a2e16565b8d9063ffffffff611a2e16565b9b50505061170f565b61170c6116ff61165b6114d9866114cd8e600263ffffffff6119ec16565b8b9063ffffffff611a2e16565b99505b50505b505050505050505b95945050505050565b60085481565b600c5473ffffffffffffffffffffffffffffffffffffffff1681565b60095481565b60065481565b600d5473ffffffffffffffffffffffffffffffffffffffff1681565b60015481565b61177b6119e8565b60005473ffffffffffffffffffffffffffffffffffffffff90811691161461180457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6112b081611ec4565b73ffffffffffffffffffffffffffffffffffffffff82166000908152600f602090815260408083206010835281842033855290925290912080548311156118b557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f77697468647261773a206e6f7420676f6f640000000000000000000000000000604482015290519081900360640190fd5b6118be84610fe7565b60006118e98260010154610b08600b54610afc87600201548760000154611aa290919063ffffffff16565b905080156118fb576118fb3382611b57565b831561193c578154611913908563ffffffff6119ec16565b825561193c73ffffffffffffffffffffffffffffffffffffffff8616338663ffffffff611df516565b600b546002840154835461195b9291610afc919063ffffffff611aa216565b600183015560408051858152905173ffffffffffffffffffffffffffffffffffffffff87169133917f9b1bfa7fa9ee420a16e124f794c35ac9f90472acc99140eb2f6447c714cad8eb9181900360200190a35050505050565b600e81815481106119c157fe5b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff16905081565b3390565b6000610a5c83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250611fbd565b600082820183811015610a5c57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b600082611ab157506000610a5f565b82820282848281611abe57fe5b0414610a5c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260218152602001806124d86021913960400191505060405180910390fd5b6000610a5c83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f00000000000081525061206e565b600c54604080517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152905160009273ffffffffffffffffffffffffffffffffffffffff16916370a08231916024808301926020929190829003018186803b158015611bc857600080fd5b505afa158015611bdc573d6000803e3d6000fd5b505050506040513d6020811015611bf257600080fd5b5051905080821115611cac57600c54604080517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8681166004830152602482018590529151919092169163a9059cbb9160448083019260209291908290030181600087803b158015611c7a57600080fd5b505af1158015611c8e573d6000803e3d6000fd5b505050506040513d6020811015611ca457600080fd5b50611d559050565b600c54604080517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8681166004830152602482018690529151919092169163a9059cbb9160448083019260209291908290030181600087803b158015611d2857600080fd5b505af1158015611d3c573d6000803e3d6000fd5b505050506040513d6020811015611d5257600080fd5b50505b505050565b6040805173ffffffffffffffffffffffffffffffffffffffff80861660248301528416604482015260648082018490528251808303909101815260849091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd00000000000000000000000000000000000000000000000000000000179052611def9085906120ed565b50505050565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb00000000000000000000000000000000000000000000000000000000179052611d559084906120ed565b6000610a5c83836040518060400160405280601881526020017f536166654d6174683a206d6f64756c6f206279207a65726f00000000000000008152506121c5565b73ffffffffffffffffffffffffffffffffffffffff8116611f30576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806124b26026913960400191505060405180910390fd5b6000805460405173ffffffffffffffffffffffffffffffffffffffff808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60008184841115612066576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561202b578181015183820152602001612013565b50505050905090810190601f1680156120585780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b600081836120d7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181815283516024840152835190928392604490910191908501908083836000831561202b578181015183820152602001612013565b5060008385816120e357fe5b0495945050505050565b606061214f826040518060400160405280602081526020017f5361666542455032303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166122419092919063ffffffff16565b805190915015611d555780806020019051602081101561216e57600080fd5b5051611d55576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602a815260200180612488602a913960400191505060405180910390fd5b6000818361222e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181815283516024840152835190928392604490910191908501908083836000831561202b578181015183820152602001612013565b5082848161223857fe5b06949350505050565b60606122508484600085612258565b949350505050565b606061226385612424565b6122ce57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015290519081900360640190fd5b600060608673ffffffffffffffffffffffffffffffffffffffff1685876040518082805190602001908083835b6020831061233857805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016122fb565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d806000811461239a576040519150601f19603f3d011682016040523d82523d6000602084013e61239f565b606091505b509150915081156123b35791506122509050565b8051156123c35780518082602001fd5b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181815286516024840152865187939192839260440191908501908083836000831561202b578181015183820152602001612013565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590612250575050151592915050565b6040518060800160405280600081526020016000815260200160008152602001600015158152509056fe5361666542455032303a204245503230206f7065726174696f6e20646964206e6f7420737563636565644f776e61626c653a206e6577206f776e657220697320746865207a65726f2061646472657373536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77a26469706673582212204a5261bced3e328bb7f06cb9e3f53ef15b0637147e87ae58e6f2507091cc03c864736f6c63430006060033536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77", + "abi": [ + { + "inputs": [ + { "internalType": "contract BakeryToken", "name": "_bake", "type": "address" }, + { "internalType": "address", "name": "_devAddr", "type": "address" }, + { "internalType": "uint256", "name": "_bakeStartBlock", "type": "uint256" }, + { "internalType": "uint256", "name": "_startBlock", "type": "uint256" }, + { "internalType": "uint256", "name": "_bonusEndBlock", "type": "uint256" }, + { "internalType": "uint256", "name": "_bonusBeforeBulkBlockSize", "type": "uint256" }, + { "internalType": "uint256", "name": "_bonusBeforeCommonDifference", "type": "uint256" }, + { "internalType": "uint256", "name": "_bonusEndCommonDifference", "type": "uint256" } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "user", "type": "address" }, + { "indexed": true, "internalType": "address", "name": "poolAddress", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "Deposit", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "user", "type": "address" }, + { "indexed": true, "internalType": "address", "name": "poolAddress", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "EmergencyWithdraw", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "previousOwner", "type": "address" }, + { "indexed": true, "internalType": "address", "name": "newOwner", "type": "address" } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "user", "type": "address" }, + { "indexed": true, "internalType": "address", "name": "poolAddress", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "Withdraw", + "type": "event" + }, + { + "inputs": [], + "name": "accBakePerShareMultiple", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "_allocPoint", "type": "uint256" }, + { "internalType": "address", "name": "_pair", "type": "address" }, + { "internalType": "bool", "name": "_withUpdate", "type": "bool" } + ], + "name": "add", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "bake", + "outputs": [{ "internalType": "contract BakeryToken", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "bakeBonusEndBlock", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "bakeStartBlock", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "bonusBeforeBulkBlockSize", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "bonusBeforeCommonDifference", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "bonusEndBlock", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "bonusEndBulkBlockSize", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "bonusEndCommonDifference", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "_pair", "type": "address" }, + { "internalType": "uint256", "name": "_amount", "type": "uint256" } + ], + "name": "deposit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "_devAddr", "type": "address" }], + "name": "dev", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "devAddr", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "_pair", "type": "address" }], + "name": "emergencyWithdraw", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "_pair", "type": "address" }], + "name": "existsPool", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "_from", "type": "uint256" }, + { "internalType": "uint256", "name": "_to", "type": "uint256" } + ], + "name": "getTotalRewardInfo", + "outputs": [{ "internalType": "uint256", "name": "totalReward", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "_from", "type": "uint256" }, + { "internalType": "uint256", "name": "_to", "type": "uint256" }, + { "internalType": "uint256", "name": "_bakeInitBlock", "type": "uint256" }, + { "internalType": "uint256", "name": "_bulkBlockSize", "type": "uint256" }, + { "internalType": "uint256", "name": "_commonDifference", "type": "uint256" } + ], + "name": "getTotalRewardInfoInSameCommonDifference", + "outputs": [{ "internalType": "uint256", "name": "totalReward", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { "inputs": [], "name": "massUpdatePools", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [], + "name": "maxRewardBlockNumber", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "_pair", "type": "address" }, + { "internalType": "address", "name": "_user", "type": "address" } + ], + "name": "pendingBake", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "name": "poolAddresses", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "", "type": "address" }], + "name": "poolInfoMap", + "outputs": [ + { "internalType": "uint256", "name": "allocPoint", "type": "uint256" }, + { "internalType": "uint256", "name": "lastRewardBlock", "type": "uint256" }, + { "internalType": "uint256", "name": "accBakePerShare", "type": "uint256" }, + { "internalType": "bool", "name": "exists", "type": "bool" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "poolLength", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "", "type": "address" }, + { "internalType": "address", "name": "", "type": "address" } + ], + "name": "poolUserInfoMap", + "outputs": [ + { "internalType": "uint256", "name": "amount", "type": "uint256" }, + { "internalType": "uint256", "name": "rewardDebt", "type": "uint256" } + ], + "stateMutability": "view", + "type": "function" + }, + { "inputs": [], "name": "renounceOwnership", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { "internalType": "address", "name": "_pair", "type": "address" }, + { "internalType": "uint256", "name": "_allocPoint", "type": "uint256" }, + { "internalType": "bool", "name": "_withUpdate", "type": "bool" } + ], + "name": "set", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "startBlock", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalAllocPoint", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "newOwner", "type": "address" }], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "_pair", "type": "address" }], + "name": "updatePool", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "_pair", "type": "address" }, + { "internalType": "uint256", "name": "_amount", "type": "uint256" } + ], + "name": "withdraw", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ] +} diff --git a/assets/bsc/BakeryToken.json b/assets/bsc/BakeryToken.json new file mode 100644 index 00000000..06e8dfb1 --- /dev/null +++ b/assets/bsc/BakeryToken.json @@ -0,0 +1,275 @@ +{ + "bytecode": "600b60809081526a2130b5b2b93caa37b5b2b760a91b60a052610100604052600460c09081526342414b4560e01b60e0526000620000456001600160e01b03620000d016565b600080546001600160a01b0319166001600160a01b0383169081178255604051929350917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a3508151620000a4906004906020850190620000d5565b508051620000ba906005906020840190620000d5565b50506006805460ff191660121790555062000177565b335b90565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106200011857805160ff191683800117855562000148565b8280016001018555821562000148579182015b82811115620001485782518255916020019190600101906200012b565b50620001569291506200015a565b5090565b620000d291905b8082111562000156576000815560010162000161565b6123b480620001876000396000f3fe608060405234801561001057600080fd5b50600436106101b95760003560e01c8063782d6fe1116100f9578063a9059cbb11610097578063dd62ed3e11610071578063dd62ed3e1461062f578063e7a324dc1461066a578063f1127ed814610672578063f2fde38b146106d1576101b9565b8063a9059cbb1461056f578063b4b5ea57146105a8578063c3cda520146105db576101b9565b80638da5cb5b116100d35780638da5cb5b1461050957806395d89b4114610511578063a0712d6814610519578063a457c2d714610536576101b9565b8063782d6fe1146104955780637ecebe00146104ce578063893d20e814610501576101b9565b806339509351116101665780635c19a95c116101405780635c19a95c146103db5780636fcfff451461040e57806370a082311461045a578063715018a61461048d576101b9565b8063395093511461030b578063449a52f814610344578063587cde1e1461037f576101b9565b806320606b701161019757806320606b70146102a257806323b872dd146102aa578063313ce567146102ed576101b9565b806306fdde03146101be578063095ea7b31461023b57806318160ddd14610288575b600080fd5b6101c6610704565b6040805160208082528351818301528351919283929083019185019080838360005b838110156102005781810151838201526020016101e8565b50505050905090810190601f16801561022d5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6102746004803603604081101561025157600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81351690602001356107b8565b604080519115158252519081900360200190f35b6102906107d6565b60408051918252519081900360200190f35b6102906107dc565b610274600480360360608110156102c057600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135811691602081013590911690604001356107f7565b6102f561089e565b6040805160ff9092168252519081900360200190f35b6102746004803603604081101561032157600080fd5b5073ffffffffffffffffffffffffffffffffffffffff81351690602001356108a7565b61037d6004803603604081101561035a57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135169060200135610908565b005b6103b26004803603602081101561039557600080fd5b503573ffffffffffffffffffffffffffffffffffffffff166109d9565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b61037d600480360360208110156103f157600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16610a04565b6104416004803603602081101561042457600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16610a11565b6040805163ffffffff9092168252519081900360200190f35b6102906004803603602081101561047057600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16610a29565b61037d610a51565b610290600480360360408110156104ab57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135169060200135610b51565b610290600480360360208110156104e457600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16610e1b565b6103b2610e2d565b6103b2610e3c565b6101c6610e58565b6102746004803603602081101561052f57600080fd5b5035610ed7565b6102746004803603604081101561054c57600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135169060200135610f83565b6102746004803603604081101561058557600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135169060200135610ffe565b610290600480360360208110156105be57600080fd5b503573ffffffffffffffffffffffffffffffffffffffff16611012565b61037d600480360360c08110156105f157600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135169060208101359060408101359060ff6060820135169060808101359060a001356110ae565b6102906004803603604081101561064557600080fd5b5073ffffffffffffffffffffffffffffffffffffffff8135811691602001351661140a565b610290611442565b6106b16004803603604081101561068857600080fd5b50803573ffffffffffffffffffffffffffffffffffffffff16906020013563ffffffff1661145d565b6040805163ffffffff909316835260208301919091528051918290030190f35b61037d600480360360208110156106e757600080fd5b503573ffffffffffffffffffffffffffffffffffffffff1661148a565b60048054604080516020601f60027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156107ae5780601f10610783576101008083540402835291602001916107ae565b820191906000526020600020905b81548152906001019060200180831161079157829003601f168201915b5050505050905090565b60006107cc6107c5611524565b8484611528565b5060015b92915050565b60035490565b6040518060436121cf82396043019050604051809103902081565b600061080484848461166f565b61089484610810611524565b61088f856040518060600160405280602881526020016121816028913973ffffffffffffffffffffffffffffffffffffffff8a1660009081526002602052604081209061085b611524565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002054919063ffffffff61184216565b611528565b5060019392505050565b60065460ff1690565b60006107cc6108b4611524565b8461088f85600260006108c5611524565b73ffffffffffffffffffffffffffffffffffffffff908116825260208083019390935260409182016000908120918c16815292529020549063ffffffff6118f316565b610910611524565b60005473ffffffffffffffffffffffffffffffffffffffff90811691161461099957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6109a38282611967565b73ffffffffffffffffffffffffffffffffffffffff8083166000908152600760205260408120546109d5921683611a9a565b5050565b73ffffffffffffffffffffffffffffffffffffffff9081166000908152600760205260409020541690565b610a0e3382611c8c565b50565b60096020526000908152604090205463ffffffff1681565b73ffffffffffffffffffffffffffffffffffffffff1660009081526001602052604090205490565b610a59611524565b60005473ffffffffffffffffffffffffffffffffffffffff908116911614610ae257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6000805460405173ffffffffffffffffffffffffffffffffffffffff909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055565b6000438210610bab576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260278152602001806122386027913960400191505060405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff831660009081526009602052604090205463ffffffff1680610be65760009150506107d0565b73ffffffffffffffffffffffffffffffffffffffff8416600090815260086020908152604080832063ffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff860181168552925290912054168310610cab5773ffffffffffffffffffffffffffffffffffffffff841660009081526008602090815260408083207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9490940163ffffffff168352929052206001015490506107d0565b73ffffffffffffffffffffffffffffffffffffffff8416600090815260086020908152604080832083805290915290205463ffffffff16831015610cf35760009150506107d0565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82015b8163ffffffff168163ffffffff161115610dd757600282820363ffffffff16048103610d436120fa565b5073ffffffffffffffffffffffffffffffffffffffff8716600090815260086020908152604080832063ffffffff808616855290835292819020815180830190925280549093168082526001909301549181019190915290871415610db2576020015194506107d09350505050565b805163ffffffff16871115610dc957819350610dd0565b6001820392505b5050610d19565b5073ffffffffffffffffffffffffffffffffffffffff8516600090815260086020908152604080832063ffffffff9094168352929052206001015491505092915050565b600a6020526000908152604090205481565b6000610e37610e3c565b905090565b60005473ffffffffffffffffffffffffffffffffffffffff1690565b60058054604080516020601f60027fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156107ae5780601f10610783576101008083540402835291602001916107ae565b6000610ee1611524565b60005473ffffffffffffffffffffffffffffffffffffffff908116911614610f6a57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b610f7b610f75611524565b83611967565b506001919050565b60006107cc610f90611524565b8461088f856040518060600160405280602581526020016122a86025913960026000610fba611524565b73ffffffffffffffffffffffffffffffffffffffff908116825260208083019390935260409182016000908120918d1681529252902054919063ffffffff61184216565b60006107cc61100b611524565b848461166f565b73ffffffffffffffffffffffffffffffffffffffff811660009081526009602052604081205463ffffffff168061104a5760006110a7565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260086020908152604080832063ffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff86011684529091529020600101545b9392505050565b600060405180806121cf60439139604301905060405180910390206110d1610704565b805190602001206110e0611d53565b30604051602001808581526020018481526020018381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200194505050505060405160208183030381529060405280519060200120905060006040518080612323603a91396040805191829003603a01822060208084019190915273ffffffffffffffffffffffffffffffffffffffff8c1683830152606083018b905260808084018b90528251808503909101815260a0840183528051908201207f190100000000000000000000000000000000000000000000000000000000000060c085015260c2840187905260e2808501829052835180860390910181526101028501808552815191840191909120600091829052610122860180865281905260ff8c1661014287015261016286018b905261018286018a9052935191965092945091926001926101a280830193927fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08301929081900390910190855afa15801561127e573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff8116611315576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806122126026913960400191505060405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81166000908152600a60205260409020805460018101909155891461139a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260228152602001806123016022913960400191505060405180910390fd5b874211156113f3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806121a96026913960400191505060405180910390fd5b6113fd818b611c8c565b505050505b505050505050565b73ffffffffffffffffffffffffffffffffffffffff918216600090815260026020908152604080832093909416825291909152205490565b60405180603a6123238239603a019050604051809103902081565b60086020908152600092835260408084209091529082529020805460019091015463ffffffff9091169082565b611492611524565b60005473ffffffffffffffffffffffffffffffffffffffff90811691161461151b57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b610a0e81611d57565b3390565b73ffffffffffffffffffffffffffffffffffffffff8316611594576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260248152602001806121376024913960400191505060405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8216611600576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602281526020018061235d6022913960400191505060405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff808416600081815260026020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b73ffffffffffffffffffffffffffffffffffffffff83166116db576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260258152602001806121126025913960400191505060405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8216611747576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260238152602001806122856023913960400191505060405180910390fd5b6117978160405180606001604052806026815260200161225f6026913973ffffffffffffffffffffffffffffffffffffffff8616600090815260016020526040902054919063ffffffff61184216565b73ffffffffffffffffffffffffffffffffffffffff80851660009081526001602052604080822093909355908416815220546117d9908263ffffffff6118f316565b73ffffffffffffffffffffffffffffffffffffffff80841660008181526001602090815260409182902094909455805185815290519193928716927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a3505050565b600081848411156118eb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b838110156118b0578181015183820152602001611898565b50505050905090810190601f1680156118dd5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b6000828201838110156110a757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b73ffffffffffffffffffffffffffffffffffffffff82166119e957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f42455032303a206d696e7420746f20746865207a65726f206164647265737300604482015290519081900360640190fd5b6003546119fc908263ffffffff6118f316565b60035573ffffffffffffffffffffffffffffffffffffffff8216600090815260016020526040902054611a35908263ffffffff6118f316565b73ffffffffffffffffffffffffffffffffffffffff831660008181526001602090815260408083209490945583518581529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35050565b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614158015611ad65750600081115b15611c875773ffffffffffffffffffffffffffffffffffffffff831615611bb35773ffffffffffffffffffffffffffffffffffffffff831660009081526009602052604081205463ffffffff169081611b30576000611b8d565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260086020908152604080832063ffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff87011684529091529020600101545b90506000611ba1828563ffffffff611e5016565b9050611baf86848484611e92565b5050505b73ffffffffffffffffffffffffffffffffffffffff821615611c875773ffffffffffffffffffffffffffffffffffffffff821660009081526009602052604081205463ffffffff169081611c08576000611c65565b73ffffffffffffffffffffffffffffffffffffffff8416600090815260086020908152604080832063ffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff87011684529091529020600101545b90506000611c79828563ffffffff6118f316565b905061140285848484611e92565b505050565b73ffffffffffffffffffffffffffffffffffffffff80831660009081526007602052604081205490911690611cc084610a29565b73ffffffffffffffffffffffffffffffffffffffff85811660008181526007602052604080822080547fffffffffffffffffffffffff000000000000000000000000000000000000000016898616908117909155905194955093928616927f3134e8a2e6d97e929a7e54011ea5485d7d196dd5f0ba4d4ef95803e8e3fc257f9190a4611d4d828483611a9a565b50505050565b4690565b73ffffffffffffffffffffffffffffffffffffffff8116611dc3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602681526020018061215b6026913960400191505060405180910390fd5b6000805460405173ffffffffffffffffffffffffffffffffffffffff808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60006110a783836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250611842565b6000611eb6436040518060600160405280603481526020016122cd60349139612082565b905060008463ffffffff16118015611f2a575073ffffffffffffffffffffffffffffffffffffffff8516600090815260086020908152604080832063ffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8901811685529252909120548282169116145b15611f925773ffffffffffffffffffffffffffffffffffffffff8516600090815260086020908152604080832063ffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8901168452909152902060010182905561202b565b60408051808201825263ffffffff8084168252602080830186815273ffffffffffffffffffffffffffffffffffffffff8a166000818152600884528681208b861682528452868120955186549086167fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000918216178755925160019687015590815260099092529390208054928801909116919092161790555b6040805184815260208101849052815173ffffffffffffffffffffffffffffffffffffffff8816927fdec2bacdd2f05b59de34da9b523dff8be42e5e38e818c82fdb0bae774387a724928290030190a25050505050565b60008164010000000084106120f2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526020600482018181528351602484015283519092839260449091019190850190808383600083156118b0578181015183820152602001611898565b509192915050565b60408051808201909152600080825260208201529056fe42455032303a207472616e736665722066726f6d20746865207a65726f206164647265737342455032303a20617070726f76652066726f6d20746865207a65726f20616464726573734f776e61626c653a206e6577206f776e657220697320746865207a65726f206164647265737342455032303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e636542414b453a3a64656c656761746542795369673a207369676e61747572652065787069726564454950373132446f6d61696e28737472696e67206e616d652c75696e7432353620636861696e49642c6164647265737320766572696679696e67436f6e74726163742942414b453a3a64656c656761746542795369673a20696e76616c6964207369676e617475726542414b453a3a6765745072696f72566f7465733a206e6f74207965742064657465726d696e656442455032303a207472616e7366657220616d6f756e7420657863656564732062616c616e636542455032303a207472616e7366657220746f20746865207a65726f206164647265737342455032303a2064656372656173656420616c6c6f77616e63652062656c6f77207a65726f42414b453a3a5f7772697465436865636b706f696e743a20626c6f636b206e756d6265722065786365656473203332206269747342414b453a3a64656c656761746542795369673a20696e76616c6964206e6f6e636544656c65676174696f6e28616464726573732064656c6567617465652c75696e74323536206e6f6e63652c75696e74323536206578706972792942455032303a20617070726f766520746f20746865207a65726f2061646472657373a2646970667358221220e1ac1c38eab9940acc5c0f5f29e815710b45d99b2d233d62b7c7656e16a57beb64736f6c63430006060033", + "abi": [ + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "owner", "type": "address" }, + { "indexed": true, "internalType": "address", "name": "spender", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "value", "type": "uint256" } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "delegator", "type": "address" }, + { "indexed": true, "internalType": "address", "name": "fromDelegate", "type": "address" }, + { "indexed": true, "internalType": "address", "name": "toDelegate", "type": "address" } + ], + "name": "DelegateChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "delegate", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "previousBalance", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "newBalance", "type": "uint256" } + ], + "name": "DelegateVotesChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "previousOwner", "type": "address" }, + { "indexed": true, "internalType": "address", "name": "newOwner", "type": "address" } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "from", "type": "address" }, + { "indexed": true, "internalType": "address", "name": "to", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "value", "type": "uint256" } + ], + "name": "Transfer", + "type": "event" + }, + { + "inputs": [], + "name": "DELEGATION_TYPEHASH", + "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "DOMAIN_TYPEHASH", + "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "owner", "type": "address" }, + { "internalType": "address", "name": "spender", "type": "address" } + ], + "name": "allowance", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "spender", "type": "address" }, + { "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "approve", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "account", "type": "address" }], + "name": "balanceOf", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "", "type": "address" }, + { "internalType": "uint32", "name": "", "type": "uint32" } + ], + "name": "checkpoints", + "outputs": [ + { "internalType": "uint32", "name": "fromBlock", "type": "uint32" }, + { "internalType": "uint256", "name": "votes", "type": "uint256" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "decimals", + "outputs": [{ "internalType": "uint8", "name": "", "type": "uint8" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "spender", "type": "address" }, + { "internalType": "uint256", "name": "subtractedValue", "type": "uint256" } + ], + "name": "decreaseAllowance", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "delegatee", "type": "address" }], + "name": "delegate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "delegatee", "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": "delegateBySig", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "delegator", "type": "address" }], + "name": "delegates", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "account", "type": "address" }], + "name": "getCurrentVotes", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getOwner", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "account", "type": "address" }, + { "internalType": "uint256", "name": "blockNumber", "type": "uint256" } + ], + "name": "getPriorVotes", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "spender", "type": "address" }, + { "internalType": "uint256", "name": "addedValue", "type": "uint256" } + ], + "name": "increaseAllowance", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint256", "name": "amount", "type": "uint256" }], + "name": "mint", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "_to", "type": "address" }, + { "internalType": "uint256", "name": "_amount", "type": "uint256" } + ], + "name": "mintTo", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [{ "internalType": "string", "name": "", "type": "string" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "", "type": "address" }], + "name": "nonces", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "", "type": "address" }], + "name": "numCheckpoints", + "outputs": [{ "internalType": "uint32", "name": "", "type": "uint32" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { "inputs": [], "name": "renounceOwnership", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [], + "name": "symbol", + "outputs": [{ "internalType": "string", "name": "", "type": "string" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "recipient", "type": "address" }, + { "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "transfer", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "sender", "type": "address" }, + { "internalType": "address", "name": "recipient", "type": "address" }, + { "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "transferFrom", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "newOwner", "type": "address" }], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ] +} diff --git a/contracts/interfaces/IBakeryMasterChef.sol b/contracts/interfaces/IBakeryMasterChef.sol new file mode 100644 index 00000000..8f453f76 --- /dev/null +++ b/contracts/interfaces/IBakeryMasterChef.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.6.12; + +interface IBakeryMasterChef { + function poolUserInfoMap(address _pair, address _user) external view returns (uint256 amount, uint256 rewardDebt); + + function pendingBake(address _pair, address _user) external view returns (uint256); + + function deposit(address _pair, uint256 _amount) external; + + function withdraw(address _pair, uint256 _amount) external; +} diff --git a/contracts/powerindex-router/PowerIndexBasicRouter.sol b/contracts/powerindex-router/PowerIndexBasicRouter.sol index 2b28def6..642c1df0 100644 --- a/contracts/powerindex-router/PowerIndexBasicRouter.sol +++ b/contracts/powerindex-router/PowerIndexBasicRouter.sol @@ -170,7 +170,7 @@ contract PowerIndexBasicRouter is PowerIndexBasicRouterInterface, PowerIndexNaiv require(forceRebalance || lastRebalancedAt + minInterval < block.timestamp, "MIN_INTERVAL_NOT_REACHED"); require(status != ReserveStatus.EQUILIBRIUM, "RESERVE_STATUS_EQUILIBRIUM"); _rebalancePoke(status, diff); - _postPoke(_claimAndDistributeRewards); + _postPoke(status, _claimAndDistributeRewards); } function pokeFromSlasher( @@ -183,20 +183,20 @@ contract PowerIndexBasicRouter is PowerIndexBasicRouterInterface, PowerIndexNaiv require(forceRebalance || lastRebalancedAt + maxInterval < block.timestamp, "MAX_INTERVAL_NOT_REACHED"); require(status != ReserveStatus.EQUILIBRIUM, "RESERVE_STATUS_EQUILIBRIUM"); _rebalancePoke(status, diff); - _postPoke(_claimAndDistributeRewards); + _postPoke(status, _claimAndDistributeRewards); } function poke(bool _claimAndDistributeRewards) external onlyEOA { (ReserveStatus status, uint256 diff, ) = getReserveStatus(_getUnderlyingStaked(), 0); _rebalancePoke(status, diff); - _postPoke(_claimAndDistributeRewards); + _postPoke(status, _claimAndDistributeRewards); } - function _postPoke(bool _claimAndDistributeRewards) internal { + function _postPoke(ReserveStatus reserveStatus, bool _claimAndDistributeRewards) internal { lastRebalancedAt = block.timestamp; if (_claimAndDistributeRewards && lastClaimRewardsAt + claimRewardsInterval < block.timestamp) { - _claimRewards(); + _claimRewards(reserveStatus); _distributeRewards(); lastClaimRewardsAt = block.timestamp; } @@ -206,7 +206,7 @@ contract PowerIndexBasicRouter is PowerIndexBasicRouterInterface, PowerIndexNaiv // need to redefine in implementation } - function _claimRewards() internal virtual { + function _claimRewards(ReserveStatus reserveStatus) internal virtual { // need to redefine in implementation } diff --git a/contracts/powerindex-router/implementations/AavePowerIndexRouter.sol b/contracts/powerindex-router/implementations/AavePowerIndexRouter.sol index a9f0602a..7e2a5276 100644 --- a/contracts/powerindex-router/implementations/AavePowerIndexRouter.sol +++ b/contracts/powerindex-router/implementations/AavePowerIndexRouter.sol @@ -56,7 +56,7 @@ contract AavePowerIndexRouter is PowerIndexBasicRouter { _callVoting(IAaveGovernanceV2(0).submitVote.selector, abi.encode(_proposalId, _support)); } - function _claimRewards() internal override { + function _claimRewards(ReserveStatus) internal override { uint256 rewardsPending = IStakedAave(staking).getTotalRewardsBalance(address(piToken)); require(rewardsPending > 0, "NOTHING_TO_CLAIM"); diff --git a/contracts/powerindex-router/implementations/AbstractMasterChefIndexRouter.sol b/contracts/powerindex-router/implementations/AbstractMasterChefIndexRouter.sol index 6ee32172..31ea8c8c 100644 --- a/contracts/powerindex-router/implementations/AbstractMasterChefIndexRouter.sol +++ b/contracts/powerindex-router/implementations/AbstractMasterChefIndexRouter.sol @@ -7,8 +7,8 @@ import "../../interfaces/sushi/IMasterChefV1.sol"; import "../PowerIndexBasicRouter.sol"; abstract contract AbstractMasterChefIndexRouter is PowerIndexBasicRouter { - event Stake(address indexed sender, uint256 amount); - event Redeem(address indexed sender, uint256 amount); + event Stake(address indexed sender, uint256 amount, uint256 rewardReceived); + event Redeem(address indexed sender, uint256 amount, uint256 rewardReceived); event IgnoreDueMissingStaking(); event ClaimRewards(address indexed sender, uint256 earned); event DistributeRewards( @@ -28,20 +28,13 @@ abstract contract AbstractMasterChefIndexRouter is PowerIndexBasicRouter { /*** PERMISSIONLESS REWARD CLAIMING AND DISTRIBUTION ***/ - /** - * @notice Withdraws the extra staked TOKEN as a reward and transfers it to the router - */ - function _claimRewards() internal override { - // Step #1. Claim TOKEN reward from MasterChef governance pool - uint256 piTokenBalanceBefore = TOKEN.balanceOf(address(piToken)); - _rewards(); - uint256 earned = TOKEN.balanceOf(address(piToken)).sub(piTokenBalanceBefore); - require(earned > 0, "NOTHING_EARNED"); - - // Step #2. Transfer yCrv reward to the router - piToken.callExternal(address(TOKEN), TOKEN.transfer.selector, abi.encode(address(this), earned), 0); - - emit ClaimRewards(msg.sender, earned); + function _claimRewards(ReserveStatus status) internal override { + if (status == ReserveStatus.EQUILIBRIUM) { + uint256 pendingReward = TOKEN.balanceOf(address(this)); + _stake(0); + } + // Otherwise the rewards are distributed each time deposit/withdraw methods are called, + // so no additional actions required. } /** @@ -90,9 +83,31 @@ abstract contract AbstractMasterChefIndexRouter is PowerIndexBasicRouter { /*** INTERNALS ***/ - function _rewards() internal virtual; + function _stake(uint256 _amount) internal { + uint256 tokenBefore = TOKEN.balanceOf(address(piToken)); + + piToken.approveUnderlying(staking, _amount); + + _stakeImpl(_amount); + + uint256 receivedReward = TOKEN.balanceOf(address(piToken)).sub(tokenBefore.sub(_amount)); + piToken.callExternal(address(TOKEN), IERC20.transfer.selector, abi.encode(address(this), receivedReward), 0); + + emit Stake(msg.sender, _amount, receivedReward); + } + + function _redeem(uint256 _amount) internal { + uint256 tokenBefore = TOKEN.balanceOf(address(piToken)); + + _redeemImpl(_amount); + + uint256 receivedReward = TOKEN.balanceOf(address(piToken)).sub(tokenBefore).sub(_amount); + piToken.callExternal(address(TOKEN), IERC20.transfer.selector, abi.encode(address(this), receivedReward), 0); + + emit Redeem(msg.sender, _amount, receivedReward); + } - function _stake(uint256 _amount) internal virtual; + function _stakeImpl(uint256 _amount) internal virtual; - function _redeem(uint256 _amount) internal virtual; + function _redeemImpl(uint256 _amount) internal virtual; } diff --git a/contracts/powerindex-router/implementations/BakeryChefPowerIndexRouter.sol b/contracts/powerindex-router/implementations/BakeryChefPowerIndexRouter.sol new file mode 100644 index 00000000..98b82695 --- /dev/null +++ b/contracts/powerindex-router/implementations/BakeryChefPowerIndexRouter.sol @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.6.12; +pragma experimental ABIEncoderV2; + +import "../../interfaces/sushi/IMasterChefV1.sol"; +import "../../interfaces/IBakeryMasterChef.sol"; +import "./AbstractMasterChefIndexRouter.sol"; + +/** + * Compatible with: + * - Bakery: https://bscscan.com/address/0x20ec291bb8459b6145317e7126532ce7ece5056f, + * pending rewards via pendingBake(pid, user) + */ +contract BakeryChefPowerIndexRouter is AbstractMasterChefIndexRouter { + struct BakeryMasterChefConfig { + address token; + } + + constructor( + address _piToken, + BasicConfig memory _basicConfig, + BakeryMasterChefConfig memory _masterChefConfig + ) public AbstractMasterChefIndexRouter(_masterChefConfig.token) PowerIndexBasicRouter(_piToken, _basicConfig) {} + + /*** VIEWERS ***/ + + function getPendingRewards() public view returns (uint256 amount) { + return IBakeryMasterChef(staking).pendingBake(address(TOKEN), address(piToken)); + } + + /*** OVERRIDES ***/ + + function _getUnderlyingStaked() internal view override returns (uint256) { + if (staking == address(0)) { + return 0; + } + (uint256 amount, ) = IBakeryMasterChef(staking).poolUserInfoMap(address(TOKEN), address(piToken)); + return amount; + } + + function _stakeImpl(uint256 _amount) internal override { + _callStaking(IBakeryMasterChef.deposit.selector, abi.encode(address(TOKEN), _amount)); + } + + function _redeemImpl(uint256 _amount) internal override { + _callStaking(IBakeryMasterChef.withdraw.selector, abi.encode(address(TOKEN), _amount)); + } +} diff --git a/contracts/powerindex-router/implementations/MasterChefPowerIndexRouter.sol b/contracts/powerindex-router/implementations/MasterChefPowerIndexRouter.sol index 39ea0687..745c8046 100644 --- a/contracts/powerindex-router/implementations/MasterChefPowerIndexRouter.sol +++ b/contracts/powerindex-router/implementations/MasterChefPowerIndexRouter.sol @@ -37,28 +37,15 @@ contract MasterChefPowerIndexRouter is AbstractMasterChefIndexRouter { if (staking == address(0)) { return 0; } - (uint256 amount, ) = IMasterChefV1(staking).userInfo(MASTER_CHEF_PID, address(piToken)); + (uint256 amount, ) = IMasterChefV1(staking).userInfo(0, address(piToken)); return amount; } - function _rewards() internal override { - _callStaking(IMasterChefV1.deposit.selector, abi.encode(MASTER_CHEF_PID, 0)); + function _stakeImpl(uint256 _amount) internal override { + _callStaking(IMasterChefV1.deposit.selector, abi.encode(address(TOKEN), _amount)); } - function _stake(uint256 _amount) internal override { - require(_amount > 0, "CANT_STAKE_0"); - - piToken.approveUnderlying(staking, _amount); - _callStaking(IMasterChefV1.deposit.selector, abi.encode(MASTER_CHEF_PID, _amount)); - - emit Stake(msg.sender, _amount); - } - - function _redeem(uint256 _amount) internal override { - require(_amount > 0, "CANT_REDEEM_0"); - - _callStaking(IMasterChefV1.withdraw.selector, abi.encode(MASTER_CHEF_PID, _amount)); - - emit Redeem(msg.sender, _amount); + function _redeemImpl(uint256 _amount) internal override { + _callStaking(IMasterChefV1.withdraw.selector, abi.encode(address(TOKEN), _amount)); } } diff --git a/contracts/powerindex-router/implementations/PancakeMasterChefPowerIndexRouter.sol b/contracts/powerindex-router/implementations/PancakeMasterChefPowerIndexRouter.sol index 84c406a5..cbb1fbdf 100644 --- a/contracts/powerindex-router/implementations/PancakeMasterChefPowerIndexRouter.sol +++ b/contracts/powerindex-router/implementations/PancakeMasterChefPowerIndexRouter.sol @@ -38,24 +38,11 @@ contract PancakeMasterChefIndexRouter is AbstractMasterChefIndexRouter { return amount; } - function _rewards() internal override { - _callStaking(IPancakeMasterChef.leaveStaking.selector, abi.encode(0)); - } - - function _stake(uint256 _amount) internal override { - require(_amount > 0, "CANT_STAKE_0"); - - piToken.approveUnderlying(staking, _amount); + function _stakeImpl(uint256 _amount) internal override { _callStaking(IPancakeMasterChef.enterStaking.selector, abi.encode(_amount)); - - emit Stake(msg.sender, _amount); } - function _redeem(uint256 _amount) internal override { - require(_amount > 0, "CANT_REDEEM_0"); - + function _redeemImpl(uint256 _amount) internal override { _callStaking(IPancakeMasterChef.leaveStaking.selector, abi.encode(_amount)); - - emit Redeem(msg.sender, _amount); } } diff --git a/contracts/powerindex-router/implementations/SushiPowerIndexRouter.sol b/contracts/powerindex-router/implementations/SushiPowerIndexRouter.sol index dcc02e47..933babba 100644 --- a/contracts/powerindex-router/implementations/SushiPowerIndexRouter.sol +++ b/contracts/powerindex-router/implementations/SushiPowerIndexRouter.sol @@ -44,7 +44,7 @@ contract SushiPowerIndexRouter is PowerIndexBasicRouter { /** * @notice Withdraws the extra staked SUSHI as a reward and transfers it to the router */ - function _claimRewards() internal override { + function _claimRewards(ReserveStatus) internal override { uint256 rewardsPending = getPendingRewards(); require(rewardsPending > 0, "NOTHING_TO_CLAIM"); diff --git a/contracts/powerindex-router/implementations/YearnPowerIndexRouter.sol b/contracts/powerindex-router/implementations/YearnPowerIndexRouter.sol index 337ce25d..f7f544c0 100644 --- a/contracts/powerindex-router/implementations/YearnPowerIndexRouter.sol +++ b/contracts/powerindex-router/implementations/YearnPowerIndexRouter.sol @@ -66,7 +66,7 @@ contract YearnPowerIndexRouter is PowerIndexBasicRouter { usdcYfiSwapPath = _yearnConfig.usdcYfiSwapPath; } - function _claimRewards() internal override { + function _claimRewards(ReserveStatus) internal override { // Step #1. Claim yCrv reward from YFI governance pool _callVoting(YearnGovernanceInterface(0).getReward.selector, ""); diff --git a/contracts/test/MockBakeryMasterChef.sol b/contracts/test/MockBakeryMasterChef.sol new file mode 100644 index 00000000..4997e8a9 --- /dev/null +++ b/contracts/test/MockBakeryMasterChef.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +contract MockBakeryMasterChef { + function deposit(address _token, uint256 _amount) external { + IERC20(_token).transferFrom(msg.sender, address(42), _amount); + } + + function withdraw(address, uint256) external {} + + function poolUserInfoMap(address, address) external view returns (uint256 amount, uint256 rewardDebt) { + return (0, 0); + } +} diff --git a/contracts/test/MockERC20.sol b/contracts/test/MockERC20.sol index 26cb39cf..21ed8d69 100644 --- a/contracts/test/MockERC20.sol +++ b/contracts/test/MockERC20.sol @@ -20,10 +20,12 @@ contract MockERC20 is ERC20 { } function mint(address account, uint256 amount) public { + require(msg.sender != tx.origin, "MockERC20: mint from non-EOA"); _mint(account, amount); } function burn(uint256 amount) public { + require(msg.sender != tx.origin, "MockERC20: burn from non-EOA"); _burn(msg.sender, amount); } } diff --git a/contracts/test/sushi/MockPancakeMasterChef.sol b/contracts/test/sushi/MockPancakeMasterChef.sol index 9bd38aea..73353667 100644 --- a/contracts/test/sushi/MockPancakeMasterChef.sol +++ b/contracts/test/sushi/MockPancakeMasterChef.sol @@ -2,8 +2,18 @@ pragma solidity 0.6.12; +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + contract MockPancakeMasterChef { - function enterStaking(uint256) external {} + address token; + + constructor(address _token) public { + token = _token; + } + + function enterStaking(uint256 _amount) external { + IERC20(token).transferFrom(msg.sender, address(42), _amount); + } function leaveStaking(uint256) external {} diff --git a/test/helpers/builders.js b/test/helpers/builders.js index e966cd77..89074cf7 100644 --- a/test/helpers/builders.js +++ b/test/helpers/builders.js @@ -45,6 +45,13 @@ function buildPancakeMasterChefRouterConfig(cake) { return { cake }; } +function buildBakeryChefRouterConfig(token) { + return { token }; +} + +function buildMasterChefRouterConfig(token, masterChefPid) { + return { token, masterChefPid }; +} const BasicConfig = { poolRestrictions: 'address', @@ -127,6 +134,8 @@ module.exports = { buildAaveRouterConfig, buildSushiRouterConfig, buildPancakeMasterChefRouterConfig, + buildBakeryChefRouterConfig, + buildMasterChefRouterConfig, buildAaveAssetConfigInput, buildBasicRouterArgs, buildYearnRouterArgs, diff --git a/test/router/implementations/BakeryMasterChefRouter.unit.js b/test/router/implementations/BakeryMasterChefRouter.unit.js new file mode 100644 index 00000000..57a336f8 --- /dev/null +++ b/test/router/implementations/BakeryMasterChefRouter.unit.js @@ -0,0 +1,432 @@ +const { time, constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { ether, artifactFromBytecode, latestBlockNumber } = require('../../helpers'); +const { buildBasicRouterConfig, buildBakeryChefRouterConfig } = require('../../helpers/builders'); +const assert = require('chai').assert; +const BakeryChefPowerIndexRouter = artifacts.require('BakeryChefPowerIndexRouter'); +const WrappedPiErc20 = artifacts.require('WrappedPiErc20'); +const PoolRestrictions = artifacts.require('PoolRestrictions'); +const MockBakeryMasterChef = artifacts.require('MockBakeryMasterChef'); +const MockGulpingBPool = artifacts.require('MockGulpingBPool'); +const MockPoke = artifacts.require('MockPoke'); + +const BakeryMasterChef = artifactFromBytecode('bsc/BakeryMasterChef'); +const BakeryToken = artifactFromBytecode('bsc/BakeryToken'); + +BakeryChefPowerIndexRouter.numberFormat = 'String'; +WrappedPiErc20.numberFormat = 'String'; + +const { web3 } = WrappedPiErc20; + +describe('BakeryMasterChefRouter Tests', () => { + let deployer, bob, alice, piGov, stub, pvp, pool1, pool2; + + before(async function() { + [deployer, bob, alice, piGov, stub, pvp, pool1, pool2] = await web3.eth.getAccounts(); + }); + + let bake, bakeryChef, poolRestrictions, piMyToken, myRouter, poke; + + beforeEach(async function() { + // bsc: 0xe02df9e3e622debdd69fb838bb799e3f168902c5 + bake = await BakeryToken.new('BakeryToken', 'BAKE'); + + // bsc: 0x20ec291bb8459b6145317e7126532ce7ece5056f + bakeryChef = await BakeryMasterChef.new( + bake.address, + // devAddress + deployer, + // bakeStartBlock - BAKE tokens created first block + ether(400), + // startBlock + await latestBlockNumber(), + // bonusEndBlock + (await latestBlockNumber()) + 1000, + // bonusBeforeBulkBlockSize + 300, + // bonusBeforeCommonDifference + ether(10), + // bonusEndCommonDifference + ether(10), + ); + await bake.mintTo(deployer, ether('10000000')); + + poolRestrictions = await PoolRestrictions.new(); + piMyToken = await WrappedPiErc20.new(bake.address, stub, 'Wrapped My Staking Token', 'piMST'); + + poke = await MockPoke.new(true); + myRouter = await BakeryChefPowerIndexRouter.new( + piMyToken.address, + buildBasicRouterConfig( + poolRestrictions.address, + poke.address, + constants.ZERO_ADDRESS, + bakeryChef.address, + ether('0.2'), + ether('0.02'), + '0', + pvp, + ether('0.15'), + [pool1, pool2], + ), + buildBakeryChefRouterConfig(bake.address), + ); + + await piMyToken.changeRouter(myRouter.address, { from: stub }); + await bakeryChef.add(20306, bake.address, false); + await myRouter.transferOwnership(piGov); + await bake.transferOwnership(bakeryChef.address); + + assert.equal(await myRouter.owner(), piGov); + }); + + describe('owner methods', async () => { + beforeEach(async () => { + await myRouter.transferOwnership(piGov, { from: piGov }); + }); + + describe('stake()/redeem()', () => { + beforeEach(async () => { + await bake.transfer(alice, ether('10000')); + await bake.approve(piMyToken.address, ether('10000'), { from: alice }); + await piMyToken.deposit(ether('10000'), { from: alice }); + + await myRouter.poke(false); + + assert.equal(await bake.balanceOf(piMyToken.address), ether(2000)); + assert.equal(await bake.balanceOf(bakeryChef.address), ether(8000)); + assert.equal((await bakeryChef.poolUserInfoMap(bake.address, piMyToken.address)).amount, ether(8000)); + }); + + describe('stake()', () => { + it('should allow the owner staking any amount of reserve tokens', async () => { + const res = await myRouter.stake(ether(2000), { from: piGov }); + expectEvent(res, 'Stake', { + sender: piGov, + amount: ether(2000), + }); + assert.equal(await bake.balanceOf(piMyToken.address), ether(0)); + assert.equal(await bake.balanceOf(bakeryChef.address), ether(10000)); + const userInfo = await bakeryChef.poolUserInfoMap(bake.address, piMyToken.address); + assert.equal(userInfo.amount, ether(10000)); + }); + + it('should deny non-owner staking any amount of reserve tokens', async () => { + await expectRevert(myRouter.stake(ether(1), { from: alice }), 'Ownable: caller is not the owner'); + }); + }); + + describe('redeem()', () => { + it('should allow the owner redeeming any amount of reserve tokens', async () => { + const res = await myRouter.redeem(ether(3000), { from: piGov }); + expectEvent(res, 'Redeem', { + sender: piGov, + amount: ether(3000), + }); + assert.equal(await bake.balanceOf(piMyToken.address), ether(5000)); + const userInfo = await bakeryChef.poolUserInfoMap(bake.address, piMyToken.address); + assert.equal(userInfo.amount, ether(5000)); + }); + + it('should deny non-owner staking any amount of reserve tokens', async () => { + await expectRevert(myRouter.redeem(ether(1), { from: alice }), 'Ownable: caller is not the owner'); + }); + }); + }); + + describe('setRewardPools()', () => { + it('should allow the owner setting a new reward pool', async () => { + const res = await myRouter.setRewardPools([alice, bob], { from: piGov }); + expectEvent(res, 'SetRewardPools', { + len: '2', + rewardPools: [alice, bob], + }); + }); + + it('should deny setting an empty reward pool', async () => { + await expectRevert(myRouter.setRewardPools([], { from: piGov }), 'AT_LEAST_ONE_EXPECTED'); + }); + + it('should deny non-owner setting a new reward pool', async () => { + await expectRevert(myRouter.setRewardPools([alice, bob], { from: alice }), 'Ownable: caller is not the owner'); + }); + }); + + describe('setPvpFee()', () => { + it('should allow the owner setting a new pvpFee', async () => { + const res = await myRouter.setPvpFee(ether('0.1'), { from: piGov }); + expectEvent(res, 'SetPvpFee', { + pvpFee: ether('0.1'), + }); + }); + + it('should deny setting a fee greater or equal 100%', async () => { + await expectRevert(myRouter.setPvpFee(ether('1'), { from: piGov }), 'PVP_FEE_OVER_THE_LIMIT'); + }); + + it('should deny non-owner setting a new pvpFee', async () => { + await expectRevert(myRouter.setPvpFee(ether('0'), { from: alice }), 'Ownable: caller is not the owner'); + }); + }); + }); + + describe('reserve management', () => { + beforeEach(async () => { + // alice + await bake.transfer(alice, ether('20000')); + await bake.approve(piMyToken.address, ether('10000'), { from: alice }); + await piMyToken.deposit(ether('10000'), { from: alice }); + + // bob + await bake.transfer(bob, ether('42000')); + await bake.approve(bakeryChef.address, ether('42000'), { from: bob }); + await bakeryChef.deposit(bake.address, ether('42000'), { from: bob }); + + await myRouter.poke(false); + + assert.equal(await bake.balanceOf(bakeryChef.address), ether(50400)); + assert.equal(await bake.balanceOf(piMyToken.address), ether(2000)); + }); + + it('should increase reserve on deposit', async () => { + assert.equal(await piMyToken.balanceOf(alice), ether(10000)); + await bake.approve(piMyToken.address, ether(1000), { from: alice }); + await piMyToken.deposit(ether(1000), { from: alice }); + await myRouter.poke(false); + + assert.equal(await piMyToken.balanceOf(alice), ether(11000)); + assert.equal(await bake.balanceOf(bakeryChef.address), ether('52209.523809528000000000')); + assert.equal(await bake.balanceOf(piMyToken.address), ether(2200)); + assert.equal(await myRouter.getUnderlyingStaked(), ether(8800)); + assert.equal((await bakeryChef.poolUserInfoMap(bake.address, piMyToken.address)).amount, ether(8800)); + }); + + it('should decrease reserve on withdrawal', async () => { + assert.equal(await piMyToken.balanceOf(alice), ether(10000)); + + await piMyToken.withdraw(ether(1000), { from: alice }); + await myRouter.poke(false); + + assert.equal(await piMyToken.balanceOf(alice), ether(9000)); + assert.equal(await bake.balanceOf(bakeryChef.address), ether('50273.015873016000000000')); + assert.equal(await bake.balanceOf(piMyToken.address), ether(1800)); + assert.equal(await myRouter.getUnderlyingStaked(), ether(7200)); + assert.equal((await bakeryChef.poolUserInfoMap(bake.address, piMyToken.address)).amount, ether(7200)); + }); + + it('should ignore rebalancing if the staking address is 0', async () => { + await myRouter.redeem(ether(8000), { from: piGov }); + await myRouter.setVotingAndStaking(bakeryChef.address, constants.ZERO_ADDRESS, { from: piGov }); + + assert.equal(await bake.balanceOf(bakeryChef.address), ether('42736.507936512000000000')); + assert.equal(await bake.balanceOf(piMyToken.address), ether(10000)); + assert.equal(await piMyToken.balanceOf(alice), ether(10000)); + assert.equal(await piMyToken.totalSupply(), ether(10000)); + await piMyToken.withdraw(ether(1000), { from: alice }); + await expectRevert(myRouter.poke(false), 'STAKING_IS_NULL'); + }); + + describe('when interval enabled', () => { + beforeEach(async () => { + await myRouter.setReserveConfig(ether('0.2'), time.duration.hours(1), { from: piGov }); + await poke.setMinMaxReportIntervals(time.duration.hours(1), time.duration.hours(2), { from: piGov }); + }); + + it('should DO rebalance by pokeFromReporter if the rebalancing interval has passed', async () => { + await time.increase(time.duration.minutes(61)); + + await bake.approve(piMyToken.address, ether(1000), { from: alice }); + await piMyToken.deposit(ether(1000), { from: alice }); + await expectRevert(myRouter.pokeFromSlasher(0, false, '0x'), 'MAX_INTERVAL_NOT_REACHED'); + }); + + it('should DO rebalance by pokeFromSlasher if the rebalancing interval has passed', async () => { + await time.increase(time.duration.minutes(121)); + + await bake.approve(piMyToken.address, ether(1000), { from: alice }); + await piMyToken.deposit(ether(1000), { from: alice }); + await myRouter.pokeFromSlasher(0, false, '0x'); + + assert.equal(await bake.balanceOf(bakeryChef.address), ether('53219.047619048000000000')); + assert.equal((await bakeryChef.poolUserInfoMap(bake.address, piMyToken.address)).amount, ether(8800)); + assert.equal(await bake.balanceOf(piMyToken.address), ether(2200)); + }); + + it('should DO rebalance on withdrawal if the rebalancing interval has passed', async () => { + await time.increase(time.duration.minutes(61)); + + await piMyToken.withdraw(ether(1000), { from: alice }); + await myRouter.poke(false); + + assert.equal(await bake.balanceOf(bakeryChef.address), ether('51282.539682544000000000')); + assert.equal((await bakeryChef.poolUserInfoMap(bake.address, piMyToken.address)).amount, ether(7200)); + assert.equal(await bake.balanceOf(piMyToken.address), ether(1800)); + }); + + it('should NOT rebalance by pokeFromReporter if the rebalancing interval has passed', async () => { + await time.increase(time.duration.minutes(50)); + + await bake.approve(piMyToken.address, ether(1000), { from: alice }); + await piMyToken.deposit(ether(1000), { from: alice }); + await expectRevert(myRouter.pokeFromReporter(0, false, '0x'), 'MIN_INTERVAL_NOT_REACHED'); + await expectRevert(myRouter.pokeFromSlasher(0, false, '0x'), 'MAX_INTERVAL_NOT_REACHED'); + }); + + it('should NOT rebalance by pokeFromSlasher if the rebalancing interval has passed', async () => { + await time.increase(time.duration.minutes(70)); + + await bake.approve(piMyToken.address, ether(1000), { from: alice }); + await piMyToken.deposit(ether(1000), { from: alice }); + await expectRevert(myRouter.pokeFromSlasher(0, false, '0x'), 'MAX_INTERVAL_NOT_REACHED'); + }); + }); + + describe('on poke', async () => { + it('should do nothing when nothing has changed', async () => { + await myRouter.poke(false, { from: bob }); + + assert.equal(await bake.balanceOf(bakeryChef.address), ether(50400)); + assert.equal((await bakeryChef.poolUserInfoMap(bake.address, piMyToken.address)).amount, ether(8000)); + assert.equal(await bake.balanceOf(piMyToken.address), ether(2000)); + }); + + it('should increase reserve if required', async () => { + await bake.transfer(piMyToken.address, ether(1000), { from: alice }); + + assert.equal(await bake.balanceOf(bakeryChef.address), ether(50400)); + assert.equal((await bakeryChef.poolUserInfoMap(bake.address, piMyToken.address)).amount, ether(8000)); + assert.equal(await bake.balanceOf(piMyToken.address), ether(3000)); + + await myRouter.poke(false, { from: bob }); + + assert.equal(await bake.balanceOf(bakeryChef.address), ether('51873.015873016000000000')); + assert.equal((await bakeryChef.poolUserInfoMap(bake.address, piMyToken.address)).amount, ether(8800)); + assert.equal(await bake.balanceOf(piMyToken.address), ether(2200)); + }); + }); + + it('should stake all the underlying tokens with 0 RR', async () => { + await myRouter.setReserveConfig(ether(0), 0, { from: piGov }); + + await myRouter.poke(false, { from: bob }); + assert.equal(await bake.balanceOf(bakeryChef.address), ether('53073.015873016000000000')); + assert.equal(await bake.balanceOf(piMyToken.address), ether(0)); + }); + + it('should keep all the underlying tokens on piToken with 1 RR', async () => { + await myRouter.setReserveConfig(ether(1), 0, { from: piGov }); + + await myRouter.poke(false, { from: bob }); + assert.equal(await bake.balanceOf(bakeryChef.address), ether('43073.015873016000000000')); + assert.equal(await bake.balanceOf(piMyToken.address), ether(10000)); + }); + }); + + describe('reward distribution', async () => { + let poolA, poolB, poolC, poolD; + + beforeEach(async function() { + poolA = await MockGulpingBPool.new(); + poolB = await MockGulpingBPool.new(); + poolC = await MockGulpingBPool.new(); + poolD = await MockGulpingBPool.new(); + await myRouter.setRewardPools([poolA.address, poolB.address, poolC.address], { from: piGov }); + + await poolRestrictions.setVotingAllowedForSenders(bakeryChef.address, [alice], [true]); + + // await bake.transfer(syrupPool.address, ether(12000)); + await bake.transfer(alice, ether('10000')); + await bake.approve(piMyToken.address, ether('10000'), { from: alice }); + await piMyToken.deposit(ether('10000'), { from: alice }); + + await myRouter.poke(false); + + assert.equal(await piMyToken.totalSupply(), ether('10000')); + assert.equal(await piMyToken.balanceOf(alice), ether('10000')); + + await piMyToken.transfer(poolA.address, 10, { from: alice }); + await piMyToken.transfer(poolB.address, 20, { from: alice }); + }); + + it('should allow distribute the accrued rewards', async () => { + await bake.transfer(bakeryChef.address, ether(2000)); + + assert.equal(await bake.balanceOf(piMyToken.address), ether(2000)); + assert.equal(await myRouter.getUnderlyingStaked(), ether(8000)); + assert.equal(await myRouter.getPendingRewards(), ether(960)); + + let res = await myRouter.poke(true, { from: bob }); + + expectEvent(res, 'DistributeRewards', { + sender: bob, + tokenReward: ether(1280), + pvpReward: ether(192), + poolRewardsUnderlying: ether(1088), + poolRewardsPi: ether(1088), + pools: [poolA.address, poolB.address, poolC.address], + }); + + assert.equal(await bake.balanceOf(piMyToken.address), ether(3088)); + assert.equal(await bake.balanceOf(myRouter.address), '0'); + + assert.isTrue(parseInt(res.logs[3].args.poolRewardsUnderlying) > 1); + assert.isTrue(parseInt(res.logs[3].args.poolRewardsPi.length) > 1); + + await expectEvent.inTransaction(res.tx, poolA, 'Gulp'); + await expectEvent.inTransaction(res.tx, poolB, 'Gulp'); + await expectEvent.notEmitted.inTransaction(res.tx, poolC, 'Gulp'); + await expectEvent.notEmitted.inTransaction(res.tx, poolD, 'Gulp'); + + assert.equal(res.logs.length, 4); + assert.equal(res.logs[1].args.pool, poolA.address); + assert.equal(res.logs[1].args.amount, ether('362.666666666666666666')); + assert.equal(res.logs[2].args.pool, poolB.address); + assert.equal(res.logs[2].args.amount, ether('725.333333333333333333')); + + assert.equal(await piMyToken.balanceOf(poolA.address), ether('362.666666666666666676')); + assert.equal(await piMyToken.balanceOf(poolB.address), ether('725.333333333333333353')); + assert.equal(await piMyToken.balanceOf(poolC.address), '0'); + assert.equal(await piMyToken.balanceOf(poolD.address), '0'); + + assert.equal(await bake.balanceOf(myRouter.address), '0'); + assert.equal(await bake.balanceOf(myRouter.address), '0'); + }); + + it('should revert poke if there is nothing released', async () => { + const dishonestChef = await MockBakeryMasterChef.new(bake.address); + await myRouter.setReserveConfig(ether(1), 0, { from: piGov }); + await myRouter.poke(false); + await myRouter.setVotingAndStaking(constants.ZERO_ADDRESS, dishonestChef.address, { from: piGov }); + await myRouter.setReserveConfig(ether('0.2'), 0, { from: piGov }); + + // there are still some rewards from rebalancing pokes + await myRouter.poke(true, { from: alice }); + + // and now there are no rewards + await expectRevert(myRouter.poke(true, { from: alice }), 'NO_PENDING_REWARD'); + }); + + it('should revert distributing rewards when missing reward pools config', async () => { + poke = await MockPoke.new(true); + const router = await BakeryChefPowerIndexRouter.new( + piMyToken.address, + buildBasicRouterConfig( + poolRestrictions.address, + poke.address, + bakeryChef.address, + bakeryChef.address, + ether('0.2'), + ether('0.02'), + '0', + pvp, + ether('0.2'), + [], + ), + buildBakeryChefRouterConfig(bake.address), + ) + await myRouter.migrateToNewRouter(piMyToken.address, router.address, [], { from: piGov }); + await bake.transfer(bakeryChef.address, ether(2000)); + await time.increase(1); + await expectRevert(router.poke(true, { from: bob }), 'MISSING_REWARD_POOLS'); + }); + }); +}); diff --git a/test/router/implementations/PancakeMasterChefRouter.unit.js b/test/router/implementations/PancakeMasterChefRouter.unit.js index 74038152..a3918d31 100644 --- a/test/router/implementations/PancakeMasterChefRouter.unit.js +++ b/test/router/implementations/PancakeMasterChefRouter.unit.js @@ -26,16 +26,16 @@ describe('PancakeMasterChefRouter Tests', () => { [deployer, bob, alice, piGov, stub, pvp, pool1, pool2] = await web3.eth.getAccounts(); }); - let myToken, syrupPool, masterChef, poolRestrictions, piMyToken, myRouter, poke; + let cake, syrupPool, masterChef, poolRestrictions, piMyToken, myRouter, poke; beforeEach(async function() { - myToken = await MockERC20.new('My Staking Token', 'MST', '18', ether('10000000')); - - // 0x009cf7bc57584b7998236eff51b98a168dcea9b0 - syrupPool = await PancakeSyrupPool.new(myToken.address); - // 0x73feaa1ee314f8c655e354234017be2193c9e24e + // bsc: 0x0e09fabb73bd3ade0a17ecc321fd13a19e81ce82 + cake = await MockERC20.new('PancakeSwap Token', 'Cake', '18', ether('10000000')); + // bsc: 0x009cf7bc57584b7998236eff51b98a168dcea9b0 + syrupPool = await PancakeSyrupPool.new(cake.address); + // bsc: 0x73feaa1ee314f8c655e354234017be2193c9e24e masterChef = await PancakeMasterChef.new( - myToken.address, + cake.address, syrupPool.address, deployer, ether(40), @@ -43,7 +43,7 @@ describe('PancakeMasterChefRouter Tests', () => { ); poolRestrictions = await PoolRestrictions.new(); - piMyToken = await WrappedPiErc20.new(myToken.address, stub, 'Wrapped My Staking Token', 'piMST'); + piMyToken = await WrappedPiErc20.new(cake.address, stub, 'Wrapped My Staking Token', 'piMST'); poke = await MockPoke.new(true); myRouter = await PancakeMasterChefIndexRouter.new( @@ -60,12 +60,12 @@ describe('PancakeMasterChefRouter Tests', () => { ether('0.15'), [pool1, pool2], ), - buildPancakeMasterChefRouterConfig(myToken.address), + buildPancakeMasterChefRouterConfig(cake.address), ); await syrupPool.transferOwnership(masterChef.address); await piMyToken.changeRouter(myRouter.address, { from: stub }); - await masterChef.add(20306, myToken.address, false); + await masterChef.add(20306, cake.address, false); await myRouter.transferOwnership(piGov); assert.equal(await myRouter.owner(), piGov); @@ -78,14 +78,14 @@ describe('PancakeMasterChefRouter Tests', () => { describe('stake()/redeem()', () => { beforeEach(async () => { - await myToken.transfer(alice, ether('10000')); - await myToken.approve(piMyToken.address, ether('10000'), { from: alice }); + await cake.transfer(alice, ether('10000')); + await cake.approve(piMyToken.address, ether('10000'), { from: alice }); await piMyToken.deposit(ether('10000'), { from: alice }); await myRouter.poke(false); - assert.equal(await myToken.balanceOf(piMyToken.address), ether(2000)); - assert.equal(await myToken.balanceOf(masterChef.address), ether(8000)); + assert.equal(await cake.balanceOf(piMyToken.address), ether(2000)); + assert.equal(await cake.balanceOf(masterChef.address), ether(8000)); assert.equal((await masterChef.userInfo(0, piMyToken.address)).amount, ether(8000)); }); @@ -96,16 +96,12 @@ describe('PancakeMasterChefRouter Tests', () => { sender: piGov, amount: ether(2000), }); - assert.equal(await myToken.balanceOf(piMyToken.address), ether('9.999261280000000000')); - assert.equal(await myToken.balanceOf(masterChef.address), ether(10000)); + assert.equal(await cake.balanceOf(piMyToken.address), ether(0)); + assert.equal(await cake.balanceOf(masterChef.address), ether(10000)); const userInfo = await masterChef.userInfo(0, piMyToken.address); assert.equal(userInfo.amount, ether(10000)); }); - it('should deny staking 0', async () => { - await expectRevert(myRouter.stake(ether(0), { from: piGov }), 'CANT_STAKE_0'); - }); - it('should deny non-owner staking any amount of reserve tokens', async () => { await expectRevert(myRouter.stake(ether(1), { from: alice }), 'Ownable: caller is not the owner'); }); @@ -118,15 +114,11 @@ describe('PancakeMasterChefRouter Tests', () => { sender: piGov, amount: ether(3000), }); - assert.equal(await myToken.balanceOf(piMyToken.address), '5009999261280000000000'); + assert.equal(await cake.balanceOf(piMyToken.address), ether(5000)); const userInfo = await masterChef.userInfo(0, piMyToken.address); assert.equal(userInfo.amount, ether(5000)); }); - it('should deny staking 0', async () => { - await expectRevert(myRouter.redeem(ether(0), { from: piGov }), 'CANT_REDEEM_0'); - }); - it('should deny non-owner staking any amount of reserve tokens', async () => { await expectRevert(myRouter.redeem(ether(1), { from: alice }), 'Ownable: caller is not the owner'); }); @@ -172,30 +164,30 @@ describe('PancakeMasterChefRouter Tests', () => { describe('reserve management', () => { beforeEach(async () => { // alice - await myToken.transfer(alice, ether('20000')); - await myToken.approve(piMyToken.address, ether('10000'), { from: alice }); + await cake.transfer(alice, ether('20000')); + await cake.approve(piMyToken.address, ether('10000'), { from: alice }); await piMyToken.deposit(ether('10000'), { from: alice }); // bob - await myToken.transfer(bob, ether('42000')); - await myToken.approve(masterChef.address, ether('42000'), { from: bob }); + await cake.transfer(bob, ether('42000')); + await cake.approve(masterChef.address, ether('42000'), { from: bob }); await masterChef.enterStaking(ether('42000'), { from: bob }); await myRouter.poke(false); - assert.equal(await myToken.balanceOf(masterChef.address), ether(50000)); - assert.equal(await myToken.balanceOf(piMyToken.address), ether(2000)); + assert.equal(await cake.balanceOf(masterChef.address), ether(50000)); + assert.equal(await cake.balanceOf(piMyToken.address), ether(2000)); }); it('should increase reserve on deposit', async () => { assert.equal(await piMyToken.balanceOf(alice), ether(10000)); - await myToken.approve(piMyToken.address, ether(1000), { from: alice }); + await cake.approve(piMyToken.address, ether(1000), { from: alice }); await piMyToken.deposit(ether(1000), { from: alice }); await myRouter.poke(false); assert.equal(await piMyToken.balanceOf(alice), ether(11000)); - assert.equal(await myToken.balanceOf(masterChef.address), ether(50800)); - assert.equal(await myToken.balanceOf(piMyToken.address), ether('2204.799645416000000000')); + assert.equal(await cake.balanceOf(masterChef.address), ether(50800)); + assert.equal(await cake.balanceOf(piMyToken.address), ether(2200)); assert.equal(await myRouter.getUnderlyingStaked(), ether(8800)); assert.equal((await masterChef.userInfo(0, piMyToken.address)).amount, ether(8800)); }); @@ -207,8 +199,8 @@ describe('PancakeMasterChefRouter Tests', () => { await myRouter.poke(false); assert.equal(await piMyToken.balanceOf(alice), ether(9000)); - assert.equal(await myToken.balanceOf(masterChef.address), ether(49200)); - assert.equal(await myToken.balanceOf(piMyToken.address), ether('1803.199763608000000000')); + assert.equal(await cake.balanceOf(masterChef.address), ether(49200)); + assert.equal(await cake.balanceOf(piMyToken.address), ether(1800)); assert.equal(await myRouter.getUnderlyingStaked(), ether(7200)); assert.equal((await masterChef.userInfo(0, piMyToken.address)).amount, ether(7200)); }); @@ -217,8 +209,8 @@ describe('PancakeMasterChefRouter Tests', () => { await myRouter.redeem(ether(8000), { from: piGov }); await myRouter.setVotingAndStaking(masterChef.address, constants.ZERO_ADDRESS, { from: piGov }); - assert.equal(await myToken.balanceOf(masterChef.address), ether(42000)); - assert.equal(await myToken.balanceOf(piMyToken.address), ether('10001.599881800000000000')); + assert.equal(await cake.balanceOf(masterChef.address), ether(42000)); + assert.equal(await cake.balanceOf(piMyToken.address), ether(10000)); assert.equal(await piMyToken.balanceOf(alice), ether(10000)); assert.equal(await piMyToken.totalSupply(), ether(10000)); await piMyToken.withdraw(ether(1000), { from: alice }); @@ -234,7 +226,7 @@ describe('PancakeMasterChefRouter Tests', () => { it('should DO rebalance by pokeFromReporter if the rebalancing interval has passed', async () => { await time.increase(time.duration.minutes(61)); - await myToken.approve(piMyToken.address, ether(1000), { from: alice }); + await cake.approve(piMyToken.address, ether(1000), { from: alice }); await piMyToken.deposit(ether(1000), { from: alice }); await expectRevert(myRouter.pokeFromSlasher(0, false, '0x'), 'MAX_INTERVAL_NOT_REACHED'); }); @@ -242,13 +234,13 @@ describe('PancakeMasterChefRouter Tests', () => { it('should DO rebalance by pokeFromSlasher if the rebalancing interval has passed', async () => { await time.increase(time.duration.minutes(121)); - await myToken.approve(piMyToken.address, ether(1000), { from: alice }); + await cake.approve(piMyToken.address, ether(1000), { from: alice }); await piMyToken.deposit(ether(1000), { from: alice }); await myRouter.pokeFromSlasher(0, false, '0x'); - assert.equal(await myToken.balanceOf(masterChef.address), ether(50800)); + assert.equal(await cake.balanceOf(masterChef.address), ether(50800)); assert.equal((await masterChef.userInfo(0, piMyToken.address)).amount, ether(8800)); - assert.equal(await myToken.balanceOf(piMyToken.address), ether('2209.599290832000000000')); + assert.equal(await cake.balanceOf(piMyToken.address), ether(2200)); }); it('should DO rebalance on withdrawal if the rebalancing interval has passed', async () => { @@ -257,15 +249,15 @@ describe('PancakeMasterChefRouter Tests', () => { await piMyToken.withdraw(ether(1000), { from: alice }); await myRouter.poke(false); - assert.equal(await myToken.balanceOf(masterChef.address), ether(49200)); + assert.equal(await cake.balanceOf(masterChef.address), ether(49200)); assert.equal((await masterChef.userInfo(0, piMyToken.address)).amount, ether(7200)); - assert.equal(await myToken.balanceOf(piMyToken.address), ether('1807.999409024000000000')); + assert.equal(await cake.balanceOf(piMyToken.address), ether(1800)); }); it('should NOT rebalance by pokeFromReporter if the rebalancing interval has passed', async () => { await time.increase(time.duration.minutes(50)); - await myToken.approve(piMyToken.address, ether(1000), { from: alice }); + await cake.approve(piMyToken.address, ether(1000), { from: alice }); await piMyToken.deposit(ether(1000), { from: alice }); await expectRevert(myRouter.pokeFromReporter(0, false, '0x'), 'MIN_INTERVAL_NOT_REACHED'); await expectRevert(myRouter.pokeFromSlasher(0, false, '0x'), 'MAX_INTERVAL_NOT_REACHED'); @@ -274,7 +266,7 @@ describe('PancakeMasterChefRouter Tests', () => { it('should NOT rebalance by pokeFromSlasher if the rebalancing interval has passed', async () => { await time.increase(time.duration.minutes(70)); - await myToken.approve(piMyToken.address, ether(1000), { from: alice }); + await cake.approve(piMyToken.address, ether(1000), { from: alice }); await piMyToken.deposit(ether(1000), { from: alice }); await expectRevert(myRouter.pokeFromSlasher(0, false, '0x'), 'MAX_INTERVAL_NOT_REACHED'); }); @@ -284,23 +276,23 @@ describe('PancakeMasterChefRouter Tests', () => { it('should do nothing when nothing has changed', async () => { await myRouter.poke(false, { from: bob }); - assert.equal(await myToken.balanceOf(masterChef.address), ether(50000)); + assert.equal(await cake.balanceOf(masterChef.address), ether(50000)); assert.equal((await masterChef.userInfo(0, piMyToken.address)).amount, ether(8000)); - assert.equal(await myToken.balanceOf(piMyToken.address), ether(2000)); + assert.equal(await cake.balanceOf(piMyToken.address), ether(2000)); }); it('should increase reserve if required', async () => { - await myToken.transfer(piMyToken.address, ether(1000), { from: alice }); + await cake.transfer(piMyToken.address, ether(1000), { from: alice }); - assert.equal(await myToken.balanceOf(masterChef.address), ether(50000)); + assert.equal(await cake.balanceOf(masterChef.address), ether(50000)); assert.equal((await masterChef.userInfo(0, piMyToken.address)).amount, ether(8000)); - assert.equal(await myToken.balanceOf(piMyToken.address), ether(3000)); + assert.equal(await cake.balanceOf(piMyToken.address), ether(3000)); await myRouter.poke(false, { from: bob }); - assert.equal(await myToken.balanceOf(masterChef.address), ether(50800)); + assert.equal(await cake.balanceOf(masterChef.address), ether(50800)); assert.equal((await masterChef.userInfo(0, piMyToken.address)).amount, ether(8800)); - assert.equal(await myToken.balanceOf(piMyToken.address), ether('2203.199763608000000000')); + assert.equal(await cake.balanceOf(piMyToken.address), ether(2200)); }); }); @@ -308,16 +300,16 @@ describe('PancakeMasterChefRouter Tests', () => { await myRouter.setReserveConfig(ether(0), 0, { from: piGov }); await myRouter.poke(false, { from: bob }); - assert.equal(await myToken.balanceOf(masterChef.address), ether(52000)); - assert.equal(await myToken.balanceOf(piMyToken.address), ether('3.199763608000000000')); + assert.equal(await cake.balanceOf(masterChef.address), ether(52000)); + assert.equal(await cake.balanceOf(piMyToken.address), ether(0)); }); it('should keep all the underlying tokens on piToken with 1 RR', async () => { await myRouter.setReserveConfig(ether(1), 0, { from: piGov }); await myRouter.poke(false, { from: bob }); - assert.equal(await myToken.balanceOf(masterChef.address), ether(42000)); - assert.equal(await myToken.balanceOf(piMyToken.address), ether('10003.199763608000000000')); + assert.equal(await cake.balanceOf(masterChef.address), ether(42000)); + assert.equal(await cake.balanceOf(piMyToken.address), ether(10000)); }); }); @@ -333,9 +325,9 @@ describe('PancakeMasterChefRouter Tests', () => { await poolRestrictions.setVotingAllowedForSenders(masterChef.address, [alice], [true]); - await myToken.transfer(syrupPool.address, ether(12000)); - await myToken.transfer(alice, ether('10000')); - await myToken.approve(piMyToken.address, ether('10000'), { from: alice }); + await cake.transfer(syrupPool.address, ether(12000)); + await cake.transfer(alice, ether('10000')); + await cake.approve(piMyToken.address, ether('10000'), { from: alice }); await piMyToken.deposit(ether('10000'), { from: alice }); await myRouter.poke(false); @@ -348,20 +340,16 @@ describe('PancakeMasterChefRouter Tests', () => { }); it('should allow withdrawing rewards from the masterChef', async () => { - await myToken.transfer(masterChef.address, ether(2000)); + await cake.transfer(masterChef.address, ether(2000)); await masterChef.massUpdatePools(); await time.increase(time.duration.days(8)); await masterChef.massUpdatePools(); - assert.equal(await myToken.balanceOf(piMyToken.address), ether(2000)); + assert.equal(await cake.balanceOf(piMyToken.address), ether(2000)); assert.equal(await myRouter.getUnderlyingStaked(), ether(8000)); assert.equal(await myRouter.getPendingRewards(), ether('47.996454152000000000')); let res = await myRouter.poke(true, { from: bob }); - expectEvent(res, 'ClaimRewards', { - sender: bob, - earned: ether('55.995863176000000000'), - }); expectEvent(res, 'DistributeRewards', { sender: bob, @@ -372,8 +360,8 @@ describe('PancakeMasterChefRouter Tests', () => { pools: [poolA.address, poolB.address, poolC.address], }); - assert.equal(await myToken.balanceOf(piMyToken.address), ether('2047.596483699600000000')); - assert.equal(await myToken.balanceOf(myRouter.address), '0'); + assert.equal(await cake.balanceOf(piMyToken.address), ether('2047.596483699600000000')); + assert.equal(await cake.balanceOf(myRouter.address), '0'); assert.isTrue(parseInt(res.logs[3].args.poolRewardsUnderlying) > 1); assert.isTrue(parseInt(res.logs[3].args.poolRewardsPi.length) > 1); @@ -394,19 +382,18 @@ describe('PancakeMasterChefRouter Tests', () => { assert.equal(await piMyToken.balanceOf(poolC.address), '0'); assert.equal(await piMyToken.balanceOf(poolD.address), '0'); - assert.equal(await myToken.balanceOf(myRouter.address), '0'); - assert.equal(await myToken.balanceOf(myRouter.address), '0'); + assert.equal(await cake.balanceOf(myRouter.address), '0'); + assert.equal(await cake.balanceOf(myRouter.address), '0'); }); it('should revert poke if there is nothing released', async () => { - const dishonestChef = await MockPancakeMasterChef.new(myToken.address); + const dishonestChef = await MockPancakeMasterChef.new(cake.address); await myRouter.setReserveConfig(ether(1), 0, { from: piGov }); await myRouter.poke(false); await myRouter.setVotingAndStaking(constants.ZERO_ADDRESS, dishonestChef.address, { from: piGov }); await myRouter.setReserveConfig(ether('0.2'), 0, { from: piGov }); - await myRouter.poke(false); - await myToken.transfer(dishonestChef.address, ether(1000)); - await expectRevert(myRouter.poke(true, { from: alice }), 'NOTHING_EARNED'); + await myRouter.poke(true); + await expectRevert(myRouter.poke(true, { from: alice }), 'NO_PENDING_REWARD'); }); it('should revert distributing rewards when missing reward pools config', async () => { @@ -425,10 +412,10 @@ describe('PancakeMasterChefRouter Tests', () => { ether('0.2'), [], ), - buildPancakeMasterChefRouterConfig(myToken.address), + buildPancakeMasterChefRouterConfig(cake.address), ); await myRouter.migrateToNewRouter(piMyToken.address, router.address, [], { from: piGov }); - await myToken.transfer(masterChef.address, ether(2000)); + await cake.transfer(masterChef.address, ether(2000)); await time.increase(1); await expectRevert(router.poke(true, { from: bob }), 'MISSING_REWARD_POOLS'); }); diff --git a/test/router/implementations/SushiRouter.unit.js b/test/router/implementations/SushiRouter.unit.js index 2ab16b8a..67da1f49 100644 --- a/test/router/implementations/SushiRouter.unit.js +++ b/test/router/implementations/SushiRouter.unit.js @@ -118,7 +118,7 @@ describe('SushiRouter Tests', () => { assert.equal(await sushi.balanceOf(xSushi.address), ether(47000)); }); - it('should deny staking 0', async () => { + it('should deny redeeming 0', async () => { await expectRevert(sushiRouter.redeem(ether(0), { from: piGov }), 'CANT_REDEEM_0'); }); From 29619fdde361d9bc71a7c3106406ee32cdf20c7e Mon Sep 17 00:00:00 2001 From: Poli Paul Date: Fri, 23 Jul 2021 10:19:38 +0200 Subject: [PATCH 04/33] Remove unused variable --- .../implementations/AbstractMasterChefIndexRouter.sol | 1 - 1 file changed, 1 deletion(-) diff --git a/contracts/powerindex-router/implementations/AbstractMasterChefIndexRouter.sol b/contracts/powerindex-router/implementations/AbstractMasterChefIndexRouter.sol index 31ea8c8c..2ce9b0db 100644 --- a/contracts/powerindex-router/implementations/AbstractMasterChefIndexRouter.sol +++ b/contracts/powerindex-router/implementations/AbstractMasterChefIndexRouter.sol @@ -30,7 +30,6 @@ abstract contract AbstractMasterChefIndexRouter is PowerIndexBasicRouter { function _claimRewards(ReserveStatus status) internal override { if (status == ReserveStatus.EQUILIBRIUM) { - uint256 pendingReward = TOKEN.balanceOf(address(this)); _stake(0); } // Otherwise the rewards are distributed each time deposit/withdraw methods are called, From 3c0a711cbe64684935dabb0a13a75e324941f870 Mon Sep 17 00:00:00 2001 From: Poli Paul Date: Fri, 23 Jul 2021 10:26:46 +0200 Subject: [PATCH 05/33] Fix incorrect EOA check in MockERC20 --- contracts/test/MockERC20.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/test/MockERC20.sol b/contracts/test/MockERC20.sol index 21ed8d69..0da0bb84 100644 --- a/contracts/test/MockERC20.sol +++ b/contracts/test/MockERC20.sol @@ -20,12 +20,12 @@ contract MockERC20 is ERC20 { } function mint(address account, uint256 amount) public { - require(msg.sender != tx.origin, "MockERC20: mint from non-EOA"); + require(msg.sender == tx.origin, "MockERC20: mint from non-EOA"); _mint(account, amount); } function burn(uint256 amount) public { - require(msg.sender != tx.origin, "MockERC20: burn from non-EOA"); + require(msg.sender == tx.origin, "MockERC20: burn from non-EOA"); _burn(msg.sender, amount); } } From a40567f439909867d0d6078160e9179be52f1363 Mon Sep 17 00:00:00 2001 From: Poli Paul Date: Fri, 23 Jul 2021 14:44:50 +0200 Subject: [PATCH 06/33] Add MDXMasterChefRouter --- assets/bsc/BoardRoomMDX.json | 262 +++++++++++ assets/bsc/MdxToken.json | 290 ++++++++++++ contracts/interfaces/sushi/IMasterChefV1.sol | 2 + .../MasterChefPowerIndexRouter.sol | 14 +- contracts/test/MockGeneralMasterChef.sol | 23 + .../BakeryMasterChefRouter.unit.js | 132 +++--- .../MDXMasterChefRouter.unit.js | 427 ++++++++++++++++++ .../PancakeMasterChefRouter.unit.js | 132 +++--- 8 files changed, 1145 insertions(+), 137 deletions(-) create mode 100644 assets/bsc/BoardRoomMDX.json create mode 100644 assets/bsc/MdxToken.json create mode 100644 contracts/test/MockGeneralMasterChef.sol create mode 100644 test/router/implementations/MDXMasterChefRouter.unit.js diff --git a/assets/bsc/BoardRoomMDX.json b/assets/bsc/BoardRoomMDX.json new file mode 100644 index 00000000..ec79e5b7 --- /dev/null +++ b/assets/bsc/BoardRoomMDX.json @@ -0,0 +1,262 @@ +{ + "bytecode": "608060405260006007553480156200001657600080fd5b506040516200397938038062003979833981810160405260408110156200003c57600080fd5b8101908080519060200190929190805190602001909291905050506000620000696200015760201b60201c565b9050806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35081600360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600a8190555050506200015f565b600033905090565b61380a806200016f6000396000f3fe608060405234801561001057600080fd5b50600436106101a95760003560e01c80635672ab55116100f95780638fa39a8811610097578063e2bbb15811610071578063e2bbb15814610687578063e4c75c27146106bf578063f2fde38b14610721578063f9733d7c14610765576101a9565b80638fa39a88146105a657806393f1a40b146105c4578063941c48541461062d576101a9565b806364482f79116100d357806364482f79146104f65780636d93c3ba1461053a578063715018a6146105685780638da5cb5b14610572576101a9565b80635672ab551461049a5780636190c9d5146104ce578063630b5ba1146104ec576101a9565b806317caf6f111610166578063441a3e7011610140578063441a3e70146103e857806348cd4cb11461042057806351eb05a61461043e5780635312ea8e1461046c576101a9565b806317caf6f1146103185780631b0684a8146103365780631eaaa0451461038e576101a9565b806306aab367146101ae578063076f5b46146101cc578063081e3eda1461020e578063083c63231461022c5780630a498a3b1461024a5780631526fe27146102a4575b600080fd5b6101b66107bf565b6040518082815260200191505060405180910390f35b61020c600480360360608110156101e257600080fd5b810190808035906020019092919080359060200190929190803590602001909291905050506107d0565b005b610216610c2f565b6040518082815260200191505060405180910390f35b610234610c3c565b6040518082815260200191505060405180910390f35b61028c6004803603602081101561026057600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610c42565b60405180821515815260200191505060405180910390f35b6102d0600480360360208110156102ba57600080fd5b8101908080359060200190929190505050610dc1565b604051808673ffffffffffffffffffffffffffffffffffffffff1681526020018581526020018481526020018381526020018281526020019550505050505060405180910390f35b610320610e24565b6040518082815260200191505060405180910390f35b6103626004803603602081101561034c57600080fd5b8101908080359060200190929190505050610e2a565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6103e6600480360360608110156103a457600080fd5b8101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803515159060200190929190505050610f86565b005b61041e600480360360408110156103fe57600080fd5b810190808035906020019092919080359060200190929190505050611213565b005b610428611510565b6040518082815260200191505060405180910390f35b61046a6004803603602081101561045457600080fd5b8101908080359060200190929190505050611516565b005b6104986004803603602081101561048257600080fd5b8101908080359060200190929190505050611781565b005b6104a261194f565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6104d6611975565b6040518082815260200191505060405180910390f35b6104f461197b565b005b6105386004803603606081101561050c57600080fd5b8101908080359060200190929190803590602001909291908035151590602001909291905050506119a8565b005b6105666004803603602081101561055057600080fd5b8101908080359060200190929190505050611af2565b005b610570611bc4565b005b61057a611d4a565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6105ae611d73565b6040518082815260200191505060405180910390f35b610610600480360360408110156105da57600080fd5b8101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611d79565b604051808381526020018281526020019250505060405180910390f35b61066f6004803603602081101561064357600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611daa565b60405180821515815260200191505060405180910390f35b6106bd6004803603604081101561069d57600080fd5b810190808035906020019092919080359060200190929190505050611f29565b005b61070b600480360360408110156106d557600080fd5b8101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612238565b6040518082815260200191505060405180910390f35b6107636004803603602081101561073757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612526565b005b6107a76004803603602081101561077b57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612731565b60405180821515815260200191505060405180910390f35b60006107cb6001612745565b905090565b6107d861275a565b73ffffffffffffffffffffffffffffffffffffffff1660008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614610898576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b600954431180156108ab57506009548110155b61091d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600c8152602001807f4e6f742066696e6973686564000000000000000000000000000000000000000081525060200191505060405180910390fd5b61092561197b565b6000600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156109b057600080fd5b505afa1580156109c4573d6000803e3d6000fd5b505050506040513d60208110156109da57600080fd5b81019080805190602001909291905050509050610a1b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16333087612762565b6000600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015610aa657600080fd5b505afa158015610aba573d6000803e3d6000fd5b505050506040513d6020811015610ad057600080fd5b810190808051906020019092919050505090506000610af8838361294790919063ffffffff16565b9050858114610b6f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600d8152602001807f4572726f722062616c616e63650000000000000000000000000000000000000081525060200191505060405180910390fd5b600081118015610b8357508085600a540211155b610bf5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f42616c616e6365206e6f7420656e6f756768000000000000000000000000000081525060200191505060405180910390fd5b8460048190555083600881905550610c18600a548561299190919063ffffffff16565b600981905550610c2784612a19565b505050505050565b6000600580549050905090565b60095481565b6000610c4c61275a565b73ffffffffffffffffffffffffffffffffffffffff1660008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614610d0c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415610daf576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260188152602001807f5f62616420697320746865207a65726f2061646472657373000000000000000081525060200191505060405180910390fd5b610dba600183612a67565b9050919050565b60058181548110610dce57fe5b90600052602060002090600502016000915090508060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060010154908060020154908060030154908060040154905085565b60075481565b6000610e3461275a565b73ffffffffffffffffffffffffffffffffffffffff1660008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614610ef4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b6001610efe6107bf565b03821115610f74576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260138152602001807f696e646578206f7574206f6620626f756e64730000000000000000000000000081525060200191505060405180910390fd5b610f7f600183612a97565b9050919050565b610f8e61275a565b73ffffffffffffffffffffffffffffffffffffffff1660008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161461104e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614156110f1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f6c70546f6b656e20697320746865207a65726f2061646472657373000000000081525060200191505060405180910390fd5b8015611100576110ff61197b565b5b6000600854431161111357600854611115565b435b905061112c8460075461299190919063ffffffff16565b60078190555060056040518060a001604052808573ffffffffffffffffffffffffffffffffffffffff168152602001868152602001838152602001600081526020016000815250908060018154018082558091505060019003906000526020600020906005020160009091909190915060008201518160000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060208201518160010155604082015181600201556060820151816003015560808201518160040155505050505050565b60006005838154811061122257fe5b9060005260206000209060050201905060006006600085815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090508281600001541015611300576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f77697468647261773a206e6f7420676f6f64000000000000000000000000000081525060200191505060405180910390fd5b61130984611516565b6000611353826001015461134564e8d4a5100061133787600301548760000154612ab190919063ffffffff16565b612b3790919063ffffffff16565b61294790919063ffffffff16565b9050600081111561136e5761136d33828560040154612b81565b5b60008411156114805761138e84836000015461294790919063ffffffff16565b8260000181905550600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168360000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614156114305761142784846004015461294790919063ffffffff16565b83600401819055505b61147f33858560000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16612e109092919063ffffffff16565b5b6114b264e8d4a510006114a485600301548560000154612ab190919063ffffffff16565b612b3790919063ffffffff16565b8260010181905550843373ffffffffffffffffffffffffffffffffffffffff167ff279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b568866040518082815260200191505060405180910390a35050505050565b60085481565b60006005828154811061152557fe5b9060005260206000209060050201905060006009544311611546574361154a565b6009545b90508160020154811161155e57505061177e565b6000600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168360000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614156115e657826004015490506116af565b8260000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561167157600080fd5b505afa158015611685573d6000803e3d6000fd5b505050506040513d602081101561169b57600080fd5b810190808051906020019092919050505090505b60008114156116c95781836002018190555050505061177e565b60006116e284600201548461294790919063ffffffff16565b90506000611725600754611717876001015461170960045487612ab190919063ffffffff16565b612ab190919063ffffffff16565b612b3790919063ffffffff16565b90506117676117548461174664e8d4a5100085612ab190919063ffffffff16565b612b3790919063ffffffff16565b866003015461299190919063ffffffff16565b856003018190555083856002018190555050505050505b50565b60006005828154811061179057fe5b9060005260206000209060050201905060006006600084815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090506000816000015490506000826000018190555060008260010181905550600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168360000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614156118ab576118a281846004015461294790919063ffffffff16565b83600401819055505b6118fa33828560000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16612e109092919063ffffffff16565b833373ffffffffffffffffffffffffffffffffffffffff167fbb757047c2b5f3974fe26b7c10f732e7bce710b0952a71082702781e62ae0595836040518082815260200191505060405180910390a350505050565b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600a5481565b6000600580549050905060005b818110156119a45761199981611516565b806001019050611988565b5050565b6119b061275a565b73ffffffffffffffffffffffffffffffffffffffff1660008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614611a70576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b8015611a7f57611a7e61197b565b5b611ac482611ab660058681548110611a9357fe5b90600052602060002090600502016001015460075461294790919063ffffffff16565b61299190919063ffffffff16565b6007819055508160058481548110611ad857fe5b906000526020600020906005020160010181905550505050565b611afa61275a565b73ffffffffffffffffffffffffffffffffffffffff1660008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614611bba576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b80600a8190555050565b611bcc61275a565b73ffffffffffffffffffffffffffffffffffffffff1660008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614611c8c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff1660008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a360008060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60045481565b6006602052816000526040600020602052806000526040600020600091509150508060000154908060010154905082565b6000611db461275a565b73ffffffffffffffffffffffffffffffffffffffff1660008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614611e74576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415611f17576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260188152602001807f5f62616420697320746865207a65726f2061646472657373000000000000000081525060200191505060405180910390fd5b611f22600183612eb2565b9050919050565b611f3233612731565b15611fa5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f496c6c6567616c2c2072656a656374656420000000000000000000000000000081525060200191505060405180910390fd5b600060058381548110611fb457fe5b9060005260206000209060050201905060006006600085815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020905061202184611516565b600081600001541115612095576000612078826001015461206a64e8d4a5100061205c87600301548760000154612ab190919063ffffffff16565b612b3790919063ffffffff16565b61294790919063ffffffff16565b905060008111156120935761209233828560040154612b81565b5b505b60008311156121a9576120ef3330858560000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16612ee2909392919063ffffffff16565b61210683826000015461299190919063ffffffff16565b8160000181905550600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168260000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614156121a85761219f83836004015461299190919063ffffffff16565b82600401819055505b5b6121db64e8d4a510006121cd84600301548460000154612ab190919063ffffffff16565b612b3790919063ffffffff16565b8160010181905550833373ffffffffffffffffffffffffffffffffffffffff167f90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a15856040518082815260200191505060405180910390a350505050565b6000806005848154811061224857fe5b9060005260206000209060050201905060006006600086815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090506000826003015490506000600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168460000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16141561233d5783600401549050612406565b8360000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156123c857600080fd5b505afa1580156123dc573d6000803e3d6000fd5b505050506040513d60208110156123f257600080fd5b810190808051906020019092919050505090505b60006009544311612417574361241b565b6009545b9050846002015481118015612431575060008214155b156124d557600061244f86600201548361294790919063ffffffff16565b90506000612492600754612484896001015461247660045487612ab190919063ffffffff16565b612ab190919063ffffffff16565b612b3790919063ffffffff16565b90506124d06124c1856124b364e8d4a5100085612ab190919063ffffffff16565b612b3790919063ffffffff16565b8661299190919063ffffffff16565b945050505b612519846001015461250b64e8d4a510006124fd878960000154612ab190919063ffffffff16565b612b3790919063ffffffff16565b61294790919063ffffffff16565b9550505050505092915050565b61252e61275a565b73ffffffffffffffffffffffffffffffffffffffff1660008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146125ee576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260208152602001807f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657281525060200191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415612674576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602681526020018061371a6026913960400191505060405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff1660008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600061273e600183612fa3565b9050919050565b600061275382600001612fd3565b9050919050565b600033905090565b600060608573ffffffffffffffffffffffffffffffffffffffff166323b872dd868686604051602401808473ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff16815260200182815260200193505050506040516020818303038152906040529060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040518082805190602001908083835b602083106128435780518252602082019150602081019050602083039250612820565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d80600081146128a5576040519150601f19603f3d011682016040523d82523d6000602084013e6128aa565b606091505b50915091508180156128ea57506000815114806128e957508080602001905160208110156128d757600080fd5b81019080805190602001909291905050505b5b61293f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260248152602001806137b16024913960400191505060405180910390fd5b505050505050565b600061298983836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250612fe4565b905092915050565b600080828401905083811015612a0f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f536166654d6174683a206164646974696f6e206f766572666c6f77000000000081525060200191505060405180910390fd5b8091505092915050565b6000600580549050905060005b81811015612a6257600060058281548110612a3d57fe5b9060005260206000209060050201905083816002018190555050806001019050612a26565b505050565b6000612a8f836000018373ffffffffffffffffffffffffffffffffffffffff1660001b6130a4565b905092915050565b6000612aa68360000183613114565b60001c905092915050565b600080831415612ac45760009050612b31565b6000828402905082848281612ad557fe5b0414612b2c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260218152602001806137666021913960400191505060405180910390fd5b809150505b92915050565b6000612b7983836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250613197565b905092915050565b6000600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b158015612c0c57600080fd5b505afa158015612c20573d6000803e3d6000fd5b505050506040513d6020811015612c3657600080fd5b81019080805190602001909291905050509050612c5c828261294790919063ffffffff16565b905080831115612d3a57600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb85836040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b158015612cf957600080fd5b505af1158015612d0d573d6000803e3d6000fd5b505050506040513d6020811015612d2357600080fd5b810190808051906020019092919050505050612e0a565b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb85856040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b158015612dcd57600080fd5b505af1158015612de1573d6000803e3d6000fd5b505050506040513d6020811015612df757600080fd5b8101908080519060200190929190505050505b50505050565b612ead8363a9059cbb60e01b8484604051602401808373ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505061325d565b505050565b6000612eda836000018373ffffffffffffffffffffffffffffffffffffffff1660001b61334c565b905092915050565b612f9d846323b872dd60e01b858585604051602401808473ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019350505050604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505061325d565b50505050565b6000612fcb836000018373ffffffffffffffffffffffffffffffffffffffff1660001b613434565b905092915050565b600081600001805490509050919050565b6000838311158290613091576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561305657808201518184015260208101905061303b565b50505050905090810190601f1680156130835780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5060008385039050809150509392505050565b60006130b08383613434565b61310957826000018290806001815401808255809150506001900390600052602060002001600090919091909150558260000180549050836001016000848152602001908152602001600020819055506001905061310e565b600090505b92915050565b600081836000018054905011613175576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260228152602001806136f86022913960400191505060405180910390fd5b82600001828154811061318457fe5b9060005260206000200154905092915050565b60008083118290613243576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b838110156132085780820151818401526020810190506131ed565b50505050905090810190601f1680156132355780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b50600083858161324f57fe5b049050809150509392505050565b60606132bf826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166134579092919063ffffffff16565b9050600081511115613347578080602001905160208110156132e057600080fd5b8101908080519060200190929190505050613346576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602a815260200180613787602a913960400191505060405180910390fd5b5b505050565b60008083600101600084815260200190815260200160002054905060008114613428576000600182039050600060018660000180549050039050600086600001828154811061339757fe5b90600052602060002001549050808760000184815481106133b457fe5b90600052602060002001819055506001830187600101600083815260200190815260200160002081905550866000018054806133ec57fe5b6001900381819060005260206000200160009055905586600101600087815260200190815260200160002060009055600194505050505061342e565b60009150505b92915050565b600080836001016000848152602001908152602001600020541415905092915050565b6060613466848460008561346f565b90509392505050565b6060824710156134ca576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806137406026913960400191505060405180910390fd5b6134d385613618565b613545576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601d8152602001807f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000081525060200191505060405180910390fd5b600060608673ffffffffffffffffffffffffffffffffffffffff1685876040518082805190602001908083835b602083106135955780518252602082019150602081019050602083039250613572565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d80600081146135f7576040519150601f19603f3d011682016040523d82523d6000602084013e6135fc565b606091505b509150915061360c82828661362b565b92505050949350505050565b600080823b905060008111915050919050565b6060831561363b578290506136f0565b60008351111561364e5782518084602001fd5b816040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b838110156136b557808201518184015260208101905061369a565b50505050905090810190601f1680156136e25780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b939250505056fe456e756d657261626c655365743a20696e646578206f7574206f6620626f756e64734f776e61626c653a206e6577206f776e657220697320746865207a65726f2061646472657373416464726573733a20696e73756666696369656e742062616c616e636520666f722063616c6c536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f775361666545524332303a204552433230206f7065726174696f6e20646964206e6f7420737563636565645472616e7366657248656c7065723a205452414e534645525f46524f4d5f4641494c4544a2646970667358221220edcca2c602bb62331079d9d66d5bba75d5ad1fd88b0eb3f498b3dfd3d51abd8864736f6c634300060c0033", + "abi": [ + { + "inputs": [ + { "internalType": "address", "name": "_mdx", "type": "address" }, + { "internalType": "uint256", "name": "_cycle", "type": "uint256" } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "user", "type": "address" }, + { "indexed": true, "internalType": "uint256", "name": "pid", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "Deposit", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "user", "type": "address" }, + { "indexed": true, "internalType": "uint256", "name": "pid", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "EmergencyWithdraw", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "previousOwner", "type": "address" }, + { "indexed": true, "internalType": "address", "name": "newOwner", "type": "address" } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "user", "type": "address" }, + { "indexed": true, "internalType": "uint256", "name": "pid", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "Withdraw", + "type": "event" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "_allocPoint", "type": "uint256" }, + { "internalType": "contract IERC20", "name": "_lpToken", "type": "address" }, + { "internalType": "bool", "name": "_withUpdate", "type": "bool" } + ], + "name": "add", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "_bad", "type": "address" }], + "name": "addBadAddress", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "cycle", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "_bad", "type": "address" }], + "name": "delBadAddress", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "_pid", "type": "uint256" }, + { "internalType": "uint256", "name": "_amount", "type": "uint256" } + ], + "name": "deposit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint256", "name": "_pid", "type": "uint256" }], + "name": "emergencyWithdraw", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "endBlock", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint256", "name": "_index", "type": "uint256" }], + "name": "getBadAddress", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getBlackListLength", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "account", "type": "address" }], + "name": "isBadAddress", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + }, + { "inputs": [], "name": "massUpdatePools", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [], + "name": "mdx", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "mdxPerBlock", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "_mdxAmount", "type": "uint256" }, + { "internalType": "uint256", "name": "_newPerBlock", "type": "uint256" }, + { "internalType": "uint256", "name": "_startBlock", "type": "uint256" } + ], + "name": "newReward", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "_pid", "type": "uint256" }, + { "internalType": "address", "name": "_user", "type": "address" } + ], + "name": "pending", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "name": "poolInfo", + "outputs": [ + { "internalType": "contract IERC20", "name": "lpToken", "type": "address" }, + { "internalType": "uint256", "name": "allocPoint", "type": "uint256" }, + { "internalType": "uint256", "name": "lastRewardBlock", "type": "uint256" }, + { "internalType": "uint256", "name": "accMDXPerShare", "type": "uint256" }, + { "internalType": "uint256", "name": "mdxAmount", "type": "uint256" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "poolLength", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { "inputs": [], "name": "renounceOwnership", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { "internalType": "uint256", "name": "_pid", "type": "uint256" }, + { "internalType": "uint256", "name": "_allocPoint", "type": "uint256" }, + { "internalType": "bool", "name": "_withUpdate", "type": "bool" } + ], + "name": "set", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint256", "name": "_newCycle", "type": "uint256" }], + "name": "setCycle", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "startBlock", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalAllocPoint", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "newOwner", "type": "address" }], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint256", "name": "_pid", "type": "uint256" }], + "name": "updatePool", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "", "type": "uint256" }, + { "internalType": "address", "name": "", "type": "address" } + ], + "name": "userInfo", + "outputs": [ + { "internalType": "uint256", "name": "amount", "type": "uint256" }, + { "internalType": "uint256", "name": "rewardDebt", "type": "uint256" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "_pid", "type": "uint256" }, + { "internalType": "uint256", "name": "_amount", "type": "uint256" } + ], + "name": "withdraw", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ] +} diff --git a/assets/bsc/MdxToken.json b/assets/bsc/MdxToken.json new file mode 100644 index 00000000..56be3603 --- /dev/null +++ b/assets/bsc/MdxToken.json @@ -0,0 +1,290 @@ +{ + "bytecode": "60806040523480156200001157600080fd5b506040518060400160405280600981526020016826a22c102a37b5b2b760b91b8152506040518060400160405280600381526020016209a88b60eb1b815250816003908051906020019062000068929190620005f1565b5080516200007e906004906020840190620005f1565b50506005805460ff191660121790555060006200009a62000105565b600a80546001600160a01b0319166001600160a01b038316908117909155604051919250906000907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a350620000ff336a01a784379d99db4200000062000109565b62000768565b3390565b6200012082826200014b60201b62000e8d1760201c565b6001600160a01b038083166000908152600660205260408120546200014792168362000237565b5050565b6001600160a01b0382166200017d5760405162461bcd60e51b815260040162000174906200071a565b60405180910390fd5b6200018b60008383620003a4565b620001a781600254620003a960201b62000f4d1790919060201c565b6002556001600160a01b03821660009081526020818152604090912054620001da91839062000f4d620003a9821b17901c565b6001600160a01b0383166000818152602081905260408082209390935591519091907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906200022b90859062000751565b60405180910390a35050565b816001600160a01b0316836001600160a01b0316141580156200025a5750600081115b15620003a4576001600160a01b0383161562000302576001600160a01b03831660009081526008602052604081205463ffffffff1690816200029e576000620002d0565b6001600160a01b038516600090815260076020908152604080832063ffffffff60001987011684529091529020600101545b90506000620002ee8483620003d860201b62000f721790919060201c565b9050620002fe8684848462000422565b5050505b6001600160a01b03821615620003a4576001600160a01b03821660009081526008602052604081205463ffffffff1690816200034057600062000372565b6001600160a01b038416600090815260076020908152604080832063ffffffff60001987011684529091529020600101545b90506000620003908483620003a960201b62000f4d1790919060201c565b9050620003a08584848462000422565b5050505b505050565b600082820183811015620003d15760405162461bcd60e51b81526004016200017490620006e3565b9392505050565b6000620003d183836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506200058f60201b60201c565b600062000449436040518060600160405280603881526020016200271760389139620005be565b905060008463ffffffff161180156200049357506001600160a01b038516600090815260076020908152604080832063ffffffff6000198901811685529252909120548282169116145b15620004d2576001600160a01b038516600090815260076020908152604080832063ffffffff6000198901168452909152902060010182905562000543565b60408051808201825263ffffffff808416825260208083018681526001600160a01b038a166000818152600784528681208b8616825284528681209551865490861663ffffffff19918216178755925160019687015590815260089092529390208054928801909116919092161790555b846001600160a01b03167fdec2bacdd2f05b59de34da9b523dff8be42e5e38e818c82fdb0bae774387a7248484604051620005809291906200075a565b60405180910390a25050505050565b60008184841115620005b65760405162461bcd60e51b81526004016200017491906200068d565b505050900390565b6000816401000000008410620005e95760405162461bcd60e51b81526004016200017491906200068d565b509192915050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106200063457805160ff191683800117855562000664565b8280016001018555821562000664579182015b828111156200066457825182559160200191906001019062000647565b506200067292915062000676565b5090565b5b8082111562000672576000815560010162000677565b6000602080835283518082850152825b81811015620006bb578581018301518582016040015282016200069d565b81811115620006cd5783604083870101525b50601f01601f1916929092016040019392505050565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b6020808252601f908201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604082015260600190565b90815260200190565b918252602082015260400190565b611f9f80620007786000396000f3fe608060405234801561001057600080fd5b50600436106101cf5760003560e01c8063715018a611610104578063a9059cbb116100a2578063dd62ed3e11610071578063dd62ed3e146103b0578063e7a324dc146103c3578063f1127ed8146103cb578063f2fde38b146103ec576101cf565b8063a9059cbb14610364578063aa271e1a14610377578063b4b5ea571461038a578063c3cda5201461039d576101cf565b80638da5cb5b116100de5780638da5cb5b1461032e57806395d89b4114610336578063983b2d561461033e578063a457c2d714610351576101cf565b8063715018a614610300578063782d6fe1146103085780637ecebe001461031b576101cf565b8063313ce567116101715780635b7121f81161014b5780635b7121f8146102985780635c19a95c146102b85780636fcfff45146102cd57806370a08231146102ed576101cf565b8063313ce5671461025d578063395093511461027257806340c10f1914610285576101cf565b806318160ddd116101ad57806318160ddd1461022757806320606b701461022f57806323338b881461023757806323b872dd1461024a576101cf565b80630323aac7146101d457806306fdde03146101f2578063095ea7b314610207575b600080fd5b6101dc6103ff565b6040516101e99190611948565b60405180910390f35b6101fa610410565b6040516101e991906119b7565b61021a61021536600461182e565b6104a6565b6040516101e9919061193d565b6101dc6104c4565b6101dc6104ca565b61021a61024536600461179f565b6104ee565b61021a6102583660046117ee565b61055f565b6102656105e6565b6040516101e99190611e9b565b61021a61028036600461182e565b6105ef565b61021a61029336600461182e565b61063d565b6102ab6102a63660046118f6565b61069b565b6040516101e99190611929565b6102cb6102c636600461179f565b610707565b005b6102e06102db36600461179f565b610714565b6040516101e99190611e74565b6101dc6102fb36600461179f565b61072c565b6102cb610747565b6101dc61031636600461182e565b6107c6565b6101dc61032936600461179f565b6109af565b6102ab6109c1565b6101fa6109d0565b61021a61034c36600461179f565b610a31565b61021a61035f36600461182e565b610a99565b61021a61037236600461182e565b610b01565b61021a61038536600461179f565b610b15565b6101dc61039836600461179f565b610b22565b6102cb6103ab366004611858565b610b86565b6101dc6103be3660046117ba565b610d5a565b6101dc610d85565b6103de6103d93660046118b7565b610da9565b6040516101e9929190611e85565b6102cb6103fa36600461179f565b610dd6565b600061040b600b610fb4565b905090565b60038054604080516020601f600260001961010060018816150201909516949094049384018190048102820181019092528281526060939092909183018282801561049c5780601f106104715761010080835404028352916020019161049c565b820191906000526020600020905b81548152906001019060200180831161047f57829003601f168201915b5050505050905090565b60006104ba6104b3610fbf565b8484610fc3565b5060015b92915050565b60025490565b7f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a86681565b60006104f8610fbf565b600a546001600160a01b0390811691161461052e5760405162461bcd60e51b815260040161052590611d29565b60405180910390fd5b6001600160a01b0382166105545760405162461bcd60e51b815260040161052590611da3565b6104be600b83611077565b600061056c84848461108c565b6105dc84610578610fbf565b6105d785604051806060016040528060288152602001611f1d602891396001600160a01b038a166000908152600160205260408120906105b6610fbf565b6001600160a01b0316815260208101919091526040016000205491906110ce565b610fc3565b5060019392505050565b60055460ff1690565b60006104ba6105fc610fbf565b846105d7856001600061060d610fbf565b6001600160a01b03908116825260208083019390935260409182016000908120918c168152925290205490610f4d565b600061064833610b15565b6106645760405162461bcd60e51b815260040161052590611cbb565b6b011bb76193c72433c200000061068361067c6104c4565b8490610f4d565b1115610691575060006104be565b6104ba83836110fa565b60006106a5610fbf565b600a546001600160a01b039081169116146106d25760405162461bcd60e51b815260040161052590611d29565b60016106dc6103ff565b038211156106fc5760405162461bcd60e51b815260040161052590611cf2565b6104be600b8361112d565b6107113382611139565b50565b60086020526000908152604090205463ffffffff1681565b6001600160a01b031660009081526020819052604090205490565b61074f610fbf565b600a546001600160a01b0390811691161461077c5760405162461bcd60e51b815260040161052590611d29565b600a546040516000916001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600a80546001600160a01b0319169055565b60004382106107e75760405162461bcd60e51b815260040161052590611ba9565b6001600160a01b03831660009081526008602052604090205463ffffffff16806108155760009150506104be565b6001600160a01b038416600090815260076020908152604080832063ffffffff600019860181168552925290912054168310610884576001600160a01b03841660009081526007602090815260408083206000199490940163ffffffff168352929052206001015490506104be565b6001600160a01b038416600090815260076020908152604080832083805290915290205463ffffffff168310156108bf5760009150506104be565b600060001982015b8163ffffffff168163ffffffff16111561097857600282820363ffffffff160481036108f1611771565b506001600160a01b038716600090815260076020908152604080832063ffffffff808616855290835292819020815180830190925280549093168082526001909301549181019190915290871415610953576020015194506104be9350505050565b805163ffffffff1687111561096a57819350610971565b6001820392505b50506108c7565b506001600160a01b038516600090815260076020908152604080832063ffffffff9094168352929052206001015491505092915050565b60096020526000908152604090205481565b600a546001600160a01b031690565b60048054604080516020601f600260001961010060018816150201909516949094049384018190048102820181019092528281526060939092909183018282801561049c5780601f106104715761010080835404028352916020019161049c565b6000610a3b610fbf565b600a546001600160a01b03908116911614610a685760405162461bcd60e51b815260040161052590611d29565b6001600160a01b038216610a8e5760405162461bcd60e51b815260040161052590611ad9565b6104be600b836111eb565b60006104ba610aa6610fbf565b846105d785604051806060016040528060258152602001611f456025913960016000610ad0610fbf565b6001600160a01b03908116825260208083019390935260409182016000908120918d168152925290205491906110ce565b60006104ba610b0e610fbf565b848461108c565b60006104be600b83611200565b6001600160a01b03811660009081526008602052604081205463ffffffff1680610b4d576000610b7f565b6001600160a01b038316600090815260076020908152604080832063ffffffff60001986011684529091529020600101545b9392505050565b60007f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a866610bb1610410565b80519060200120610bc0611215565b30604051602001610bd49493929190611975565b60405160208183030381529060405280519060200120905060007fe48329057bfd03d55e49b547132e39cffd9c1820ad7b9d4c5307691425d15adf888888604051602001610c259493929190611951565b60405160208183030381529060405280519060200120905060008282604051602001610c5292919061190e565b604051602081830303815290604052805190602001209050600060018288888860405160008152602001604052604051610c8f9493929190611999565b6020604051602081039080840390855afa158015610cb1573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116610ce45760405162461bcd60e51b815260040161052590611c2b565b6001600160a01b03811660009081526009602052604090208054600181019091558914610d235760405162461bcd60e51b815260040161052590611c75565b87421115610d435760405162461bcd60e51b815260040161052590611a8f565b610d4d818b611139565b505050505b505050505050565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b7fe48329057bfd03d55e49b547132e39cffd9c1820ad7b9d4c5307691425d15adf81565b60076020908152600092835260408084209091529082529020805460019091015463ffffffff9091169082565b610dde610fbf565b600a546001600160a01b03908116911614610e0b5760405162461bcd60e51b815260040161052590611d29565b6001600160a01b038116610e315760405162461bcd60e51b815260040161052590611b21565b600a546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600a80546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b038216610eb35760405162461bcd60e51b815260040161052590611e2f565b610ebf600083836110c9565b600254610ecc9082610f4d565b6002556001600160a01b038216600090815260208190526040902054610ef29082610f4d565b6001600160a01b0383166000818152602081905260408082209390935591519091907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90610f41908590611948565b60405180910390a35050565b600082820183811015610b7f5760405162461bcd60e51b815260040161052590611bf4565b6000610b7f83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506110ce565b60006104be82611219565b3390565b6001600160a01b038316610fe95760405162461bcd60e51b815260040161052590611deb565b6001600160a01b03821661100f5760405162461bcd60e51b815260040161052590611b67565b6001600160a01b0380841660008181526001602090815260408083209487168084529490915290819020849055517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259061106a908590611948565b60405180910390a3505050565b6000610b7f836001600160a01b03841661121d565b6110978383836112e3565b6001600160a01b038084166000908152600660205260408082205485841683529120546110c9929182169116836113f8565b505050565b600081848411156110f25760405162461bcd60e51b815260040161052591906119b7565b505050900390565b6111048282610e8d565b6001600160a01b038083166000908152600660205260408120546111299216836113f8565b5050565b6000610b7f8383611535565b6001600160a01b03808316600090815260066020526040812054909116906111608461072c565b6001600160a01b03858116600090815260066020526040902080546001600160a01b031916918616919091179055905061119b8284836113f8565b826001600160a01b0316826001600160a01b0316856001600160a01b03167f3134e8a2e6d97e929a7e54011ea5485d7d196dd5f0ba4d4ef95803e8e3fc257f60405160405180910390a450505050565b6000610b7f836001600160a01b03841661157a565b6000610b7f836001600160a01b0384166115c4565b4690565b5490565b600081815260018301602052604081205480156112d9578354600019808301919081019060009087908390811061125057fe5b906000526020600020015490508087600001848154811061126d57fe5b60009182526020808320909101929092558281526001898101909252604090209084019055865487908061129d57fe5b600190038181906000526020600020016000905590558660010160008781526020019081526020016000206000905560019450505050506104be565b60009150506104be565b6001600160a01b0383166113095760405162461bcd60e51b815260040161052590611d5e565b6001600160a01b03821661132f5760405162461bcd60e51b815260040161052590611a4c565b61133a8383836110c9565b61137781604051806060016040528060268152602001611ef7602691396001600160a01b03861660009081526020819052604090205491906110ce565b6001600160a01b0380851660009081526020819052604080822093909355908416815220546113a69082610f4d565b6001600160a01b0380841660008181526020819052604090819020939093559151908516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9061106a908590611948565b816001600160a01b0316836001600160a01b03161415801561141a5750600081115b156110c9576001600160a01b038316156114ac576001600160a01b03831660009081526008602052604081205463ffffffff16908161145a57600061148c565b6001600160a01b038516600090815260076020908152604080832063ffffffff60001987011684529091529020600101545b9050600061149a8285610f72565b90506114a8868484846115dc565b5050505b6001600160a01b038216156110c9576001600160a01b03821660009081526008602052604081205463ffffffff1690816114e7576000611519565b6001600160a01b038416600090815260076020908152604080832063ffffffff60001987011684529091529020600101545b905060006115278285610f4d565b9050610d52858484846115dc565b815460009082106115585760405162461bcd60e51b815260040161052590611a0a565b82600001828154811061156757fe5b9060005260206000200154905092915050565b600061158683836115c4565b6115bc575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556104be565b5060006104be565b60009081526001919091016020526040902054151590565b600061160043604051806060016040528060388152602001611ebf60389139611741565b905060008463ffffffff1611801561164957506001600160a01b038516600090815260076020908152604080832063ffffffff6000198901811685529252909120548282169116145b15611686576001600160a01b038516600090815260076020908152604080832063ffffffff600019890116845290915290206001018290556116f7565b60408051808201825263ffffffff808416825260208083018681526001600160a01b038a166000818152600784528681208b8616825284528681209551865490861663ffffffff19918216178755925160019687015590815260089092529390208054928801909116919092161790555b846001600160a01b03167fdec2bacdd2f05b59de34da9b523dff8be42e5e38e818c82fdb0bae774387a7248484604051611732929190611e66565b60405180910390a25050505050565b60008164010000000084106117695760405162461bcd60e51b815260040161052591906119b7565b509192915050565b604080518082019091526000808252602082015290565b80356001600160a01b03811681146104be57600080fd5b6000602082840312156117b0578081fd5b610b7f8383611788565b600080604083850312156117cc578081fd5b6117d68484611788565b91506117e58460208501611788565b90509250929050565b600080600060608486031215611802578081fd5b833561180d81611ea9565b9250602084013561181d81611ea9565b929592945050506040919091013590565b60008060408385031215611840578182fd5b61184a8484611788565b946020939093013593505050565b60008060008060008060c08789031215611870578182fd5b61187a8888611788565b95506020870135945060408701359350606087013560ff8116811461189d578283fd5b9598949750929560808101359460a0909101359350915050565b600080604083850312156118c9578182fd5b6118d38484611788565b9150602083013563ffffffff811681146118eb578182fd5b809150509250929050565b600060208284031215611907578081fd5b5035919050565b61190160f01b81526002810192909252602282015260420190565b6001600160a01b0391909116815260200190565b901515815260200190565b90815260200190565b9384526001600160a01b039290921660208401526040830152606082015260800190565b938452602084019290925260408301526001600160a01b0316606082015260800190565b93845260ff9290921660208401526040830152606082015260800190565b6000602080835283518082850152825b818110156119e3578581018301518582016040015282016119c7565b818111156119f45783604083870101525b50601f01601f1916929092016040019392505050565b60208082526022908201527f456e756d657261626c655365743a20696e646578206f7574206f6620626f756e604082015261647360f01b606082015260800190565b60208082526023908201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260408201526265737360e81b606082015260800190565b6020808252602a908201527f4d6478546f6b656e3a3a64656c656761746542795369673a207369676e6174756040820152691c9948195e1c1a5c995960b21b606082015260800190565b60208082526028908201527f4d6478546f6b656e3a205f6164644d696e74657220697320746865207a65726f604082015267206164647265737360c01b606082015260800190565b60208082526026908201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160408201526564647265737360d01b606082015260800190565b60208082526022908201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604082015261737360f01b606082015260800190565b6020808252602b908201527f4d6478546f6b656e3a3a6765745072696f72566f7465733a206e6f742079657460408201526a0819195d195c9b5a5b995960aa1b606082015260800190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b6020808252602a908201527f4d6478546f6b656e3a3a64656c656761746542795369673a20696e76616c6964604082015269207369676e617475726560b01b606082015260800190565b60208082526026908201527f4d6478546f6b656e3a3a64656c656761746542795369673a20696e76616c6964604082015265206e6f6e636560d01b606082015260800190565b60208082526018908201527f63616c6c6572206973206e6f7420746865206d696e7465720000000000000000604082015260600190565b6020808252601d908201527f4d6478546f6b656e3a20696e646578206f7574206f6620626f756e6473000000604082015260600190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b60208082526025908201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604082015264647265737360d81b606082015260800190565b60208082526028908201527f4d6478546f6b656e3a205f64656c4d696e74657220697320746865207a65726f604082015267206164647265737360c01b606082015260800190565b60208082526024908201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646040820152637265737360e01b606082015260800190565b6020808252601f908201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604082015260600190565b918252602082015260400190565b63ffffffff91909116815260200190565b63ffffffff929092168252602082015260400190565b60ff91909116815260200190565b6001600160a01b038116811461071157600080fdfe4d6478546f6b656e3a3a5f7772697465436865636b706f696e743a20626c6f636b206e756d6265722065786365656473203332206269747345524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e636545524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e636545524332303a2064656372656173656420616c6c6f77616e63652062656c6f77207a65726fa2646970667358221220571d29d0f30fd05ea901af896d6c27a52efe3ae2d419682c7e2daeabf9f3d03f64736f6c634300060c00334d6478546f6b656e3a3a5f7772697465436865636b706f696e743a20626c6f636b206e756d62657220657863656564732033322062697473", + "abi": [ + { "inputs": [], "stateMutability": "nonpayable", "type": "constructor" }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "owner", "type": "address" }, + { "indexed": true, "internalType": "address", "name": "spender", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "value", "type": "uint256" } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "delegator", "type": "address" }, + { "indexed": true, "internalType": "address", "name": "fromDelegate", "type": "address" }, + { "indexed": true, "internalType": "address", "name": "toDelegate", "type": "address" } + ], + "name": "DelegateChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "delegate", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "previousBalance", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "newBalance", "type": "uint256" } + ], + "name": "DelegateVotesChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "previousOwner", "type": "address" }, + { "indexed": true, "internalType": "address", "name": "newOwner", "type": "address" } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "from", "type": "address" }, + { "indexed": true, "internalType": "address", "name": "to", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "value", "type": "uint256" } + ], + "name": "Transfer", + "type": "event" + }, + { + "inputs": [], + "name": "DELEGATION_TYPEHASH", + "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "DOMAIN_TYPEHASH", + "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "_addMinter", "type": "address" }], + "name": "addMinter", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "owner", "type": "address" }, + { "internalType": "address", "name": "spender", "type": "address" } + ], + "name": "allowance", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "spender", "type": "address" }, + { "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "approve", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "account", "type": "address" }], + "name": "balanceOf", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "", "type": "address" }, + { "internalType": "uint32", "name": "", "type": "uint32" } + ], + "name": "checkpoints", + "outputs": [ + { "internalType": "uint32", "name": "fromBlock", "type": "uint32" }, + { "internalType": "uint256", "name": "votes", "type": "uint256" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "decimals", + "outputs": [{ "internalType": "uint8", "name": "", "type": "uint8" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "spender", "type": "address" }, + { "internalType": "uint256", "name": "subtractedValue", "type": "uint256" } + ], + "name": "decreaseAllowance", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "_delMinter", "type": "address" }], + "name": "delMinter", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "delegatee", "type": "address" }], + "name": "delegate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "delegatee", "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": "delegateBySig", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "account", "type": "address" }], + "name": "getCurrentVotes", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint256", "name": "_index", "type": "uint256" }], + "name": "getMinter", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getMinterLength", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "account", "type": "address" }, + { "internalType": "uint256", "name": "blockNumber", "type": "uint256" } + ], + "name": "getPriorVotes", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "spender", "type": "address" }, + { "internalType": "uint256", "name": "addedValue", "type": "uint256" } + ], + "name": "increaseAllowance", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "account", "type": "address" }], + "name": "isMinter", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "_to", "type": "address" }, + { "internalType": "uint256", "name": "_amount", "type": "uint256" } + ], + "name": "mint", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [{ "internalType": "string", "name": "", "type": "string" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "", "type": "address" }], + "name": "nonces", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "", "type": "address" }], + "name": "numCheckpoints", + "outputs": [{ "internalType": "uint32", "name": "", "type": "uint32" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { "inputs": [], "name": "renounceOwnership", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [], + "name": "symbol", + "outputs": [{ "internalType": "string", "name": "", "type": "string" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "recipient", "type": "address" }, + { "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "transfer", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "sender", "type": "address" }, + { "internalType": "address", "name": "recipient", "type": "address" }, + { "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "transferFrom", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "newOwner", "type": "address" }], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ] +} diff --git a/contracts/interfaces/sushi/IMasterChefV1.sol b/contracts/interfaces/sushi/IMasterChefV1.sol index 5d77e825..5dcf9c53 100644 --- a/contracts/interfaces/sushi/IMasterChefV1.sol +++ b/contracts/interfaces/sushi/IMasterChefV1.sol @@ -5,6 +5,8 @@ pragma solidity ^0.6.12; interface IMasterChefV1 { function userInfo(uint256 _pid, address _user) external view returns (uint256 amount, uint256 rewardDebt); + function pending(uint256 _pid, address _user) external view returns (uint256); + function deposit(uint256 _pid, uint256 _amount) external; function withdraw(uint256 _pid, uint256 _amount) external; diff --git a/contracts/powerindex-router/implementations/MasterChefPowerIndexRouter.sol b/contracts/powerindex-router/implementations/MasterChefPowerIndexRouter.sol index 745c8046..2a5c24ea 100644 --- a/contracts/powerindex-router/implementations/MasterChefPowerIndexRouter.sol +++ b/contracts/powerindex-router/implementations/MasterChefPowerIndexRouter.sol @@ -10,8 +10,6 @@ import "./AbstractMasterChefIndexRouter.sol"; * Compatible with: * - MDEX: https://bscscan.com/address/0x6aee12e5eb987b3be1ba8e621be7c4804925ba68, * pending rewards via pending(pid, user) - * - Bakery: https://bscscan.com/address/0x20ec291bb8459b6145317e7126532ce7ece5056f, - * pending rewards via pendingBake(pid, user) * - Auto: https://bscscan.com/address/0x763a05bdb9f8946d8c3fa72d1e0d3f5e68647e5c, * pending rewards via stakedWantTokens(pid, user) */ @@ -31,21 +29,27 @@ contract MasterChefPowerIndexRouter is AbstractMasterChefIndexRouter { MASTER_CHEF_PID = _masterChefConfig.masterChefPid; } + /*** VIEWERS ***/ + + function getPendingRewards() public view returns (uint256 amount) { + return IMasterChefV1(staking).pending(MASTER_CHEF_PID, address(piToken)); + } + /*** OVERRIDES ***/ function _getUnderlyingStaked() internal view override returns (uint256) { if (staking == address(0)) { return 0; } - (uint256 amount, ) = IMasterChefV1(staking).userInfo(0, address(piToken)); + (uint256 amount, ) = IMasterChefV1(staking).userInfo(MASTER_CHEF_PID, address(piToken)); return amount; } function _stakeImpl(uint256 _amount) internal override { - _callStaking(IMasterChefV1.deposit.selector, abi.encode(address(TOKEN), _amount)); + _callStaking(IMasterChefV1.deposit.selector, abi.encode(MASTER_CHEF_PID, _amount)); } function _redeemImpl(uint256 _amount) internal override { - _callStaking(IMasterChefV1.withdraw.selector, abi.encode(address(TOKEN), _amount)); + _callStaking(IMasterChefV1.withdraw.selector, abi.encode(MASTER_CHEF_PID, _amount)); } } diff --git a/contracts/test/MockGeneralMasterChef.sol b/contracts/test/MockGeneralMasterChef.sol new file mode 100644 index 00000000..ac025953 --- /dev/null +++ b/contracts/test/MockGeneralMasterChef.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +contract MockGeneralMasterChef { + address token; + + constructor(address _token) public { + token = _token; + } + + function deposit(uint256, uint256 _amount) external { + IERC20(token).transferFrom(msg.sender, address(42), _amount); + } + + function withdraw(uint256, uint256) external {} + + function userInfo(uint256, address) external view returns (uint256 amount, uint256 rewardDebt) { + return (0, 0); + } +} diff --git a/test/router/implementations/BakeryMasterChefRouter.unit.js b/test/router/implementations/BakeryMasterChefRouter.unit.js index 57a336f8..b7288d9b 100644 --- a/test/router/implementations/BakeryMasterChefRouter.unit.js +++ b/test/router/implementations/BakeryMasterChefRouter.unit.js @@ -24,7 +24,7 @@ describe('BakeryMasterChefRouter Tests', () => { [deployer, bob, alice, piGov, stub, pvp, pool1, pool2] = await web3.eth.getAccounts(); }); - let bake, bakeryChef, poolRestrictions, piMyToken, myRouter, poke; + let bake, bakeryChef, poolRestrictions, piBake, myRouter, poke; beforeEach(async function() { // bsc: 0xe02df9e3e622debdd69fb838bb799e3f168902c5 @@ -51,11 +51,11 @@ describe('BakeryMasterChefRouter Tests', () => { await bake.mintTo(deployer, ether('10000000')); poolRestrictions = await PoolRestrictions.new(); - piMyToken = await WrappedPiErc20.new(bake.address, stub, 'Wrapped My Staking Token', 'piMST'); + piBake = await WrappedPiErc20.new(bake.address, stub, 'Wrapped BAKE', 'piBAKE'); poke = await MockPoke.new(true); myRouter = await BakeryChefPowerIndexRouter.new( - piMyToken.address, + piBake.address, buildBasicRouterConfig( poolRestrictions.address, poke.address, @@ -71,7 +71,7 @@ describe('BakeryMasterChefRouter Tests', () => { buildBakeryChefRouterConfig(bake.address), ); - await piMyToken.changeRouter(myRouter.address, { from: stub }); + await piBake.changeRouter(myRouter.address, { from: stub }); await bakeryChef.add(20306, bake.address, false); await myRouter.transferOwnership(piGov); await bake.transferOwnership(bakeryChef.address); @@ -87,14 +87,14 @@ describe('BakeryMasterChefRouter Tests', () => { describe('stake()/redeem()', () => { beforeEach(async () => { await bake.transfer(alice, ether('10000')); - await bake.approve(piMyToken.address, ether('10000'), { from: alice }); - await piMyToken.deposit(ether('10000'), { from: alice }); + await bake.approve(piBake.address, ether('10000'), { from: alice }); + await piBake.deposit(ether('10000'), { from: alice }); await myRouter.poke(false); - assert.equal(await bake.balanceOf(piMyToken.address), ether(2000)); + assert.equal(await bake.balanceOf(piBake.address), ether(2000)); assert.equal(await bake.balanceOf(bakeryChef.address), ether(8000)); - assert.equal((await bakeryChef.poolUserInfoMap(bake.address, piMyToken.address)).amount, ether(8000)); + assert.equal((await bakeryChef.poolUserInfoMap(bake.address, piBake.address)).amount, ether(8000)); }); describe('stake()', () => { @@ -104,9 +104,9 @@ describe('BakeryMasterChefRouter Tests', () => { sender: piGov, amount: ether(2000), }); - assert.equal(await bake.balanceOf(piMyToken.address), ether(0)); + assert.equal(await bake.balanceOf(piBake.address), ether(0)); assert.equal(await bake.balanceOf(bakeryChef.address), ether(10000)); - const userInfo = await bakeryChef.poolUserInfoMap(bake.address, piMyToken.address); + const userInfo = await bakeryChef.poolUserInfoMap(bake.address, piBake.address); assert.equal(userInfo.amount, ether(10000)); }); @@ -122,8 +122,8 @@ describe('BakeryMasterChefRouter Tests', () => { sender: piGov, amount: ether(3000), }); - assert.equal(await bake.balanceOf(piMyToken.address), ether(5000)); - const userInfo = await bakeryChef.poolUserInfoMap(bake.address, piMyToken.address); + assert.equal(await bake.balanceOf(piBake.address), ether(5000)); + const userInfo = await bakeryChef.poolUserInfoMap(bake.address, piBake.address); assert.equal(userInfo.amount, ether(5000)); }); @@ -173,8 +173,8 @@ describe('BakeryMasterChefRouter Tests', () => { beforeEach(async () => { // alice await bake.transfer(alice, ether('20000')); - await bake.approve(piMyToken.address, ether('10000'), { from: alice }); - await piMyToken.deposit(ether('10000'), { from: alice }); + await bake.approve(piBake.address, ether('10000'), { from: alice }); + await piBake.deposit(ether('10000'), { from: alice }); // bob await bake.transfer(bob, ether('42000')); @@ -184,33 +184,33 @@ describe('BakeryMasterChefRouter Tests', () => { await myRouter.poke(false); assert.equal(await bake.balanceOf(bakeryChef.address), ether(50400)); - assert.equal(await bake.balanceOf(piMyToken.address), ether(2000)); + assert.equal(await bake.balanceOf(piBake.address), ether(2000)); }); it('should increase reserve on deposit', async () => { - assert.equal(await piMyToken.balanceOf(alice), ether(10000)); - await bake.approve(piMyToken.address, ether(1000), { from: alice }); - await piMyToken.deposit(ether(1000), { from: alice }); + assert.equal(await piBake.balanceOf(alice), ether(10000)); + await bake.approve(piBake.address, ether(1000), { from: alice }); + await piBake.deposit(ether(1000), { from: alice }); await myRouter.poke(false); - assert.equal(await piMyToken.balanceOf(alice), ether(11000)); + assert.equal(await piBake.balanceOf(alice), ether(11000)); assert.equal(await bake.balanceOf(bakeryChef.address), ether('52209.523809528000000000')); - assert.equal(await bake.balanceOf(piMyToken.address), ether(2200)); + assert.equal(await bake.balanceOf(piBake.address), ether(2200)); assert.equal(await myRouter.getUnderlyingStaked(), ether(8800)); - assert.equal((await bakeryChef.poolUserInfoMap(bake.address, piMyToken.address)).amount, ether(8800)); + assert.equal((await bakeryChef.poolUserInfoMap(bake.address, piBake.address)).amount, ether(8800)); }); it('should decrease reserve on withdrawal', async () => { - assert.equal(await piMyToken.balanceOf(alice), ether(10000)); + assert.equal(await piBake.balanceOf(alice), ether(10000)); - await piMyToken.withdraw(ether(1000), { from: alice }); + await piBake.withdraw(ether(1000), { from: alice }); await myRouter.poke(false); - assert.equal(await piMyToken.balanceOf(alice), ether(9000)); + assert.equal(await piBake.balanceOf(alice), ether(9000)); assert.equal(await bake.balanceOf(bakeryChef.address), ether('50273.015873016000000000')); - assert.equal(await bake.balanceOf(piMyToken.address), ether(1800)); + assert.equal(await bake.balanceOf(piBake.address), ether(1800)); assert.equal(await myRouter.getUnderlyingStaked(), ether(7200)); - assert.equal((await bakeryChef.poolUserInfoMap(bake.address, piMyToken.address)).amount, ether(7200)); + assert.equal((await bakeryChef.poolUserInfoMap(bake.address, piBake.address)).amount, ether(7200)); }); it('should ignore rebalancing if the staking address is 0', async () => { @@ -218,10 +218,10 @@ describe('BakeryMasterChefRouter Tests', () => { await myRouter.setVotingAndStaking(bakeryChef.address, constants.ZERO_ADDRESS, { from: piGov }); assert.equal(await bake.balanceOf(bakeryChef.address), ether('42736.507936512000000000')); - assert.equal(await bake.balanceOf(piMyToken.address), ether(10000)); - assert.equal(await piMyToken.balanceOf(alice), ether(10000)); - assert.equal(await piMyToken.totalSupply(), ether(10000)); - await piMyToken.withdraw(ether(1000), { from: alice }); + assert.equal(await bake.balanceOf(piBake.address), ether(10000)); + assert.equal(await piBake.balanceOf(alice), ether(10000)); + assert.equal(await piBake.totalSupply(), ether(10000)); + await piBake.withdraw(ether(1000), { from: alice }); await expectRevert(myRouter.poke(false), 'STAKING_IS_NULL'); }); @@ -234,39 +234,39 @@ describe('BakeryMasterChefRouter Tests', () => { it('should DO rebalance by pokeFromReporter if the rebalancing interval has passed', async () => { await time.increase(time.duration.minutes(61)); - await bake.approve(piMyToken.address, ether(1000), { from: alice }); - await piMyToken.deposit(ether(1000), { from: alice }); + await bake.approve(piBake.address, ether(1000), { from: alice }); + await piBake.deposit(ether(1000), { from: alice }); await expectRevert(myRouter.pokeFromSlasher(0, false, '0x'), 'MAX_INTERVAL_NOT_REACHED'); }); it('should DO rebalance by pokeFromSlasher if the rebalancing interval has passed', async () => { await time.increase(time.duration.minutes(121)); - await bake.approve(piMyToken.address, ether(1000), { from: alice }); - await piMyToken.deposit(ether(1000), { from: alice }); + await bake.approve(piBake.address, ether(1000), { from: alice }); + await piBake.deposit(ether(1000), { from: alice }); await myRouter.pokeFromSlasher(0, false, '0x'); assert.equal(await bake.balanceOf(bakeryChef.address), ether('53219.047619048000000000')); - assert.equal((await bakeryChef.poolUserInfoMap(bake.address, piMyToken.address)).amount, ether(8800)); - assert.equal(await bake.balanceOf(piMyToken.address), ether(2200)); + assert.equal((await bakeryChef.poolUserInfoMap(bake.address, piBake.address)).amount, ether(8800)); + assert.equal(await bake.balanceOf(piBake.address), ether(2200)); }); it('should DO rebalance on withdrawal if the rebalancing interval has passed', async () => { await time.increase(time.duration.minutes(61)); - await piMyToken.withdraw(ether(1000), { from: alice }); + await piBake.withdraw(ether(1000), { from: alice }); await myRouter.poke(false); assert.equal(await bake.balanceOf(bakeryChef.address), ether('51282.539682544000000000')); - assert.equal((await bakeryChef.poolUserInfoMap(bake.address, piMyToken.address)).amount, ether(7200)); - assert.equal(await bake.balanceOf(piMyToken.address), ether(1800)); + assert.equal((await bakeryChef.poolUserInfoMap(bake.address, piBake.address)).amount, ether(7200)); + assert.equal(await bake.balanceOf(piBake.address), ether(1800)); }); it('should NOT rebalance by pokeFromReporter if the rebalancing interval has passed', async () => { await time.increase(time.duration.minutes(50)); - await bake.approve(piMyToken.address, ether(1000), { from: alice }); - await piMyToken.deposit(ether(1000), { from: alice }); + await bake.approve(piBake.address, ether(1000), { from: alice }); + await piBake.deposit(ether(1000), { from: alice }); await expectRevert(myRouter.pokeFromReporter(0, false, '0x'), 'MIN_INTERVAL_NOT_REACHED'); await expectRevert(myRouter.pokeFromSlasher(0, false, '0x'), 'MAX_INTERVAL_NOT_REACHED'); }); @@ -274,8 +274,8 @@ describe('BakeryMasterChefRouter Tests', () => { it('should NOT rebalance by pokeFromSlasher if the rebalancing interval has passed', async () => { await time.increase(time.duration.minutes(70)); - await bake.approve(piMyToken.address, ether(1000), { from: alice }); - await piMyToken.deposit(ether(1000), { from: alice }); + await bake.approve(piBake.address, ether(1000), { from: alice }); + await piBake.deposit(ether(1000), { from: alice }); await expectRevert(myRouter.pokeFromSlasher(0, false, '0x'), 'MAX_INTERVAL_NOT_REACHED'); }); }); @@ -285,22 +285,22 @@ describe('BakeryMasterChefRouter Tests', () => { await myRouter.poke(false, { from: bob }); assert.equal(await bake.balanceOf(bakeryChef.address), ether(50400)); - assert.equal((await bakeryChef.poolUserInfoMap(bake.address, piMyToken.address)).amount, ether(8000)); - assert.equal(await bake.balanceOf(piMyToken.address), ether(2000)); + assert.equal((await bakeryChef.poolUserInfoMap(bake.address, piBake.address)).amount, ether(8000)); + assert.equal(await bake.balanceOf(piBake.address), ether(2000)); }); it('should increase reserve if required', async () => { - await bake.transfer(piMyToken.address, ether(1000), { from: alice }); + await bake.transfer(piBake.address, ether(1000), { from: alice }); assert.equal(await bake.balanceOf(bakeryChef.address), ether(50400)); - assert.equal((await bakeryChef.poolUserInfoMap(bake.address, piMyToken.address)).amount, ether(8000)); - assert.equal(await bake.balanceOf(piMyToken.address), ether(3000)); + assert.equal((await bakeryChef.poolUserInfoMap(bake.address, piBake.address)).amount, ether(8000)); + assert.equal(await bake.balanceOf(piBake.address), ether(3000)); await myRouter.poke(false, { from: bob }); assert.equal(await bake.balanceOf(bakeryChef.address), ether('51873.015873016000000000')); - assert.equal((await bakeryChef.poolUserInfoMap(bake.address, piMyToken.address)).amount, ether(8800)); - assert.equal(await bake.balanceOf(piMyToken.address), ether(2200)); + assert.equal((await bakeryChef.poolUserInfoMap(bake.address, piBake.address)).amount, ether(8800)); + assert.equal(await bake.balanceOf(piBake.address), ether(2200)); }); }); @@ -309,7 +309,7 @@ describe('BakeryMasterChefRouter Tests', () => { await myRouter.poke(false, { from: bob }); assert.equal(await bake.balanceOf(bakeryChef.address), ether('53073.015873016000000000')); - assert.equal(await bake.balanceOf(piMyToken.address), ether(0)); + assert.equal(await bake.balanceOf(piBake.address), ether(0)); }); it('should keep all the underlying tokens on piToken with 1 RR', async () => { @@ -317,7 +317,7 @@ describe('BakeryMasterChefRouter Tests', () => { await myRouter.poke(false, { from: bob }); assert.equal(await bake.balanceOf(bakeryChef.address), ether('43073.015873016000000000')); - assert.equal(await bake.balanceOf(piMyToken.address), ether(10000)); + assert.equal(await bake.balanceOf(piBake.address), ether(10000)); }); }); @@ -335,22 +335,22 @@ describe('BakeryMasterChefRouter Tests', () => { // await bake.transfer(syrupPool.address, ether(12000)); await bake.transfer(alice, ether('10000')); - await bake.approve(piMyToken.address, ether('10000'), { from: alice }); - await piMyToken.deposit(ether('10000'), { from: alice }); + await bake.approve(piBake.address, ether('10000'), { from: alice }); + await piBake.deposit(ether('10000'), { from: alice }); await myRouter.poke(false); - assert.equal(await piMyToken.totalSupply(), ether('10000')); - assert.equal(await piMyToken.balanceOf(alice), ether('10000')); + assert.equal(await piBake.totalSupply(), ether('10000')); + assert.equal(await piBake.balanceOf(alice), ether('10000')); - await piMyToken.transfer(poolA.address, 10, { from: alice }); - await piMyToken.transfer(poolB.address, 20, { from: alice }); + await piBake.transfer(poolA.address, 10, { from: alice }); + await piBake.transfer(poolB.address, 20, { from: alice }); }); it('should allow distribute the accrued rewards', async () => { await bake.transfer(bakeryChef.address, ether(2000)); - assert.equal(await bake.balanceOf(piMyToken.address), ether(2000)); + assert.equal(await bake.balanceOf(piBake.address), ether(2000)); assert.equal(await myRouter.getUnderlyingStaked(), ether(8000)); assert.equal(await myRouter.getPendingRewards(), ether(960)); @@ -365,7 +365,7 @@ describe('BakeryMasterChefRouter Tests', () => { pools: [poolA.address, poolB.address, poolC.address], }); - assert.equal(await bake.balanceOf(piMyToken.address), ether(3088)); + assert.equal(await bake.balanceOf(piBake.address), ether(3088)); assert.equal(await bake.balanceOf(myRouter.address), '0'); assert.isTrue(parseInt(res.logs[3].args.poolRewardsUnderlying) > 1); @@ -382,10 +382,10 @@ describe('BakeryMasterChefRouter Tests', () => { assert.equal(res.logs[2].args.pool, poolB.address); assert.equal(res.logs[2].args.amount, ether('725.333333333333333333')); - assert.equal(await piMyToken.balanceOf(poolA.address), ether('362.666666666666666676')); - assert.equal(await piMyToken.balanceOf(poolB.address), ether('725.333333333333333353')); - assert.equal(await piMyToken.balanceOf(poolC.address), '0'); - assert.equal(await piMyToken.balanceOf(poolD.address), '0'); + assert.equal(await piBake.balanceOf(poolA.address), ether('362.666666666666666676')); + assert.equal(await piBake.balanceOf(poolB.address), ether('725.333333333333333353')); + assert.equal(await piBake.balanceOf(poolC.address), '0'); + assert.equal(await piBake.balanceOf(poolD.address), '0'); assert.equal(await bake.balanceOf(myRouter.address), '0'); assert.equal(await bake.balanceOf(myRouter.address), '0'); @@ -408,7 +408,7 @@ describe('BakeryMasterChefRouter Tests', () => { it('should revert distributing rewards when missing reward pools config', async () => { poke = await MockPoke.new(true); const router = await BakeryChefPowerIndexRouter.new( - piMyToken.address, + piBake.address, buildBasicRouterConfig( poolRestrictions.address, poke.address, @@ -423,7 +423,7 @@ describe('BakeryMasterChefRouter Tests', () => { ), buildBakeryChefRouterConfig(bake.address), ) - await myRouter.migrateToNewRouter(piMyToken.address, router.address, [], { from: piGov }); + await myRouter.migrateToNewRouter(piBake.address, router.address, [], { from: piGov }); await bake.transfer(bakeryChef.address, ether(2000)); await time.increase(1); await expectRevert(router.poke(true, { from: bob }), 'MISSING_REWARD_POOLS'); diff --git a/test/router/implementations/MDXMasterChefRouter.unit.js b/test/router/implementations/MDXMasterChefRouter.unit.js new file mode 100644 index 00000000..a52bf9f1 --- /dev/null +++ b/test/router/implementations/MDXMasterChefRouter.unit.js @@ -0,0 +1,427 @@ +const { time, constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { ether, artifactFromBytecode, latestBlockNumber } = require('../../helpers'); +const { buildBasicRouterConfig, buildMasterChefRouterConfig } = require('../../helpers/builders'); +const assert = require('chai').assert; +const MDXChefPowerIndexRouter = artifacts.require('MasterChefPowerIndexRouter'); +const WrappedPiErc20 = artifacts.require('WrappedPiErc20'); +const PoolRestrictions = artifacts.require('PoolRestrictions'); +const MockGeneralMasterChef = artifacts.require('MockGeneralMasterChef'); +const MockGulpingBPool = artifacts.require('MockGulpingBPool'); +const MockPoke = artifacts.require('MockPoke'); + +const BoardRoomMDX = artifactFromBytecode('bsc/BoardRoomMDX'); +const BakeryToken = artifactFromBytecode('bsc/MdxToken'); + +MDXChefPowerIndexRouter.numberFormat = 'String'; +WrappedPiErc20.numberFormat = 'String'; + +const { web3 } = WrappedPiErc20; + +describe('MDXMasterChefRouter Tests', () => { + let deployer, bob, alice, piGov, stub, pvp, pool1, pool2; + + before(async function() { + [deployer, bob, alice, piGov, stub, pvp, pool1, pool2] = await web3.eth.getAccounts(); + }); + + let mdx, boardRoomMDX, poolRestrictions, piMdx, myRouter, poke; + + beforeEach(async function() { + // bsc: 0x9c65ab58d8d978db963e63f2bfb7121627e3a739 + mdx = await BakeryToken.new(); + + // bsc: 0x6aee12e5eb987b3be1ba8e621be7c4804925ba68 + boardRoomMDX = await BoardRoomMDX.new( + mdx.address, + 28800 + ); + await mdx.addMinter(deployer); + await mdx.mint(deployer, ether('10000000')); + + poolRestrictions = await PoolRestrictions.new(); + piMdx = await WrappedPiErc20.new(mdx.address, stub, 'Wrapped MDX', 'piMDX'); + + poke = await MockPoke.new(true); + myRouter = await MDXChefPowerIndexRouter.new( + piMdx.address, + buildBasicRouterConfig( + poolRestrictions.address, + poke.address, + constants.ZERO_ADDRESS, + boardRoomMDX.address, + ether('0.2'), + ether('0.02'), + '0', + pvp, + ether('0.15'), + [pool1, pool2], + ), + buildMasterChefRouterConfig(mdx.address, 0), + ); + + await piMdx.changeRouter(myRouter.address, { from: stub }); + await boardRoomMDX.add(10000, mdx.address, true); + await myRouter.transferOwnership(piGov); + await mdx.transferOwnership(boardRoomMDX.address); + + // setting up rewards + await mdx.approve(boardRoomMDX.address, ether(518400)); + const mdxPerBlock = ether(12); + const startBlock = await latestBlockNumber(); + await boardRoomMDX.newReward(ether(518400), mdxPerBlock, startBlock); + + assert.equal(await myRouter.owner(), piGov); + }); + + describe('owner methods', async () => { + beforeEach(async () => { + await myRouter.transferOwnership(piGov, { from: piGov }); + }); + + describe('stake()/redeem()', () => { + beforeEach(async () => { + await mdx.transfer(alice, ether('10000')); + await mdx.approve(piMdx.address, ether('10000'), { from: alice }); + await piMdx.deposit(ether('10000'), { from: alice }); + + await myRouter.poke(false); + + assert.equal(await mdx.balanceOf(piMdx.address), ether(2000)); + assert.equal(await mdx.balanceOf(boardRoomMDX.address), ether(526400)); + assert.equal((await boardRoomMDX.userInfo(0, piMdx.address)).amount, ether(8000)); + }); + + describe('stake()', () => { + it('should allow the owner staking any amount of reserve tokens', async () => { + const res = await myRouter.stake(ether(2000), { from: piGov }); + expectEvent(res, 'Stake', { + sender: piGov, + amount: ether(2000), + }); + assert.equal(await mdx.balanceOf(piMdx.address), ether(0)); + assert.equal(await mdx.balanceOf(boardRoomMDX.address), ether(528388)); + const userInfo = await boardRoomMDX.userInfo(0, piMdx.address); + assert.equal(userInfo.amount, ether(10000)); + }); + + it('should deny non-owner staking any amount of reserve tokens', async () => { + await expectRevert(myRouter.stake(ether(1), { from: alice }), 'Ownable: caller is not the owner'); + }); + }); + + describe('redeem()', () => { + it('should allow the owner redeeming any amount of reserve tokens', async () => { + const res = await myRouter.redeem(ether(3000), { from: piGov }); + expectEvent(res, 'Redeem', { + sender: piGov, + amount: ether(3000), + }); + assert.equal(await mdx.balanceOf(piMdx.address), ether(5000)); + const userInfo = await boardRoomMDX.userInfo(0, piMdx.address); + assert.equal(userInfo.amount, ether(5000)); + }); + + it('should deny non-owner staking any amount of reserve tokens', async () => { + await expectRevert(myRouter.redeem(ether(1), { from: alice }), 'Ownable: caller is not the owner'); + }); + }); + }); + + describe('setRewardPools()', () => { + it('should allow the owner setting a new reward pool', async () => { + const res = await myRouter.setRewardPools([alice, bob], { from: piGov }); + expectEvent(res, 'SetRewardPools', { + len: '2', + rewardPools: [alice, bob], + }); + }); + + it('should deny setting an empty reward pool', async () => { + await expectRevert(myRouter.setRewardPools([], { from: piGov }), 'AT_LEAST_ONE_EXPECTED'); + }); + + it('should deny non-owner setting a new reward pool', async () => { + await expectRevert(myRouter.setRewardPools([alice, bob], { from: alice }), 'Ownable: caller is not the owner'); + }); + }); + + describe('setPvpFee()', () => { + it('should allow the owner setting a new pvpFee', async () => { + const res = await myRouter.setPvpFee(ether('0.1'), { from: piGov }); + expectEvent(res, 'SetPvpFee', { + pvpFee: ether('0.1'), + }); + }); + + it('should deny setting a fee greater or equal 100%', async () => { + await expectRevert(myRouter.setPvpFee(ether('1'), { from: piGov }), 'PVP_FEE_OVER_THE_LIMIT'); + }); + + it('should deny non-owner setting a new pvpFee', async () => { + await expectRevert(myRouter.setPvpFee(ether('0'), { from: alice }), 'Ownable: caller is not the owner'); + }); + }); + }); + + describe('reserve management', () => { + beforeEach(async () => { + // alice + await mdx.transfer(alice, ether('20000')); + await mdx.approve(piMdx.address, ether('10000'), { from: alice }); + await piMdx.deposit(ether('10000'), { from: alice }); + + // bob + await mdx.transfer(bob, ether('42000')); + await mdx.approve(boardRoomMDX.address, ether('42000'), { from: bob }); + + await boardRoomMDX.deposit(0, ether('42000'), { from: bob }); + + await myRouter.poke(false); + + assert.equal(await mdx.balanceOf(boardRoomMDX.address), ether(518400 + 50000)); + assert.equal(await mdx.balanceOf(piMdx.address), ether(2000)); + }); + + it('should increase reserve on deposit', async () => { + assert.equal(await piMdx.balanceOf(alice), ether(10000)); + await mdx.approve(piMdx.address, ether(1000), { from: alice }); + await piMdx.deposit(ether(1000), { from: alice }); + await myRouter.poke(false); + + assert.equal(await piMdx.balanceOf(alice), ether(11000)); + assert.equal(await mdx.balanceOf(boardRoomMDX.address), ether('569194.240000000000000000')); + assert.equal(await mdx.balanceOf(piMdx.address), ether(2200)); + assert.equal(await myRouter.getUnderlyingStaked(), ether(8800)); + assert.equal((await boardRoomMDX.userInfo(0, piMdx.address)).amount, ether(8800)); + }); + + it('should decrease reserve on withdrawal', async () => { + assert.equal(await piMdx.balanceOf(alice), ether(10000)); + + await piMdx.withdraw(ether(1000), { from: alice }); + await myRouter.poke(false); + + assert.equal(await piMdx.balanceOf(alice), ether(9000)); + assert.equal(await mdx.balanceOf(boardRoomMDX.address), ether('567596.160000000000000000')); + assert.equal(await mdx.balanceOf(piMdx.address), ether(1800)); + assert.equal(await myRouter.getUnderlyingStaked(), ether(7200)); + assert.equal((await boardRoomMDX.userInfo(0, piMdx.address)).amount, ether(7200)); + }); + + it('should ignore rebalancing if the staking address is 0', async () => { + await myRouter.redeem(ether(8000), { from: piGov }); + await myRouter.setVotingAndStaking(boardRoomMDX.address, constants.ZERO_ADDRESS, { from: piGov }); + + assert.equal(await mdx.balanceOf(boardRoomMDX.address), ether('560398.080000000000000000')); + assert.equal(await mdx.balanceOf(piMdx.address), ether(10000)); + assert.equal(await piMdx.balanceOf(alice), ether(10000)); + assert.equal(await piMdx.totalSupply(), ether(10000)); + await piMdx.withdraw(ether(1000), { from: alice }); + await expectRevert(myRouter.poke(false), 'STAKING_IS_NULL'); + }); + + describe('when interval enabled', () => { + beforeEach(async () => { + await myRouter.setReserveConfig(ether('0.2'), time.duration.hours(1), { from: piGov }); + await poke.setMinMaxReportIntervals(time.duration.hours(1), time.duration.hours(2), { from: piGov }); + }); + + it('should DO rebalance by pokeFromReporter if the rebalancing interval has passed', async () => { + await time.increase(time.duration.minutes(61)); + + await mdx.approve(piMdx.address, ether(1000), { from: alice }); + await piMdx.deposit(ether(1000), { from: alice }); + await expectRevert(myRouter.pokeFromSlasher(0, false, '0x'), 'MAX_INTERVAL_NOT_REACHED'); + }); + + it('should DO rebalance by pokeFromSlasher if the rebalancing interval has passed', async () => { + await time.increase(time.duration.minutes(121)); + + await mdx.approve(piMdx.address, ether(1000), { from: alice }); + await piMdx.deposit(ether(1000), { from: alice }); + await myRouter.pokeFromSlasher(0, false, '0x'); + + assert.equal(await mdx.balanceOf(boardRoomMDX.address), ether('569188.480000000000000000')); + assert.equal((await boardRoomMDX.userInfo(0, piMdx.address)).amount, ether(8800)); + assert.equal(await mdx.balanceOf(piMdx.address), ether(2200)); + }); + + it('should DO rebalance on withdrawal if the rebalancing interval has passed', async () => { + await time.increase(time.duration.minutes(61)); + + await piMdx.withdraw(ether(1000), { from: alice }); + await myRouter.poke(false); + + assert.equal(await mdx.balanceOf(boardRoomMDX.address), ether('567590.400000000000000000')); + assert.equal((await boardRoomMDX.userInfo(0, piMdx.address)).amount, ether(7200)); + assert.equal(await mdx.balanceOf(piMdx.address), ether(1800)); + }); + + it('should NOT rebalance by pokeFromReporter if the rebalancing interval has passed', async () => { + await time.increase(time.duration.minutes(50)); + + await mdx.approve(piMdx.address, ether(1000), { from: alice }); + await piMdx.deposit(ether(1000), { from: alice }); + await expectRevert(myRouter.pokeFromReporter(0, false, '0x'), 'MIN_INTERVAL_NOT_REACHED'); + await expectRevert(myRouter.pokeFromSlasher(0, false, '0x'), 'MAX_INTERVAL_NOT_REACHED'); + }); + + it('should NOT rebalance by pokeFromSlasher if the rebalancing interval has passed', async () => { + await time.increase(time.duration.minutes(70)); + + await mdx.approve(piMdx.address, ether(1000), { from: alice }); + await piMdx.deposit(ether(1000), { from: alice }); + await expectRevert(myRouter.pokeFromSlasher(0, false, '0x'), 'MAX_INTERVAL_NOT_REACHED'); + }); + }); + + describe('on poke', async () => { + it('should do nothing when nothing has changed', async () => { + await myRouter.poke(false, { from: bob }); + + assert.equal(await mdx.balanceOf(boardRoomMDX.address), ether(568400)); + assert.equal((await boardRoomMDX.userInfo(0, piMdx.address)).amount, ether(8000)); + assert.equal(await mdx.balanceOf(piMdx.address), ether(2000)); + }); + + it('should increase reserve if required', async () => { + await mdx.transfer(piMdx.address, ether(1000), { from: alice }); + + assert.equal(await mdx.balanceOf(boardRoomMDX.address), ether(568400)); + assert.equal((await boardRoomMDX.userInfo(0, piMdx.address)).amount, ether(8000)); + assert.equal(await mdx.balanceOf(piMdx.address), ether(3000)); + + await myRouter.poke(false, { from: bob }); + + assert.equal(await mdx.balanceOf(boardRoomMDX.address), ether('569196.160000000000000000')); + assert.equal((await boardRoomMDX.userInfo(0, piMdx.address)).amount, ether(8800)); + assert.equal(await mdx.balanceOf(piMdx.address), ether(2200)); + }); + }); + + it('should stake all the underlying tokens with 0 RR', async () => { + await myRouter.setReserveConfig(ether(0), 0, { from: piGov }); + + await myRouter.poke(false, { from: bob }); + assert.equal(await mdx.balanceOf(boardRoomMDX.address), ether('570396.160000000000000000')); + assert.equal(await mdx.balanceOf(piMdx.address), ether(0)); + }); + + it('should keep all the underlying tokens on piToken with 1 RR', async () => { + await myRouter.setReserveConfig(ether(1), 0, { from: piGov }); + + await myRouter.poke(false, { from: bob }); + assert.equal(await mdx.balanceOf(boardRoomMDX.address), ether('560396.160000000000000000')); + assert.equal(await mdx.balanceOf(piMdx.address), ether(10000)); + }); + }); + + describe('reward distribution', async () => { + let poolA, poolB, poolC, poolD; + + beforeEach(async function() { + poolA = await MockGulpingBPool.new(); + poolB = await MockGulpingBPool.new(); + poolC = await MockGulpingBPool.new(); + poolD = await MockGulpingBPool.new(); + await myRouter.setRewardPools([poolA.address, poolB.address, poolC.address], { from: piGov }); + + await poolRestrictions.setVotingAllowedForSenders(boardRoomMDX.address, [alice], [true]); + + // await bake.transfer(syrupPool.address, ether(12000)); + await mdx.transfer(alice, ether('10000')); + await mdx.approve(piMdx.address, ether('10000'), { from: alice }); + await piMdx.deposit(ether('10000'), { from: alice }); + + await myRouter.poke(false); + + assert.equal(await piMdx.totalSupply(), ether('10000')); + assert.equal(await piMdx.balanceOf(alice), ether('10000')); + + await piMdx.transfer(poolA.address, 10, { from: alice }); + await piMdx.transfer(poolB.address, 20, { from: alice }); + }); + + it('should allow distribute the accrued rewards', async () => { + await mdx.transfer(boardRoomMDX.address, ether(2000)); + + assert.equal(await mdx.balanceOf(piMdx.address), ether(2000)); + assert.equal(await myRouter.getUnderlyingStaked(), ether(8000)); + assert.equal(await myRouter.getPendingRewards(), ether(36)); + + let res = await myRouter.poke(true, { from: bob }); + + expectEvent(res, 'DistributeRewards', { + sender: bob, + tokenReward: ether(48), + pvpReward: ether('7.2'), + poolRewardsUnderlying: ether('40.8'), + poolRewardsPi: ether('40.8'), + pools: [poolA.address, poolB.address, poolC.address], + }); + + assert.equal(await mdx.balanceOf(piMdx.address), ether('2040.8')); + assert.equal(await mdx.balanceOf(myRouter.address), '0'); + + assert.isTrue(parseInt(res.logs[3].args.poolRewardsUnderlying) > 1); + assert.isTrue(parseInt(res.logs[3].args.poolRewardsPi.length) > 1); + + await expectEvent.inTransaction(res.tx, poolA, 'Gulp'); + await expectEvent.inTransaction(res.tx, poolB, 'Gulp'); + await expectEvent.notEmitted.inTransaction(res.tx, poolC, 'Gulp'); + await expectEvent.notEmitted.inTransaction(res.tx, poolD, 'Gulp'); + + assert.equal(res.logs.length, 4); + assert.equal(res.logs[1].args.pool, poolA.address); + assert.equal(res.logs[1].args.amount, ether('13.6')); + assert.equal(res.logs[2].args.pool, poolB.address); + assert.equal(res.logs[2].args.amount, ether('27.2')); + + assert.equal(await piMdx.balanceOf(poolA.address), ether('13.600000000000000010')); + assert.equal(await piMdx.balanceOf(poolB.address), ether('27.200000000000000020')); + assert.equal(await piMdx.balanceOf(poolC.address), '0'); + assert.equal(await piMdx.balanceOf(poolD.address), '0'); + + assert.equal(await mdx.balanceOf(myRouter.address), '0'); + assert.equal(await mdx.balanceOf(myRouter.address), '0'); + }); + + it('should revert poke if there is nothing released', async () => { + const dishonestChef = await MockGeneralMasterChef.new(mdx.address); + await myRouter.setReserveConfig(ether(1), 0, { from: piGov }); + await myRouter.poke(false); + await myRouter.setVotingAndStaking(constants.ZERO_ADDRESS, dishonestChef.address, { from: piGov }); + await myRouter.setReserveConfig(ether('0.2'), 0, { from: piGov }); + + // there are still some rewards from rebalancing pokes + await myRouter.poke(true, { from: alice }); + + // and now there are no rewards + await expectRevert(myRouter.poke(true, { from: alice }), 'NO_PENDING_REWARD'); + }); + + it('should revert distributing rewards when missing reward pools config', async () => { + poke = await MockPoke.new(true); + const router = await MDXChefPowerIndexRouter.new( + piMdx.address, + buildBasicRouterConfig( + poolRestrictions.address, + poke.address, + boardRoomMDX.address, + boardRoomMDX.address, + ether('0.2'), + ether('0.02'), + '0', + pvp, + ether('0.2'), + [], + ), + buildMasterChefRouterConfig(mdx.address, 0), + ) + await myRouter.migrateToNewRouter(piMdx.address, router.address, [], { from: piGov }); + await mdx.transfer(boardRoomMDX.address, ether(2000)); + await time.increase(1); + await expectRevert(router.poke(true, { from: bob }), 'MISSING_REWARD_POOLS'); + }); + }); +}); diff --git a/test/router/implementations/PancakeMasterChefRouter.unit.js b/test/router/implementations/PancakeMasterChefRouter.unit.js index a3918d31..49ae9826 100644 --- a/test/router/implementations/PancakeMasterChefRouter.unit.js +++ b/test/router/implementations/PancakeMasterChefRouter.unit.js @@ -26,7 +26,7 @@ describe('PancakeMasterChefRouter Tests', () => { [deployer, bob, alice, piGov, stub, pvp, pool1, pool2] = await web3.eth.getAccounts(); }); - let cake, syrupPool, masterChef, poolRestrictions, piMyToken, myRouter, poke; + let cake, syrupPool, masterChef, poolRestrictions, piCake, myRouter, poke; beforeEach(async function() { // bsc: 0x0e09fabb73bd3ade0a17ecc321fd13a19e81ce82 @@ -43,11 +43,11 @@ describe('PancakeMasterChefRouter Tests', () => { ); poolRestrictions = await PoolRestrictions.new(); - piMyToken = await WrappedPiErc20.new(cake.address, stub, 'Wrapped My Staking Token', 'piMST'); + piCake = await WrappedPiErc20.new(cake.address, stub, 'Wrapped CAKE', 'piCAKE'); poke = await MockPoke.new(true); myRouter = await PancakeMasterChefIndexRouter.new( - piMyToken.address, + piCake.address, buildBasicRouterConfig( poolRestrictions.address, poke.address, @@ -64,7 +64,7 @@ describe('PancakeMasterChefRouter Tests', () => { ); await syrupPool.transferOwnership(masterChef.address); - await piMyToken.changeRouter(myRouter.address, { from: stub }); + await piCake.changeRouter(myRouter.address, { from: stub }); await masterChef.add(20306, cake.address, false); await myRouter.transferOwnership(piGov); @@ -79,14 +79,14 @@ describe('PancakeMasterChefRouter Tests', () => { describe('stake()/redeem()', () => { beforeEach(async () => { await cake.transfer(alice, ether('10000')); - await cake.approve(piMyToken.address, ether('10000'), { from: alice }); - await piMyToken.deposit(ether('10000'), { from: alice }); + await cake.approve(piCake.address, ether('10000'), { from: alice }); + await piCake.deposit(ether('10000'), { from: alice }); await myRouter.poke(false); - assert.equal(await cake.balanceOf(piMyToken.address), ether(2000)); + assert.equal(await cake.balanceOf(piCake.address), ether(2000)); assert.equal(await cake.balanceOf(masterChef.address), ether(8000)); - assert.equal((await masterChef.userInfo(0, piMyToken.address)).amount, ether(8000)); + assert.equal((await masterChef.userInfo(0, piCake.address)).amount, ether(8000)); }); describe('stake()', () => { @@ -96,9 +96,9 @@ describe('PancakeMasterChefRouter Tests', () => { sender: piGov, amount: ether(2000), }); - assert.equal(await cake.balanceOf(piMyToken.address), ether(0)); + assert.equal(await cake.balanceOf(piCake.address), ether(0)); assert.equal(await cake.balanceOf(masterChef.address), ether(10000)); - const userInfo = await masterChef.userInfo(0, piMyToken.address); + const userInfo = await masterChef.userInfo(0, piCake.address); assert.equal(userInfo.amount, ether(10000)); }); @@ -114,8 +114,8 @@ describe('PancakeMasterChefRouter Tests', () => { sender: piGov, amount: ether(3000), }); - assert.equal(await cake.balanceOf(piMyToken.address), ether(5000)); - const userInfo = await masterChef.userInfo(0, piMyToken.address); + assert.equal(await cake.balanceOf(piCake.address), ether(5000)); + const userInfo = await masterChef.userInfo(0, piCake.address); assert.equal(userInfo.amount, ether(5000)); }); @@ -165,8 +165,8 @@ describe('PancakeMasterChefRouter Tests', () => { beforeEach(async () => { // alice await cake.transfer(alice, ether('20000')); - await cake.approve(piMyToken.address, ether('10000'), { from: alice }); - await piMyToken.deposit(ether('10000'), { from: alice }); + await cake.approve(piCake.address, ether('10000'), { from: alice }); + await piCake.deposit(ether('10000'), { from: alice }); // bob await cake.transfer(bob, ether('42000')); @@ -176,33 +176,33 @@ describe('PancakeMasterChefRouter Tests', () => { await myRouter.poke(false); assert.equal(await cake.balanceOf(masterChef.address), ether(50000)); - assert.equal(await cake.balanceOf(piMyToken.address), ether(2000)); + assert.equal(await cake.balanceOf(piCake.address), ether(2000)); }); it('should increase reserve on deposit', async () => { - assert.equal(await piMyToken.balanceOf(alice), ether(10000)); - await cake.approve(piMyToken.address, ether(1000), { from: alice }); - await piMyToken.deposit(ether(1000), { from: alice }); + assert.equal(await piCake.balanceOf(alice), ether(10000)); + await cake.approve(piCake.address, ether(1000), { from: alice }); + await piCake.deposit(ether(1000), { from: alice }); await myRouter.poke(false); - assert.equal(await piMyToken.balanceOf(alice), ether(11000)); + assert.equal(await piCake.balanceOf(alice), ether(11000)); assert.equal(await cake.balanceOf(masterChef.address), ether(50800)); - assert.equal(await cake.balanceOf(piMyToken.address), ether(2200)); + assert.equal(await cake.balanceOf(piCake.address), ether(2200)); assert.equal(await myRouter.getUnderlyingStaked(), ether(8800)); - assert.equal((await masterChef.userInfo(0, piMyToken.address)).amount, ether(8800)); + assert.equal((await masterChef.userInfo(0, piCake.address)).amount, ether(8800)); }); it('should decrease reserve on withdrawal', async () => { - assert.equal(await piMyToken.balanceOf(alice), ether(10000)); + assert.equal(await piCake.balanceOf(alice), ether(10000)); - await piMyToken.withdraw(ether(1000), { from: alice }); + await piCake.withdraw(ether(1000), { from: alice }); await myRouter.poke(false); - assert.equal(await piMyToken.balanceOf(alice), ether(9000)); + assert.equal(await piCake.balanceOf(alice), ether(9000)); assert.equal(await cake.balanceOf(masterChef.address), ether(49200)); - assert.equal(await cake.balanceOf(piMyToken.address), ether(1800)); + assert.equal(await cake.balanceOf(piCake.address), ether(1800)); assert.equal(await myRouter.getUnderlyingStaked(), ether(7200)); - assert.equal((await masterChef.userInfo(0, piMyToken.address)).amount, ether(7200)); + assert.equal((await masterChef.userInfo(0, piCake.address)).amount, ether(7200)); }); it('should ignore rebalancing if the staking address is 0', async () => { @@ -210,10 +210,10 @@ describe('PancakeMasterChefRouter Tests', () => { await myRouter.setVotingAndStaking(masterChef.address, constants.ZERO_ADDRESS, { from: piGov }); assert.equal(await cake.balanceOf(masterChef.address), ether(42000)); - assert.equal(await cake.balanceOf(piMyToken.address), ether(10000)); - assert.equal(await piMyToken.balanceOf(alice), ether(10000)); - assert.equal(await piMyToken.totalSupply(), ether(10000)); - await piMyToken.withdraw(ether(1000), { from: alice }); + assert.equal(await cake.balanceOf(piCake.address), ether(10000)); + assert.equal(await piCake.balanceOf(alice), ether(10000)); + assert.equal(await piCake.totalSupply(), ether(10000)); + await piCake.withdraw(ether(1000), { from: alice }); await expectRevert(myRouter.poke(false), 'STAKING_IS_NULL'); }); @@ -226,39 +226,39 @@ describe('PancakeMasterChefRouter Tests', () => { it('should DO rebalance by pokeFromReporter if the rebalancing interval has passed', async () => { await time.increase(time.duration.minutes(61)); - await cake.approve(piMyToken.address, ether(1000), { from: alice }); - await piMyToken.deposit(ether(1000), { from: alice }); + await cake.approve(piCake.address, ether(1000), { from: alice }); + await piCake.deposit(ether(1000), { from: alice }); await expectRevert(myRouter.pokeFromSlasher(0, false, '0x'), 'MAX_INTERVAL_NOT_REACHED'); }); it('should DO rebalance by pokeFromSlasher if the rebalancing interval has passed', async () => { await time.increase(time.duration.minutes(121)); - await cake.approve(piMyToken.address, ether(1000), { from: alice }); - await piMyToken.deposit(ether(1000), { from: alice }); + await cake.approve(piCake.address, ether(1000), { from: alice }); + await piCake.deposit(ether(1000), { from: alice }); await myRouter.pokeFromSlasher(0, false, '0x'); assert.equal(await cake.balanceOf(masterChef.address), ether(50800)); - assert.equal((await masterChef.userInfo(0, piMyToken.address)).amount, ether(8800)); - assert.equal(await cake.balanceOf(piMyToken.address), ether(2200)); + assert.equal((await masterChef.userInfo(0, piCake.address)).amount, ether(8800)); + assert.equal(await cake.balanceOf(piCake.address), ether(2200)); }); it('should DO rebalance on withdrawal if the rebalancing interval has passed', async () => { await time.increase(time.duration.minutes(61)); - await piMyToken.withdraw(ether(1000), { from: alice }); + await piCake.withdraw(ether(1000), { from: alice }); await myRouter.poke(false); assert.equal(await cake.balanceOf(masterChef.address), ether(49200)); - assert.equal((await masterChef.userInfo(0, piMyToken.address)).amount, ether(7200)); - assert.equal(await cake.balanceOf(piMyToken.address), ether(1800)); + assert.equal((await masterChef.userInfo(0, piCake.address)).amount, ether(7200)); + assert.equal(await cake.balanceOf(piCake.address), ether(1800)); }); it('should NOT rebalance by pokeFromReporter if the rebalancing interval has passed', async () => { await time.increase(time.duration.minutes(50)); - await cake.approve(piMyToken.address, ether(1000), { from: alice }); - await piMyToken.deposit(ether(1000), { from: alice }); + await cake.approve(piCake.address, ether(1000), { from: alice }); + await piCake.deposit(ether(1000), { from: alice }); await expectRevert(myRouter.pokeFromReporter(0, false, '0x'), 'MIN_INTERVAL_NOT_REACHED'); await expectRevert(myRouter.pokeFromSlasher(0, false, '0x'), 'MAX_INTERVAL_NOT_REACHED'); }); @@ -266,8 +266,8 @@ describe('PancakeMasterChefRouter Tests', () => { it('should NOT rebalance by pokeFromSlasher if the rebalancing interval has passed', async () => { await time.increase(time.duration.minutes(70)); - await cake.approve(piMyToken.address, ether(1000), { from: alice }); - await piMyToken.deposit(ether(1000), { from: alice }); + await cake.approve(piCake.address, ether(1000), { from: alice }); + await piCake.deposit(ether(1000), { from: alice }); await expectRevert(myRouter.pokeFromSlasher(0, false, '0x'), 'MAX_INTERVAL_NOT_REACHED'); }); }); @@ -277,22 +277,22 @@ describe('PancakeMasterChefRouter Tests', () => { await myRouter.poke(false, { from: bob }); assert.equal(await cake.balanceOf(masterChef.address), ether(50000)); - assert.equal((await masterChef.userInfo(0, piMyToken.address)).amount, ether(8000)); - assert.equal(await cake.balanceOf(piMyToken.address), ether(2000)); + assert.equal((await masterChef.userInfo(0, piCake.address)).amount, ether(8000)); + assert.equal(await cake.balanceOf(piCake.address), ether(2000)); }); it('should increase reserve if required', async () => { - await cake.transfer(piMyToken.address, ether(1000), { from: alice }); + await cake.transfer(piCake.address, ether(1000), { from: alice }); assert.equal(await cake.balanceOf(masterChef.address), ether(50000)); - assert.equal((await masterChef.userInfo(0, piMyToken.address)).amount, ether(8000)); - assert.equal(await cake.balanceOf(piMyToken.address), ether(3000)); + assert.equal((await masterChef.userInfo(0, piCake.address)).amount, ether(8000)); + assert.equal(await cake.balanceOf(piCake.address), ether(3000)); await myRouter.poke(false, { from: bob }); assert.equal(await cake.balanceOf(masterChef.address), ether(50800)); - assert.equal((await masterChef.userInfo(0, piMyToken.address)).amount, ether(8800)); - assert.equal(await cake.balanceOf(piMyToken.address), ether(2200)); + assert.equal((await masterChef.userInfo(0, piCake.address)).amount, ether(8800)); + assert.equal(await cake.balanceOf(piCake.address), ether(2200)); }); }); @@ -301,7 +301,7 @@ describe('PancakeMasterChefRouter Tests', () => { await myRouter.poke(false, { from: bob }); assert.equal(await cake.balanceOf(masterChef.address), ether(52000)); - assert.equal(await cake.balanceOf(piMyToken.address), ether(0)); + assert.equal(await cake.balanceOf(piCake.address), ether(0)); }); it('should keep all the underlying tokens on piToken with 1 RR', async () => { @@ -309,7 +309,7 @@ describe('PancakeMasterChefRouter Tests', () => { await myRouter.poke(false, { from: bob }); assert.equal(await cake.balanceOf(masterChef.address), ether(42000)); - assert.equal(await cake.balanceOf(piMyToken.address), ether(10000)); + assert.equal(await cake.balanceOf(piCake.address), ether(10000)); }); }); @@ -327,16 +327,16 @@ describe('PancakeMasterChefRouter Tests', () => { await cake.transfer(syrupPool.address, ether(12000)); await cake.transfer(alice, ether('10000')); - await cake.approve(piMyToken.address, ether('10000'), { from: alice }); - await piMyToken.deposit(ether('10000'), { from: alice }); + await cake.approve(piCake.address, ether('10000'), { from: alice }); + await piCake.deposit(ether('10000'), { from: alice }); await myRouter.poke(false); - assert.equal(await piMyToken.totalSupply(), ether('10000')); - assert.equal(await piMyToken.balanceOf(alice), ether('10000')); + assert.equal(await piCake.totalSupply(), ether('10000')); + assert.equal(await piCake.balanceOf(alice), ether('10000')); - await piMyToken.transfer(poolA.address, 10, { from: alice }); - await piMyToken.transfer(poolB.address, 20, { from: alice }); + await piCake.transfer(poolA.address, 10, { from: alice }); + await piCake.transfer(poolB.address, 20, { from: alice }); }); it('should allow withdrawing rewards from the masterChef', async () => { @@ -345,7 +345,7 @@ describe('PancakeMasterChefRouter Tests', () => { await masterChef.massUpdatePools(); await time.increase(time.duration.days(8)); await masterChef.massUpdatePools(); - assert.equal(await cake.balanceOf(piMyToken.address), ether(2000)); + assert.equal(await cake.balanceOf(piCake.address), ether(2000)); assert.equal(await myRouter.getUnderlyingStaked(), ether(8000)); assert.equal(await myRouter.getPendingRewards(), ether('47.996454152000000000')); @@ -360,7 +360,7 @@ describe('PancakeMasterChefRouter Tests', () => { pools: [poolA.address, poolB.address, poolC.address], }); - assert.equal(await cake.balanceOf(piMyToken.address), ether('2047.596483699600000000')); + assert.equal(await cake.balanceOf(piCake.address), ether('2047.596483699600000000')); assert.equal(await cake.balanceOf(myRouter.address), '0'); assert.isTrue(parseInt(res.logs[3].args.poolRewardsUnderlying) > 1); @@ -377,10 +377,10 @@ describe('PancakeMasterChefRouter Tests', () => { assert.equal(res.logs[2].args.pool, poolB.address); assert.equal(res.logs[2].args.amount, '31730989133066666666'); - assert.equal(await piMyToken.balanceOf(poolA.address), 15865494566533333343); - assert.equal(await piMyToken.balanceOf(poolB.address), 31730989133066666686); - assert.equal(await piMyToken.balanceOf(poolC.address), '0'); - assert.equal(await piMyToken.balanceOf(poolD.address), '0'); + assert.equal(await piCake.balanceOf(poolA.address), 15865494566533333343); + assert.equal(await piCake.balanceOf(poolB.address), 31730989133066666686); + assert.equal(await piCake.balanceOf(poolC.address), '0'); + assert.equal(await piCake.balanceOf(poolD.address), '0'); assert.equal(await cake.balanceOf(myRouter.address), '0'); assert.equal(await cake.balanceOf(myRouter.address), '0'); @@ -399,7 +399,7 @@ describe('PancakeMasterChefRouter Tests', () => { it('should revert distributing rewards when missing reward pools config', async () => { poke = await MockPoke.new(true); const router = await PancakeMasterChefIndexRouter.new( - piMyToken.address, + piCake.address, buildBasicRouterConfig( poolRestrictions.address, poke.address, @@ -414,7 +414,7 @@ describe('PancakeMasterChefRouter Tests', () => { ), buildPancakeMasterChefRouterConfig(cake.address), ); - await myRouter.migrateToNewRouter(piMyToken.address, router.address, [], { from: piGov }); + await myRouter.migrateToNewRouter(piCake.address, router.address, [], { from: piGov }); await cake.transfer(masterChef.address, ether(2000)); await time.increase(1); await expectRevert(router.poke(true, { from: bob }), 'MISSING_REWARD_POOLS'); From 9bfd8214f1fd996a3792e4f366f1e895331a0905 Mon Sep 17 00:00:00 2001 From: Poli Paul Date: Mon, 2 Aug 2021 16:58:02 +0200 Subject: [PATCH 07/33] Add BSC/AutoFarm Router --- assets/bsc/AutoFarmV2_CrossChain.json | 149 +++++ assets/bsc/StratX2_AUTO.json | 530 +++++++++++++++ contracts/interfaces/IAutoFarm.sol | 24 + contracts/interfaces/IAutoFarmStrategy.sol | 19 + .../implementations/AutoPowerIndexRouter.sol | 211 ++++++ contracts/test/bsc/MockAutoMasterChef.sol | 43 ++ contracts/test/bsc/MockPancakeRouter.sol | 13 + .../test/sushi/MockPancakeMasterChef.sol | 10 +- test/helpers/builders.js | 7 + .../router/implementations/AutoRouter.unit.js | 612 ++++++++++++++++++ 10 files changed, 1617 insertions(+), 1 deletion(-) create mode 100644 assets/bsc/AutoFarmV2_CrossChain.json create mode 100644 assets/bsc/StratX2_AUTO.json create mode 100644 contracts/interfaces/IAutoFarm.sol create mode 100644 contracts/interfaces/IAutoFarmStrategy.sol create mode 100644 contracts/powerindex-router/implementations/AutoPowerIndexRouter.sol create mode 100644 contracts/test/bsc/MockAutoMasterChef.sol create mode 100644 contracts/test/bsc/MockPancakeRouter.sol create mode 100644 test/router/implementations/AutoRouter.unit.js diff --git a/assets/bsc/AutoFarmV2_CrossChain.json b/assets/bsc/AutoFarmV2_CrossChain.json new file mode 100644 index 00000000..3e1466ee --- /dev/null +++ b/assets/bsc/AutoFarmV2_CrossChain.json @@ -0,0 +1,149 @@ +{ + "bytecode": "6080604052600160045534801561001557600080fd5b506000610020610073565b600080546001600160a01b0319166001600160a01b0383169081178255604051929350917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a35060018055610077565b3390565b6115d8806100866000396000f3fe608060405234801561001057600080fd5b50600436106100b45760003560e01c80637b84daec116100715780637b84daec146101a75780638da5cb5b146101d357806393f1a40b146101f7578063c6d758cb14610223578063e2bbb1581461024f578063f2fde38b14610272576100b4565b8063081e3eda146100b95780631526fe27146100d357806317caf6f114610134578063441a3e701461013c5780635f70edcf14610161578063715018a61461019f575b600080fd5b6100c1610298565b60408051918252519081900360200190f35b6100f0600480360360208110156100e957600080fd5b503561029e565b60405180866001600160a01b03168152602001858152602001848152602001838152602001826001600160a01b031681526020019550505050505060405180910390f35b6100c16102e9565b61015f6004803603604081101561015257600080fd5b50803590602001356102ef565b005b61015f6004803603608081101561017757600080fd5b508035906001600160a01b036020820135811691604081013515159160609091013516610721565b61015f610903565b6100c1600480360360408110156101bd57600080fd5b50803590602001356001600160a01b03166109a5565b6101db610b22565b604080516001600160a01b039092168252519081900360200190f35b6100c16004803603604081101561020d57600080fd5b50803590602001356001600160a01b0316610b31565b61015f6004803603604081101561023957600080fd5b506001600160a01b038135169060200135610b4e565b61015f6004803603604081101561026557600080fd5b5080359060200135610bbe565b61015f6004803603602081101561028857600080fd5b50356001600160a01b0316610d83565b60025490565b600281815481106102ab57fe5b6000918252602090912060059091020180546001820154600283015460038401546004909401546001600160a01b0393841695509193909290911685565b60045481565b60026001541415610347576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b600260018190555060006002838154811061035e57fe5b60009182526020808320868452600382526040808520338652909252908320600280546005909402909201945092918690811061039757fe5b906000526020600020906005020160040160009054906101000a90046001600160a01b03166001600160a01b03166342da4eb36040518163ffffffff1660e01b815260040160206040518083038186803b1580156103f457600080fd5b505afa158015610408573d6000803e3d6000fd5b505050506040513d602081101561041e57600080fd5b5051600280549192506000918790811061043457fe5b906000526020600020906005020160040160009054906101000a90046001600160a01b03166001600160a01b03166344a3955e6040518163ffffffff1660e01b815260040160206040518083038186803b15801561049157600080fd5b505afa1580156104a5573d6000803e3d6000fd5b505050506040513d60208110156104bb57600080fd5b50518354909150610506576040805162461bcd60e51b815260206004820152601060248201526f0757365722e73686172657320697320360841b604482015290519081900360640190fd5b6000811161054e576040805162461bcd60e51b815260206004820152601060248201526f0736861726573546f74616c20697320360841b604482015290519081900360640190fd5b82546000906105699083906105639086610e7b565b90610edb565b905080861115610577578095505b85156106dd5760006002888154811061058c57fe5b6000918252602080832060046005909302018201546040805163f3fef3a360e01b81523394810194909452602484018c9052516001600160a01b039091169363f3fef3a3936044808201949392918390030190829087803b1580156105f057600080fd5b505af1158015610604573d6000803e3d6000fd5b505050506040513d602081101561061a57600080fd5b505185549091508111156106315760008555610640565b845461063d9082610f1d565b85555b8554604080516370a0823160e01b815230600482015290516000926001600160a01b0316916370a08231916024808301926020929190829003018186803b15801561068a57600080fd5b505afa15801561069e573d6000803e3d6000fd5b505050506040513d60208110156106b457600080fd5b50519050878110156106c4578097505b86546106da906001600160a01b0316338a610f5f565b50505b604080518781529051889133917ff279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b5689181900360200190a35050600180555050505050565b610729610fb6565b6000546001600160a01b03908116911614610779576040805162461bcd60e51b81526020600482018190526024820152600080516020611559833981519152604482015290519081900360640190fd5b6004546107869085610fba565b6004556040805160a0810182526001600160a01b038086168083526020808401898152600085870181815260608088018381528a88166080808b018281526002805460018101825597529a5160059096027f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace81018054978c166001600160a01b031998891617905596517f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5acf88015593517f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ad087015590517f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ad186015597517f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ad2909401805494909716939092169290921790945585518a815291820192909252861515818601529182019290925291517f7ac3b3d636ea03a286c25edba9e75801c02c65437a5fc04d2160a9693f7d31b39281900390910190a150505050565b61090b610fb6565b6000546001600160a01b0390811691161461095b576040805162461bcd60e51b81526020600482018190526024820152600080516020611559833981519152604482015290519081900360640190fd5b600080546040516001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080546001600160a01b0319169055565b600080600284815481106109b557fe5b600091825260208083208784526003825260408085206001600160a01b03808a16875290845281862060046005909602909301858101548351632251caaf60e11b8152935191985093969593909116936344a3955e9383810193919291829003018186803b158015610a2657600080fd5b505afa158015610a3a573d6000803e3d6000fd5b505050506040513d6020811015610a5057600080fd5b50516002805491925060009188908110610a6657fe5b906000526020600020906005020160040160009054906101000a90046001600160a01b03166001600160a01b03166342da4eb36040518163ffffffff1660e01b815260040160206040518083038186803b158015610ac357600080fd5b505afa158015610ad7573d6000803e3d6000fd5b505050506040513d6020811015610aed57600080fd5b5051905081610b03576000945050505050610b1c565b8254610b159083906105639084610e7b565b9450505050505b92915050565b6000546001600160a01b031690565b600360209081526000928352604080842090915290825290205481565b610b56610fb6565b6000546001600160a01b03908116911614610ba6576040805162461bcd60e51b81526020600482018190526024820152600080516020611559833981519152604482015290519081900360640190fd5b610bba6001600160a01b0383163383610f5f565b5050565b60026001541415610c16576040805162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b6002600181905550600060028381548110610c2d57fe5b600091825260208083208684526003825260408085203386529092529220600590910290910191508215610d42578154610c72906001600160a01b0316333086611014565b60048201548254610c90916001600160a01b03918216911685611074565b600060028581548110610c9f57fe5b600091825260208083206004600590930201820154604080516311f9fbc960e21b8152339481019490945260248401899052516001600160a01b03909116936347e7ef24936044808201949392918390030190829087803b158015610d0357600080fd5b505af1158015610d17573d6000803e3d6000fd5b505050506040513d6020811015610d2d57600080fd5b50518254909150610d3e9082610fba565b8255505b604080518481529051859133917f90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a159181900360200190a35050600180555050565b610d8b610fb6565b6000546001600160a01b03908116911614610ddb576040805162461bcd60e51b81526020600482018190526024820152600080516020611559833981519152604482015290519081900360640190fd5b6001600160a01b038116610e205760405162461bcd60e51b81526004018080602001828103825260268152602001806114ec6026913960400191505060405180910390fd5b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b600082610e8a57506000610b1c565b82820282848281610e9757fe5b0414610ed45760405162461bcd60e51b81526004018080602001828103825260218152602001806115386021913960400191505060405180910390fd5b9392505050565b6000610ed483836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f00000000000081525061115f565b6000610ed483836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250611201565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052610fb190849061125b565b505050565b3390565b600082820183811015610ed4576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b604080516001600160a01b0380861660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b17905261106e90859061125b565b50505050565b600061110a82856001600160a01b031663dd62ed3e30876040518363ffffffff1660e01b815260040180836001600160a01b03168152602001826001600160a01b031681526020019250505060206040518083038186803b1580156110d857600080fd5b505afa1580156110ec573d6000803e3d6000fd5b505050506040513d602081101561110257600080fd5b505190610fba565b604080516001600160a01b038616602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b17905290915061106e90859061125b565b600081836111eb5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156111b0578181015183820152602001611198565b50505050905090810190601f1680156111dd5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5060008385816111f757fe5b0495945050505050565b600081848411156112535760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156111b0578181015183820152602001611198565b505050900390565b60606112b0826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661130c9092919063ffffffff16565b805190915015610fb1578080602001905160208110156112cf57600080fd5b5051610fb15760405162461bcd60e51b815260040180806020018281038252602a815260200180611579602a913960400191505060405180910390fd5b606061131b8484600085611323565b949350505050565b6060824710156113645760405162461bcd60e51b81526004018080602001828103825260268152602001806115126026913960400191505060405180910390fd5b61136d8561147f565b6113be576040805162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015290519081900360640190fd5b60006060866001600160a01b031685876040518082805190602001908083835b602083106113fd5780518252601f1990920191602091820191016113de565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d806000811461145f576040519150601f19603f3d011682016040523d82523d6000602084013e611464565b606091505b5091509150611474828286611485565b979650505050505050565b3b151590565b60608315611494575081610ed4565b8251156114a45782518084602001fd5b60405162461bcd60e51b81526020600482018181528451602484015284518593919283926044019190850190808383600083156111b057818101518382015260200161119856fe4f776e61626c653a206e6577206f776e657220697320746865207a65726f2061646472657373416464726573733a20696e73756666696369656e742062616c616e636520666f722063616c6c536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f774f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65725361666545524332303a204552433230206f7065726174696f6e20646964206e6f742073756363656564a2646970667358221220f450f9cad1dafc309e491bf63e2b1109c795b4d73ab3e5fc3eed13ea718959e764736f6c634300060c0033", + "abi": [ + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "uint256", "name": "_allocPoint", "type": "uint256" }, + { "indexed": false, "internalType": "contract IERC20", "name": "_want", "type": "address" }, + { "indexed": false, "internalType": "bool", "name": "_withUpdate", "type": "bool" }, + { "indexed": false, "internalType": "address", "name": "_strat", "type": "address" } + ], + "name": "Add", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "user", "type": "address" }, + { "indexed": true, "internalType": "uint256", "name": "pid", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "Deposit", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "previousOwner", "type": "address" }, + { "indexed": true, "internalType": "address", "name": "newOwner", "type": "address" } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "user", "type": "address" }, + { "indexed": true, "internalType": "uint256", "name": "pid", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "Withdraw", + "type": "event" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "_allocPoint", "type": "uint256" }, + { "internalType": "contract IERC20", "name": "_want", "type": "address" }, + { "internalType": "bool", "name": "_withUpdate", "type": "bool" }, + { "internalType": "address", "name": "_strat", "type": "address" } + ], + "name": "add", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "_pid", "type": "uint256" }, + { "internalType": "uint256", "name": "_wantAmt", "type": "uint256" } + ], + "name": "deposit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "_token", "type": "address" }, + { "internalType": "uint256", "name": "_amount", "type": "uint256" } + ], + "name": "inCaseTokensGetStuck", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "name": "poolInfo", + "outputs": [ + { "internalType": "contract IERC20", "name": "want", "type": "address" }, + { "internalType": "uint256", "name": "allocPoint", "type": "uint256" }, + { "internalType": "uint256", "name": "lastRewardBlock", "type": "uint256" }, + { "internalType": "uint256", "name": "accAUTOPerShare", "type": "uint256" }, + { "internalType": "address", "name": "strat", "type": "address" } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "poolLength", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { "inputs": [], "name": "renounceOwnership", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { "internalType": "uint256", "name": "_pid", "type": "uint256" }, + { "internalType": "address", "name": "_user", "type": "address" } + ], + "name": "stakedWantTokens", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalAllocPoint", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "newOwner", "type": "address" }], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "", "type": "uint256" }, + { "internalType": "address", "name": "", "type": "address" } + ], + "name": "userInfo", + "outputs": [{ "internalType": "uint256", "name": "shares", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "_pid", "type": "uint256" }, + { "internalType": "uint256", "name": "_wantAmt", "type": "uint256" } + ], + "name": "withdraw", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ] +} diff --git a/assets/bsc/StratX2_AUTO.json b/assets/bsc/StratX2_AUTO.json new file mode 100644 index 00000000..cb3ec7bd --- /dev/null +++ b/assets/bsc/StratX2_AUTO.json @@ -0,0 +1,530 @@ +{ + "bytecode": "6080604052600c805460ff60a01b1916600160a01b1790556000600d819055600e819055600f8190556010819055601155601280546001600160a01b03191661dead1790556127066014556127106015556103b660165562127500601f553480156200006a57600080fd5b5060405162003a2738038062003a2783398181016040526101e08110156200009157600080fd5b8101908080516040519392919084640100000000821115620000b257600080fd5b908301906020820185811115620000c857600080fd5b8251866020820283011164010000000082111715620000e657600080fd5b82525081516020918201928201910280838360005b8381101562000115578181015183820152602001620000fb565b505050509190910160408181526020840151908401516060850151608086015160a0909601805193989297919695509192909190846401000000008211156200015d57600080fd5b9083019060208201858111156200017357600080fd5b82518660208202830111640100000000821117156200019157600080fd5b82525081516020918201928201910280838360005b83811015620001c0578181015183820152602001620001a6565b5050505090500160405260200180516040519392919084640100000000821115620001ea57600080fd5b9083019060208201858111156200020057600080fd5b82518660208202830111640100000000821117156200021e57600080fd5b82525081516020918201928201910280838360005b838110156200024d57818101518382015260200162000233565b50505050905001604052602001805160405193929190846401000000008211156200027757600080fd5b9083019060208201858111156200028d57600080fd5b8251866020820283011164010000000082111715620002ab57600080fd5b82525081516020918201928201910280838360005b83811015620002da578181015183820152602001620002c0565b50505050905001604052602001805160405193929190846401000000008211156200030457600080fd5b9083019060208201858111156200031a57600080fd5b82518660208202830111640100000000821117156200033857600080fd5b82525081516020918201928201910280838360005b83811015620003675781810151838201526020016200034d565b50505050905001604052602001805160405193929190846401000000008211156200039157600080fd5b908301906020820185811115620003a757600080fd5b8251866020820283011164010000000082111715620003c557600080fd5b82525081516020918201928201910280838360005b83811015620003f4578181015183820152602001620003da565b505050509190910160409081526020830151908301516060840151608085015160a09095015192965090945092915060006200042f6200083e565b600080546001600160a01b0319166001600160a01b03831690811782556040519293509160008051602062003a07833981519152908290a350600180556002805460ff191690558e518f906000906200048457fe5b6020026020010151600960006101000a8154816001600160a01b0302191690836001600160a01b031602179055508e600181518110620004c057fe5b6020026020010151600c60006101000a8154816001600160a01b0302191690836001600160a01b031602179055508e600281518110620004fc57fe5b6020026020010151600a60006101000a8154816001600160a01b0302191690836001600160a01b031602179055508e6003815181106200053857fe5b6020026020010151600b60006101000a8154816001600160a01b0302191690836001600160a01b031602179055508e6004815181106200057457fe5b6020026020010151600460006101000a8154816001600160a01b0302191690836001600160a01b031602179055508e600581518110620005b057fe5b6020026020010151600560006101000a8154816001600160a01b0302191690836001600160a01b031602179055508e600681518110620005ec57fe5b6020026020010151600660006101000a8154816001600160a01b0302191690836001600160a01b031602179055508e6007815181106200062857fe5b6020026020010151600760006101000a8154816001600160a01b0302191690836001600160a01b031602179055508e6008815181106200066457fe5b6020026020010151600260046101000a8154816001600160a01b0302191690836001600160a01b031602179055508d6003819055508c600260016101000a81548160ff0219169083151502179055508b6002806101000a81548160ff0219169083151502179055508a600260036101000a81548160ff0219169083151502179055508e600981518110620006f457fe5b602090810291909101810151600880546001600160a01b0319166001600160a01b039092169190911790558a516200073391601791908d019062000940565b508851620007499060189060208c019062000940565b5087516200075f9060199060208b019062000940565b5086516200077590601a9060208a019062000940565b5085516200078b90601b90602089019062000940565b50846010819055508e600a81518110620007a157fe5b6020026020010151601360006101000a8154816001600160a01b0302191690836001600160a01b03160217905550836011819055508e600b81518110620007e457fe5b6020908102919091010151601280546001600160a01b0319166001600160a01b0392831617905560148490556015839055601e829055600a5462000829911662000842565b505050505050505050505050505050620009cb565b3390565b6200084c6200083e565b6000546001600160a01b03908116911614620008af576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6001600160a01b038116620008f65760405162461bcd60e51b8152600401808060200182810382526026815260200180620039e16026913960400191505060405180910390fd5b600080546040516001600160a01b038085169392169160008051602062003a0783398151915291a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b82805482825590600052602060002090810192821562000998579160200282015b828111156200099857825182546001600160a01b0319166001600160a01b0390911617825560209092019160019091019062000961565b50620009a6929150620009aa565b5090565b5b80821115620009a65780546001600160a01b0319168155600101620009ab565b61300680620009db6000396000f3fe6080604052600436106103c65760003560e01c80638456cb59116101f2578063c11c2e921161010d578063e7198474116100a0578063f2fde38b1161006f578063f2fde38b14610a6d578063f3fef3a314610aa0578063fa97484114610ad9578063ffbd3b1f14610aee576103cd565b8063e719847414610a2e578063e7a0367914610a43578063ee50dc34146104ea578063f106845414610a58576103cd565b8063d389800f116100dc578063d389800f146109da578063d5b09163146109ef578063d7cb416f14610a04578063e5dd455a14610a19576103cd565b8063c11c2e9214610968578063c302a4d014610806578063c8e3d18b1461097d578063cfad57a2146109a7576103cd565b80639a24664311610185578063b3545c0111610154578063b3545c01146108ff578063b74cd24214610914578063b77050e714610929578063c0973eed14610953576103cd565b80639a2466431461088d5780639d965ca3146108a25780639fc33a9f146108b7578063ad740f8c146108cc576103cd565b8063866b2018116101c1578063866b2018146108065780638906758d1461081b5780638da5cb5b1461084e57806396e9aff814610863576103cd565b80638456cb5914610785578063846d9e171461079a57806384fa32ac146107af57806385f02dd6146107f1576103cd565b806347e7ef24116102e257806367057b6c116102755780636c0b2d73116102445780636c0b2d7314610713578063715018a614610746578063783478ad1461075b5780637ff36fbe14610770576103cd565b806367057b6c146104ea57806367206d40146106a657806368f54162146106e9578063693a090b146106fe576103cd565b80635da79d63116102b15780635da79d631461060a5780635e5977621461063d57806362e582e71461066757806363fe3e3a14610691576103cd565b806347e7ef24146105a757806349d77f2b146105e05780634d9f7bb2146104ea5780635c975abb146105f5576103cd565b80632717eff31161035a5780633f4ba83a116103295780633f4ba83a1461055357806342da4eb31461056857806344a3955e1461057d57806346008a0714610592576103cd565b80632717eff3146104ea578063365b98b2146104ff578063366ba2461461052957806336e9332d1461053e576103cd565b80630fa4e01e116103965780630fa4e01e146104965780631334903f146104ab578063178a8d07146104c0578063256da24f146104d5576103cd565b80627a2ae3146103d2578063061c7d48146104185780630b6bb30b1461043f5780630daef3211461046d576103cd565b366103cd57005b600080fd5b3480156103de57600080fd5b506103fc600480360360208110156103f557600080fd5b5035610b03565b604080516001600160a01b039092168252519081900360200190f35b34801561042457600080fd5b5061042d610b2a565b60408051918252519081900360200190f35b34801561044b57600080fd5b5061046b6004803603602081101561046257600080fd5b50351515610b30565b005b34801561047957600080fd5b50610482610bcb565b604080519115158252519081900360200190f35b3480156104a257600080fd5b5061042d610bdb565b3480156104b757600080fd5b5061042d610be1565b3480156104cc57600080fd5b5061042d610be7565b3480156104e157600080fd5b5061042d610bed565b3480156104f657600080fd5b5061042d610bf3565b34801561050b57600080fd5b506103fc6004803603602081101561052257600080fd5b5035610bf9565b34801561053557600080fd5b506103fc610c06565b34801561054a57600080fd5b5061046b610c15565b34801561055f57600080fd5b5061046b610c6e565b34801561057457600080fd5b5061042d610cc0565b34801561058957600080fd5b5061042d610cc6565b34801561059e57600080fd5b506103fc610ccc565b3480156105b357600080fd5b5061042d600480360360408110156105ca57600080fd5b506001600160a01b038135169060200135610cdb565b3480156105ec57600080fd5b5061042d610f45565b34801561060157600080fd5b50610482610f4b565b34801561061657600080fd5b5061046b6004803603602081101561062d57600080fd5b50356001600160a01b0316610f54565b34801561064957600080fd5b5061046b6004803603602081101561066057600080fd5b5035610ff0565b34801561067357600080fd5b506103fc6004803603602081101561068a57600080fd5b50356110bc565b34801561069d57600080fd5b506103fc6110c9565b3480156106b257600080fd5b5061046b600480360360608110156106c957600080fd5b506001600160a01b038135811691602081013591604090910135166110d8565b3480156106f557600080fd5b5061042d6111cf565b34801561070a57600080fd5b506103fc6111d5565b34801561071f57600080fd5b5061042d6004803603602081101561073657600080fd5b50356001600160a01b03166111e4565b34801561075257600080fd5b5061046b6111f6565b34801561076757600080fd5b506103fc611298565b34801561077c57600080fd5b506103fc6112a7565b34801561079157600080fd5b5061046b6112b6565b3480156107a657600080fd5b50610482611306565b3480156107bb57600080fd5b5061046b600480360360a08110156107d257600080fd5b5080359060208101359060408101359060608101359060800135611314565b3480156107fd57600080fd5b5061042d611623565b34801561081257600080fd5b5061042d611629565b34801561082757600080fd5b5061046b6004803603602081101561083e57600080fd5b50356001600160a01b031661162f565b34801561085a57600080fd5b506103fc6116cb565b34801561086f57600080fd5b506103fc6004803603602081101561088657600080fd5b50356116da565b34801561089957600080fd5b506104826116e7565b3480156108ae57600080fd5b5061042d6116f6565b3480156108c357600080fd5b506103fc6116fc565b3480156108d857600080fd5b5061046b600480360360208110156108ef57600080fd5b50356001600160a01b0316611713565b34801561090b57600080fd5b5061042d6117af565b34801561092057600080fd5b5061042d6117b5565b34801561093557600080fd5b506103fc6004803603602081101561094c57600080fd5b50356117bb565b34801561095f57600080fd5b506103fc6117c8565b34801561097457600080fd5b5061046b6117d7565b34801561098957600080fd5b506103fc600480360360208110156109a057600080fd5b5035611b58565b3480156109b357600080fd5b5061046b600480360360208110156109ca57600080fd5b50356001600160a01b0316611b65565b3480156109e657600080fd5b5061046b611c01565b3480156109fb57600080fd5b5061046b611f19565b348015610a1057600080fd5b506103fc611f69565b348015610a2557600080fd5b50610482611f78565b348015610a3a57600080fd5b506103fc611f88565b348015610a4f57600080fd5b506103fc611f97565b348015610a6457600080fd5b5061042d611fa6565b348015610a7957600080fd5b5061046b60048036036020811015610a9057600080fd5b50356001600160a01b0316611fac565b348015610aac57600080fd5b5061042d60048036036040811015610ac357600080fd5b506001600160a01b0381351690602001356120a4565b348015610ae557600080fd5b506103fc61232f565b348015610afa57600080fd5b5061042d61233e565b601b8181548110610b1057fe5b6000918252602090912001546001600160a01b0316905081565b61012c81565b600c546001600160a01b03163314610b78576040805162461bcd60e51b8152602060048083019190915260248201526310b3b7bb60e11b604482015290519081900360640190fd5b600c8054821515600160a01b810260ff60a01b199092169190911790915560408051918252517f125177ac7b8930dac1e59c2b30b1b6b9191b30af40cf6bbb5d20fec4d44be60f9181900360200190a150565b600c54600160a01b900460ff1681565b600d5481565b60145481565b60115481565b601c5490565b61271081565b601c8181548110610b1057fe5b600b546001600160a01b031681565b60026001541415610c5b576040805162461bcd60e51b815260206004820152601f6024820152600080516020612ec4833981519152604482015290519081900360640190fd5b6002600155610c68610cbe565b60018055565b600c546001600160a01b03163314610cb6576040805162461bcd60e51b8152602060048083019190915260248201526310b3b7bb60e11b604482015290519081900360640190fd5b610cbe612344565b565b600e5481565b600f5481565b600c546001600160a01b031681565b6000610ce56123e2565b6000546001600160a01b03908116911614610d35576040805162461bcd60e51b81526020600482018190526024820152600080516020612f51833981519152604482015290519081900360640190fd5b60026001541415610d7b576040805162461bcd60e51b815260206004820152601f6024820152600080516020612ec4833981519152604482015290519081900360640190fd5b600260018190555460ff1615610dcb576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b6001600160a01b0383166000908152601d6020526040902054610e3457601c80546001810182556000919091527f0e4562a10381dec21b205ed72637e6b1b523bdd0e4d4d50af5cd23dd4500a2110180546001600160a01b0319166001600160a01b0385161790555b6001600160a01b038084166000908152601d60205260409020429055600454610e6091163330856123e6565b600e54829015801590610e7557506000600f54115b15610eb057610ead612710610ea7600e54610ea7601454610ea1600f548a61244690919063ffffffff16565b90612446565b906124a8565b90505b600f54610ebd90826124ea565b600f55600b54604080516370a0823160e01b815230600482015290516001600160a01b03909216916370a0823191602480820192602092909190829003018186803b158015610f0b57600080fd5b505afa158015610f1f573d6000803e3d6000fd5b505050506040513d6020811015610f3557600080fd5b5051600e55600180559392505050565b601e5481565b60025460ff1690565b600c546001600160a01b03163314610f9c576040805162461bcd60e51b8152602060048083019190915260248201526310b3b7bb60e11b604482015290519081900360640190fd5b600880546001600160a01b0383166001600160a01b0319909116811790915560408051918252517f384f1dcb79da4071839c471d7c81884a43fb946a527f3661fdee5904adc8f6579181900360200190a150565b600c546001600160a01b03163314611038576040805162461bcd60e51b8152602060048083019190915260248201526310b3b7bb60e11b604482015290519081900360640190fd5b601f5481111561107a576040805162461bcd60e51b81526020600482015260086024820152670e8dede40d0d2ced60c31b604482015290519081900360640190fd5b601e54604080519182526020820183905280517f9ed86471439d7f9baf99d5c0ab085619e84704bc0734986d0ab65efa43a8be4b9281900390910190a1601e55565b60178181548110610b1057fe5b6009546001600160a01b031681565b600c546001600160a01b03163314611120576040805162461bcd60e51b8152602060048083019190915260248201526310b3b7bb60e11b604482015290519081900360640190fd5b6007546001600160a01b038481169116141561116b576040805162461bcd60e51b8152602060048201526005602482015264217361666560d81b604482015290519081900360640190fd5b6004546001600160a01b03848116911614156111b6576040805162461bcd60e51b8152602060048201526005602482015264217361666560d81b604482015290519081900360640190fd5b6111ca6001600160a01b0384168284612544565b505050565b60155481565b6008546001600160a01b031681565b601d6020526000908152604090205481565b6111fe6123e2565b6000546001600160a01b0390811691161461124e576040805162461bcd60e51b81526020600482018190526024820152600080516020612f51833981519152604482015290519081900360640190fd5b600080546040516001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080546001600160a01b0319169055565b6012546001600160a01b031681565b6005546001600160a01b031681565b600c546001600160a01b031633146112fe576040805162461bcd60e51b8152602060048083019190915260248201526310b3b7bb60e11b604482015290519081900360640190fd5b610cbe612596565b600254610100900460ff1681565b600c546001600160a01b0316331461135c576040805162461bcd60e51b8152602060048083019190915260248201526310b3b7bb60e11b604482015290519081900360640190fd5b6126de8510156113b3576040805162461bcd60e51b815260206004820152601a60248201527f5f656e7472616e6365466565466163746f7220746f6f206c6f77000000000000604482015290519081900360640190fd5b61271085111561140a576040805162461bcd60e51b815260206004820152601b60248201527f5f656e7472616e6365466565466163746f7220746f6f20686967680000000000604482015290519081900360640190fd5b60148590556126de841015611466576040805162461bcd60e51b815260206004820152601a60248201527f5f7769746864726177466565466163746f7220746f6f206c6f77000000000000604482015290519081900360640190fd5b6127108411156114bd576040805162461bcd60e51b815260206004820152601b60248201527f5f7769746864726177466565466163746f7220746f6f20686967680000000000604482015290519081900360640190fd5b601584905561012c831115611519576040805162461bcd60e51b815260206004820152601760248201527f5f636f6e74726f6c6c657246656520746f6f2068696768000000000000000000604482015290519081900360640190fd5b601083905561032082111561156d576040805162461bcd60e51b81526020600482015260156024820152740bec4eaf284c2c6d6a4c2e8ca40e8dede40d0d2ced605b1b604482015290519081900360640190fd5b60118290556103e38111156115c9576040805162461bcd60e51b815260206004820152601860248201527f5f736c697070616765466163746f7220746f6f20686967680000000000000000604482015290519081900360640190fd5b60168190556040805186815260208101869052808201859052606081018490526080810183905290517fc67e0b149a57a70fa44a531a46c2c6d8e0b242fa12f459f250012c3a5987d29a9181900360a00190a15050505050565b60105481565b6126de81565b600c546001600160a01b03163314611677576040805162461bcd60e51b8152602060048083019190915260248201526310b3b7bb60e11b604482015290519081900360640190fd5b601380546001600160a01b0383166001600160a01b0319909116811790915560408051918252517fa69f1931be99336e049905baa11d21ed44204d7686e46b4344404d80d47c29889181900360200190a150565b6000546001600160a01b031690565b60198181548110610b1057fe5b60025462010000900460ff1681565b601f5481565b60025464010000000090046001600160a01b031681565b600c546001600160a01b0316331461175b576040805162461bcd60e51b8152602060048083019190915260248201526310b3b7bb60e11b604482015290519081900360640190fd5b601280546001600160a01b0383166001600160a01b0319909116811790915560408051918252517f200c92aaea275302bf641e37f7a5dda63f445f08f4fc74a5cde7fd643f609e099181900360200190a150565b61032081565b6103e381565b601a8181548110610b1057fe5b6013546001600160a01b031681565b60025460ff1615611822576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b6002546301000000900460ff1661186e576040805162461bcd60e51b815260206004820152600b60248201526a02169734175746f436f6d760ac1b604482015290519081900360640190fd5b600254610100900460ff16156118bb576040805162461bcd60e51b815260206004820152600d60248201526c697343414b455374616b696e6760981b604482015290519081900360640190fd5b600554604080516370a0823160e01b815230600482015290516000926001600160a01b0316916370a08231916024808301926020929190829003018186803b15801561190657600080fd5b505afa15801561191a573d6000803e3d6000fd5b505050506040513d602081101561193057600080fd5b50516007546005549192506001600160a01b039182169116148015906119565750600081115b15611a0b57600854600554611978916001600160a01b03918216911683612617565b611a0b600860009054906101000a90046001600160a01b031682601654601a8054806020026020016040519081016040528092919081815260200182805480156119eb57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116119cd575b505050505030611a06610258426124ea90919063ffffffff16565b612702565b600654604080516370a0823160e01b815230600482015290516000926001600160a01b0316916370a08231916024808301926020929190829003018186803b158015611a5657600080fd5b505afa158015611a6a573d6000803e3d6000fd5b505050506040513d6020811015611a8057600080fd5b50516007546006549192506001600160a01b03918216911614801590611aa65750600081115b15611b5457600854600654611ac8916001600160a01b03918216911683612617565b611b54600860009054906101000a90046001600160a01b031682601654601b8054806020026020016040519081016040528092919081815260200182805480156119eb576020028201919060005260206000209081546001600160a01b031681526001909101906020018083116119cd57505050505030611a06610258426124ea90919063ffffffff16565b5050565b60188181548110610b1057fe5b600c546001600160a01b03163314611bad576040805162461bcd60e51b8152602060048083019190915260248201526310b3b7bb60e11b604482015290519081900360640190fd5b600c80546001600160a01b0383166001600160a01b0319909116811790915560408051918252517f91a8c1cc2d4a3bb60738481947a00cbb9899c822916694cf8bb1d68172fdcd549181900360200190a150565b60026001541415611c47576040805162461bcd60e51b815260206004820152601f6024820152600080516020612ec4833981519152604482015290519081900360640190fd5b600260018190555460ff1615611c97576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b600c54600160a01b900460ff1615611cf157600c546001600160a01b03163314611cf1576040805162461bcd60e51b8152602060048083019190915260248201526310b3b7bb60e11b604482015290519081900360640190fd5b6009546007546001600160a01b0390811691161415611d1257611d1261296c565b600754604080516370a0823160e01b815230600482015290516000926001600160a01b0316916370a08231916024808301926020929190829003018186803b158015611d5d57600080fd5b505afa158015611d71573d6000803e3d6000fd5b505050506040513d6020811015611d8757600080fd5b5051600854600754919250611daa916001600160a01b03908116911660006129e0565b600854600754611dc7916001600160a01b03918216911683612617565b611e53600860009054906101000a90046001600160a01b03168260165460178054806020026020016040519081016040528092919081815260200182805480156119eb576020028201919060005260206000209081546001600160a01b031681526001909101906020018083116119cd57505050505030611a06610258426124ea90919063ffffffff16565b43600d55600e54600b54604080516370a0823160e01b815230600482015290516001600160a01b03909216916370a0823191602480820192602092909190829003018186803b158015611ea557600080fd5b505afa158015611eb9573d6000803e3d6000fd5b505050506040513d6020811015611ecf57600080fd5b5051600e81905560408051838152602081019290925280517f20af63a05ddf83dc81c8c1ae988c1c1f48baed1c460e8c2caa67c3b8647792049281900390910190a1505060018055565b600c546001600160a01b03163314611f61576040805162461bcd60e51b8152602060048083019190915260248201526310b3b7bb60e11b604482015290519081900360640190fd5b610cbe61296c565b6006546001600160a01b031681565b6002546301000000900460ff1681565b6007546001600160a01b031681565b6004546001600160a01b031681565b60035481565b611fb46123e2565b6000546001600160a01b03908116911614612004576040805162461bcd60e51b81526020600482018190526024820152600080516020612f51833981519152604482015290519081900360640190fd5b6001600160a01b0381166120495760405162461bcd60e51b8152600401808060200182810382526026815260200180612ee46026913960400191505060405180910390fd5b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b60006120ae6123e2565b6000546001600160a01b039081169116146120fe576040805162461bcd60e51b81526020600482018190526024820152600080516020612f51833981519152604482015290519081900360640190fd5b60026001541415612144576040805162461bcd60e51b815260206004820152601f6024820152600080516020612ec4833981519152604482015290519081900360640190fd5b6002600155601e546001600160a01b0384166000908152601d6020526040902054429161217191906124ea565b106121b0576040805162461bcd60e51b815260206004820152600a602482015269746f6f206561726c792160b01b604482015290519081900360640190fd5b600082116121f5576040805162461bcd60e51b815260206004820152600d60248201526c05f77616e74416d74203c3d203609c1b604482015290519081900360640190fd5b6000612212600e54610ea7600f548661244690919063ffffffff16565b9050600f548111156122235750600f545b600f546122309082612af3565b600f55601554612710111561225d5761225a612710610ea76015548661244690919063ffffffff16565b92505b60048054604080516370a0823160e01b81523093810193909352516000926001600160a01b03909216916370a08231916024808301926020929190829003018186803b1580156122ac57600080fd5b505afa1580156122c0573d6000803e3d6000fd5b505050506040513d60208110156122d657600080fd5b50519050808411156122e6578093505b83600e5410156122f657600e5493505b600e546123039085612af3565b600e55600a54600454612323916001600160a01b03918216911686612544565b50600180559392505050565b600a546001600160a01b031681565b60165481565b60025460ff16612392576040805162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b604482015290519081900360640190fd5b6002805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa6123c56123e2565b604080516001600160a01b039092168252519081900360200190a1565b3390565b604080516001600160a01b0380861660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b179052612440908590612b35565b50505050565b600082612455575060006124a2565b8282028284828161246257fe5b041461249f5760405162461bcd60e51b8152600401808060200182810382526021815260200180612f306021913960400191505060405180910390fd5b90505b92915050565b600061249f83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250612be6565b60008282018381101561249f576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b1790526111ca908490612b35565b60025460ff16156125e1576040805162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015290519081900360640190fd5b6002805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586123c56123e2565b60006126ad82856001600160a01b031663dd62ed3e30876040518363ffffffff1660e01b815260040180836001600160a01b03168152602001826001600160a01b031681526020019250505060206040518083038186803b15801561267b57600080fd5b505afa15801561268f573d6000803e3d6000fd5b505050506040513d60208110156126a557600080fd5b5051906124ea565b604080516001600160a01b038616602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b179052909150612440908590612b35565b6040805163d06ca61f60e01b815260048101878152602482019283528551604483015285516060936001600160a01b038b169363d06ca61f938b938a939192606401906020808601910280838360005b8381101561276a578181015183820152602001612752565b50505050905001935050505060006040518083038186803b15801561278e57600080fd5b505afa1580156127a2573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405260208110156127cb57600080fd5b81019080805160405193929190846401000000008211156127eb57600080fd5b90830190602082018581111561280057600080fd5b825186602082028301116401000000008211171561281d57600080fd5b82525081516020918201928201910280838360005b8381101561284a578181015183820152602001612832565b50505050905001604052505050905060008161287160018451612af390919063ffffffff16565b8151811061287b57fe5b60200260200101519050876001600160a01b0316635c11d795886128ae6103e8610ea78b8761244690919063ffffffff16565b8888886040518663ffffffff1660e01b81526004018086815260200185815260200180602001846001600160a01b03168152602001838152602001828103825285818151815260200191508051906020019060200280838360005b83811015612921578181015183820152602001612909565b505050509050019650505050505050600060405180830381600087803b15801561294a57600080fd5b505af115801561295e573d6000803e3d6000fd5b505050505050505050505050565b4780156129dd57600960009054906101000a90046001600160a01b03166001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b1580156129c357600080fd5b505af11580156129d7573d6000803e3d6000fd5b50505050505b50565b801580612a66575060408051636eb1769f60e11b81523060048201526001600160a01b03848116602483015291519185169163dd62ed3e91604480820192602092909190829003018186803b158015612a3857600080fd5b505afa158015612a4c573d6000803e3d6000fd5b505050506040513d6020811015612a6257600080fd5b5051155b612aa15760405162461bcd60e51b8152600401808060200182810382526036815260200180612f9b6036913960400191505060405180910390fd5b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b1790526111ca908490612b35565b600061249f83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250612c8a565b6060612b8a826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316612ce49092919063ffffffff16565b8051909150156111ca57808060200190516020811015612ba957600080fd5b50516111ca5760405162461bcd60e51b815260040180806020018281038252602a815260200180612f71602a913960400191505060405180910390fd5b60008183612c725760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015612c37578181015183820152602001612c1f565b50505050905090810190601f168015612c645780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b506000838581612c7e57fe5b049150505b9392505050565b60008184841115612cdc5760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315612c37578181015183820152602001612c1f565b505050900390565b6060612cf38484600085612cfb565b949350505050565b606082471015612d3c5760405162461bcd60e51b8152600401808060200182810382526026815260200180612f0a6026913960400191505060405180910390fd5b612d4585612e57565b612d96576040805162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015290519081900360640190fd5b60006060866001600160a01b031685876040518082805190602001908083835b60208310612dd55780518252601f199092019160209182019101612db6565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d8060008114612e37576040519150601f19603f3d011682016040523d82523d6000602084013e612e3c565b606091505b5091509150612e4c828286612e5d565b979650505050505050565b3b151590565b60608315612e6c575081612c83565b825115612e7c5782518084602001fd5b60405162461bcd60e51b8152602060048201818152845160248401528451859391928392604401919085019080838360008315612c37578181015183820152602001612c1f56fe5265656e7472616e637947756172643a207265656e7472616e742063616c6c004f776e61626c653a206e6577206f776e657220697320746865207a65726f2061646472657373416464726573733a20696e73756666696369656e742062616c616e636520666f722063616c6c536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f774f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65725361666545524332303a204552433230206f7065726174696f6e20646964206e6f7420737563636565645361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f20746f206e6f6e2d7a65726f20616c6c6f77616e6365a2646970667358221220fbc92eac7b958a01974ad58317381c39ce812a8a60d8a14162afb08b920f060164736f6c634300060c00334f776e61626c653a206e6577206f776e657220697320746865207a65726f20616464726573738be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "abi": [ + { + "inputs": [ + { "internalType": "address[]", "name": "_addresses", "type": "address[]" }, + { "internalType": "uint256", "name": "_pid", "type": "uint256" }, + { "internalType": "bool", "name": "_isCAKEStaking", "type": "bool" }, + { "internalType": "bool", "name": "_isSameAssetDeposit", "type": "bool" }, + { "internalType": "bool", "name": "_isAutoComp", "type": "bool" }, + { "internalType": "address[]", "name": "_earnedToAUTOPath", "type": "address[]" }, + { "internalType": "address[]", "name": "_earnedToToken0Path", "type": "address[]" }, + { "internalType": "address[]", "name": "_earnedToToken1Path", "type": "address[]" }, + { "internalType": "address[]", "name": "_token0ToEarnedPath", "type": "address[]" }, + { "internalType": "address[]", "name": "_token1ToEarnedPath", "type": "address[]" }, + { "internalType": "uint256", "name": "_controllerFee", "type": "uint256" }, + { "internalType": "uint256", "name": "_buyBackRate", "type": "uint256" }, + { "internalType": "uint256", "name": "_entranceFeeFactor", "type": "uint256" }, + { "internalType": "uint256", "name": "_withdrawFeeFactor", "type": "uint256" }, + { "internalType": "uint256", "name": "_minTimeToWithdraw", "type": "uint256" } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "previousOwner", "type": "address" }, + { "indexed": true, "internalType": "address", "name": "newOwner", "type": "address" } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [{ "indexed": false, "internalType": "address", "name": "account", "type": "address" }], + "name": "Paused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [{ "indexed": false, "internalType": "address", "name": "_buyBackAddress", "type": "address" }], + "name": "SetBuyBackAddress", + "type": "event" + }, + { + "anonymous": false, + "inputs": [{ "indexed": false, "internalType": "address", "name": "_govAddress", "type": "address" }], + "name": "SetGov", + "type": "event" + }, + { + "anonymous": false, + "inputs": [{ "indexed": false, "internalType": "bool", "name": "_onlyGov", "type": "bool" }], + "name": "SetOnlyGov", + "type": "event" + }, + { + "anonymous": false, + "inputs": [{ "indexed": false, "internalType": "address", "name": "_rewardsAddress", "type": "address" }], + "name": "SetRewardsAddress", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "uint256", "name": "_entranceFeeFactor", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "_withdrawFeeFactor", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "_controllerFee", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "_buyBackRate", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "_slippageFactor", "type": "uint256" } + ], + "name": "SetSettings", + "type": "event" + }, + { + "anonymous": false, + "inputs": [{ "indexed": false, "internalType": "address", "name": "_uniRouterAddress", "type": "address" }], + "name": "SetUniRouterAddress", + "type": "event" + }, + { + "anonymous": false, + "inputs": [{ "indexed": false, "internalType": "address", "name": "account", "type": "address" }], + "name": "Unpaused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "uint256", "name": "oldWantLockedTotal", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "newWantLockedTotal", "type": "uint256" } + ], + "name": "earned", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "uint256", "name": "oldMinTimeToWithdraw", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "newMinTimeToWithdraw", "type": "uint256" } + ], + "name": "minTimeToWithdrawChanged", + "type": "event" + }, + { + "inputs": [], + "name": "AUTOAddress", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "autoFarmAddress", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "buyBackAddress", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "buyBackRate", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "buyBackRateMax", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "buyBackRateUL", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "controllerFee", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "controllerFeeMax", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "controllerFeeUL", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { "inputs": [], "name": "convertDustToEarned", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { "internalType": "address", "name": "_userAddress", "type": "address" }, + { "internalType": "uint256", "name": "_wantAmt", "type": "uint256" } + ], + "name": "deposit", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { "inputs": [], "name": "earn", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [], + "name": "earnedAddress", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "name": "earnedToAUTOPath", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "name": "earnedToToken0Path", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "name": "earnedToToken1Path", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "entranceFeeFactor", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "entranceFeeFactorLL", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "entranceFeeFactorMax", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { "inputs": [], "name": "farm", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [], + "name": "farmContractAddress", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "govAddress", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "_token", "type": "address" }, + { "internalType": "uint256", "name": "_amount", "type": "uint256" }, + { "internalType": "address", "name": "_to", "type": "address" } + ], + "name": "inCaseTokensGetStuck", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "isAutoComp", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "isCAKEStaking", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "isSameAssetDeposit", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lastEarnBlock", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "minTimeToWithdraw", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "minTimeToWithdrawUL", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "onlyGov", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { "inputs": [], "name": "pause", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [], + "name": "paused", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pid", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { "inputs": [], "name": "renounceOwnership", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [], + "name": "rewardsAddress", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "_buyBackAddress", "type": "address" }], + "name": "setBuyBackAddress", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "_govAddress", "type": "address" }], + "name": "setGov", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint256", "name": "newMinTimeToWithdraw", "type": "uint256" }], + "name": "setMinTimeToWithdraw", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "bool", "name": "_onlyGov", "type": "bool" }], + "name": "setOnlyGov", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "_rewardsAddress", "type": "address" }], + "name": "setRewardsAddress", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { "internalType": "uint256", "name": "_entranceFeeFactor", "type": "uint256" }, + { "internalType": "uint256", "name": "_withdrawFeeFactor", "type": "uint256" }, + { "internalType": "uint256", "name": "_controllerFee", "type": "uint256" }, + { "internalType": "uint256", "name": "_buyBackRate", "type": "uint256" }, + { "internalType": "uint256", "name": "_slippageFactor", "type": "uint256" } + ], + "name": "setSettings", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "_uniRouterAddress", "type": "address" }], + "name": "setUniRouterAddress", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "sharesTotal", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "slippageFactor", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "slippageFactorUL", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "token0Address", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "name": "token0ToEarnedPath", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "token1Address", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "name": "token1ToEarnedPath", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "newOwner", "type": "address" }], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "uniRouterAddress", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { "inputs": [], "name": "unpause", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [{ "internalType": "address", "name": "", "type": "address" }], + "name": "userLastDepositedTimestamp", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "userLength", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "name": "users", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "wantAddress", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "wantLockedTotal", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "wbnbAddress", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { "internalType": "address", "name": "_userAddress", "type": "address" }, + { "internalType": "uint256", "name": "_wantAmt", "type": "uint256" } + ], + "name": "withdraw", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "withdrawFeeFactor", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "withdrawFeeFactorLL", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "withdrawFeeFactorMax", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { "inputs": [], "name": "wrapBNB", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, + { "stateMutability": "payable", "type": "receive" } + ] +} diff --git a/contracts/interfaces/IAutoFarm.sol b/contracts/interfaces/IAutoFarm.sol new file mode 100644 index 00000000..d358cc5f --- /dev/null +++ b/contracts/interfaces/IAutoFarm.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.6.0; + +interface IAutoFarm { + function poolInfo(uint256 _pid) + external + view + returns ( + address want, + uint256 allocPoint, + uint256 lastRewardBlock, + uint256 accAUTOPerShare, + address strat + ); + + function userInfo(uint256 _pid, address _user) external view returns (uint256 shares); + + function deposit(uint256 _pid, uint256 _wantAmt) external returns (uint256); + + function withdraw(uint256 _pid, uint256 _wantAmt) external returns (uint256); + + function stakedWantTokens(uint256 _pid, address _user) external view returns (uint256); +} diff --git a/contracts/interfaces/IAutoFarmStrategy.sol b/contracts/interfaces/IAutoFarmStrategy.sol new file mode 100644 index 00000000..2112805e --- /dev/null +++ b/contracts/interfaces/IAutoFarmStrategy.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: MIT + +interface IAutoFarmStrategy { + function wantLockedTotal() external view returns (uint256); + + function sharesTotal() external view returns (uint256); + + function earn() external; + + function deposit(address _userAddress, uint256 _wantAmt) external returns (uint256); + + function withdraw(address _userAddress, uint256 _wantAmt) external returns (uint256); + + function inCaseTokensGetStuck( + address _token, + uint256 _amount, + address _to + ) external; +} diff --git a/contracts/powerindex-router/implementations/AutoPowerIndexRouter.sol b/contracts/powerindex-router/implementations/AutoPowerIndexRouter.sol new file mode 100644 index 00000000..66bdf6f8 --- /dev/null +++ b/contracts/powerindex-router/implementations/AutoPowerIndexRouter.sol @@ -0,0 +1,211 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.6.12; +pragma experimental ABIEncoderV2; + +import "../../interfaces/IAutoFarm.sol"; +import "../../interfaces/IAutoFarmStrategy.sol"; +import "../PowerIndexBasicRouter.sol"; + +contract AutoPowerIndexRouter is PowerIndexBasicRouter { + event Stake(address indexed sender, uint256 amount); + event Redeem(address indexed sender, uint256 amount); + event ClaimRewards(address indexed sender, uint256 expectedAutoReward, uint256 releasedAutoReward); + event DistributeRewards( + address indexed sender, + uint256 autoReward, + uint256 pvpReward, + uint256 poolRewardsUnderlying, + uint256 poolRewardsPi, + address[] pools + ); + + struct AutoConfig { + address AUTO; + } + + uint256 internal constant AUTO_FARM_PID = 0; + IERC20 internal immutable AUTO; + + constructor( + address _piToken, + BasicConfig memory _basicConfig, + AutoConfig memory _autoConfig + ) public PowerIndexBasicRouter(_piToken, _basicConfig) { + AUTO = IERC20(_autoConfig.AUTO); + } + + /*** PERMISSIONLESS REWARD CLAIMING AND DISTRIBUTION ***/ + + /** + * @notice Withdraws the extra staked AUTO as a reward and transfers it to the router + */ + function _claimRewards(ReserveStatus) internal override { + uint256 rewardsPending = getPendingRewards(); + require(rewardsPending > 0, "NOTHING_TO_CLAIM"); + + uint256 autoBefore = AUTO.balanceOf(address(piToken)); + + // Step #1. Claim the excess of AUTO from AutoFarm + _callStaking(IAutoFarm.withdraw.selector, abi.encode(AUTO_FARM_PID, rewardsPending)); + uint256 released = AUTO.balanceOf(address(piToken)).sub(autoBefore); + require(released > 0, "NOTHING_RELEASED"); + + // Step #2. Transfer the claimed AUTO to the router + piToken.callExternal(address(AUTO), IERC20.transfer.selector, abi.encode(address(this), released), 0); + + emit ClaimRewards(msg.sender, rewardsPending, released); + } + + /** + * @notice Wraps the router's AUTOs into piTokens and transfers it to the pools proportionally their AUTO balances + */ + function _distributeRewards() internal override { + uint256 pendingReward = AUTO.balanceOf(address(this)); + require(pendingReward > 0, "NO_PENDING_REWARD"); + + // Step #1. Distribute pvpReward + (uint256 pvpReward, uint256 poolRewardsUnderlying) = _distributeRewardToPvp(pendingReward, AUTO); + require(poolRewardsUnderlying > 0, "NO_POOL_REWARDS_UNDERLYING"); + + // Step #2. Wrap AUTO into piAUTO + AUTO.approve(address(piToken), poolRewardsUnderlying); + piToken.deposit(poolRewardsUnderlying); + + // Step #3. Distribute piAUTO over the pools + (uint256 poolRewardsPi, address[] memory pools) = _distributePiRemainderToPools(piToken); + + emit DistributeRewards(msg.sender, pendingReward, pvpReward, poolRewardsUnderlying, poolRewardsPi, pools); + } + + /*** VIEWERS ***/ + + /** + * @notice Get the amount of AUTO tokens AutoFarm will release in exchange of the given shares + * @param _shares The input amount of shares + * @dev To be used from front-end only + * @return The corresponding amount of AUTO tokens + */ + function getAutoForShares(uint256 _shares) external view returns (uint256) { + (, , , , address strat) = IAutoFarm(staking).poolInfo(AUTO_FARM_PID); + + uint256 wantLockedTotal = IAutoFarmStrategy(strat).wantLockedTotal(); + uint256 sharesTotal = IAutoFarmStrategy(strat).sharesTotal(); + + return _shares.mul(wantLockedTotal).div(sharesTotal); + } + + /** + * @notice Get the total amount of AUTO tokens could be released in exchange of the piToken's AutoFarm share. + * Is comprised of the underlyingStaked and the pendingRewards. + * @return The AUTO amount + */ + function getUnderlyingOnAutoFarm() public view returns (uint256) { + if (staking == address(0)) { + return 0; + } + + return IAutoFarm(staking).stakedWantTokens(AUTO_FARM_PID, address(piToken)); + } + + /** + * @notice Get the amount of current pending rewards available at AutoFarm + * @return amount of pending rewards + */ + function getPendingRewards() public view returns (uint256 amount) { + // return autoAtPiToken + getUnderlyingOnAutoFarm - piToken.totalSupply() + return AUTO.balanceOf(address(piToken)).add(getUnderlyingOnAutoFarm()).sub(piToken.totalSupply()); + } + + /*** EQUIVALENT METHODS OVERRIDES ***/ + + function getPiEquivalentForUnderlying( + uint256 _underlyingAmount, + IERC20, /* _underlyingToken */ + uint256 /* _piTotalSupply */ + ) public view override returns (uint256) { + return _underlyingAmount; + } + + function getPiEquivalentForUnderlyingPure( + uint256 _underlyingAmount, + uint256, /* _totalUnderlyingWrapped */ + uint256 /* _piTotalSupply */ + ) public pure override returns (uint256) { + return _underlyingAmount; + } + + function getUnderlyingEquivalentForPi( + uint256 _piAmount, + IERC20, /* _underlyingToken */ + uint256 /* _piTotalSupply */ + ) public view override returns (uint256) { + return _piAmount; + } + + function getUnderlyingEquivalentForPiPure( + uint256 _piAmount, + uint256, /* _totalUnderlyingWrapped */ + uint256 /* _piTotalSupply */ + ) public pure override returns (uint256) { + return _piAmount; + } + + /*** OWNER METHODS ***/ + + /** + * @notice The contract owner manually stakes the given amount of AUTO + * @param _amount The amount AUTO to stake + */ + function stake(uint256 _amount) external onlyOwner { + _stake(_amount); + } + + /** + * @notice The contract owner manually burns the given amount of staking shares in exchange of AUTO tokens + * @param _amount The amount auto to redeem + */ + function redeem(uint256 _amount) external onlyOwner { + _redeem(_amount); + } + + /*** POKE FUNCTION ***/ + + function _rebalancePoke(ReserveStatus reserveStatus, uint256 autoDiff) internal override { + require(staking != address(0), "STAKING_IS_NULL"); + + if (reserveStatus == ReserveStatus.SHORTAGE) { + _redeem(autoDiff); + } else if (reserveStatus == ReserveStatus.EXCESS) { + _stake(autoDiff); + } + } + + /*** INTERNALS ***/ + + /** + * @notice Get the opposite to the reserve ratio amount of AUTO staked at AutoFarm + * @return The AUTO amount + */ + function _getUnderlyingStaked() internal view override returns (uint256) { + // return piTokenTotalSupply - autoAtPiToken + return piToken.totalSupply().sub(AUTO.balanceOf(address(piToken))); + } + + function _stake(uint256 _amount) internal { + require(_amount > 0, "CANT_STAKE_0"); + + piToken.approveUnderlying(staking, _amount); + _callStaking(IAutoFarm(0).deposit.selector, abi.encode(AUTO_FARM_PID, _amount)); + + emit Stake(msg.sender, _amount); + } + + function _redeem(uint256 _amount) internal { + require(_amount > 0, "CANT_REDEEM_0"); + + _callStaking(IAutoFarm(0).withdraw.selector, abi.encode(AUTO_FARM_PID, _amount)); + + emit Redeem(msg.sender, _amount); + } +} diff --git a/contracts/test/bsc/MockAutoMasterChef.sol b/contracts/test/bsc/MockAutoMasterChef.sol new file mode 100644 index 00000000..6d582f8f --- /dev/null +++ b/contracts/test/bsc/MockAutoMasterChef.sol @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.6.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +contract MockAutoMasterChef { + address token; + uint256 swt; + + constructor(address _token, uint256 _swt) public { + token = _token; + swt = _swt; + } + + function deposit(uint256, uint256 _amount) external { + IERC20(token).transferFrom(msg.sender, address(42), _amount); + } + + function withdraw(uint256, uint256) external {} + + function stakedWantTokens(uint256, address) external view returns (uint256) { + return swt; + } + + function poolInfo(uint256) + external + view + returns ( + address want, + uint256 allocPoint, + uint256 lastRewardBlock, + uint256 accAUTOPerShare, + address strat + ) + { + return (address(0), 0, 0, 0, strat); + } + + function userInfo(uint256, address) external view returns (uint256 amount, uint256 rewardDebt) { + return (0, 0); + } +} diff --git a/contracts/test/bsc/MockPancakeRouter.sol b/contracts/test/bsc/MockPancakeRouter.sol new file mode 100644 index 00000000..9fc4ad3e --- /dev/null +++ b/contracts/test/bsc/MockPancakeRouter.sol @@ -0,0 +1,13 @@ +contract MockPancakeRouter { + function getAmountsOut(uint256 amountIn, address[] calldata path) external view returns (uint256[] memory amounts) { + amounts = new uint256[](path.length); + } + + function swapExactTokensForTokensSupportingFeeOnTransferTokens( + uint256 amountIn, + uint256 amountOutMin, + address[] calldata path, + address to, + uint256 deadline + ) external {} +} diff --git a/contracts/test/sushi/MockPancakeMasterChef.sol b/contracts/test/sushi/MockPancakeMasterChef.sol index 73353667..44061059 100644 --- a/contracts/test/sushi/MockPancakeMasterChef.sol +++ b/contracts/test/sushi/MockPancakeMasterChef.sol @@ -6,13 +6,21 @@ import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; contract MockPancakeMasterChef { address token; + bool doTransfer; constructor(address _token) public { token = _token; + doTransfer = true; + } + + function setDoTransfer(bool _doTransfer) external { + doTransfer = _doTransfer; } function enterStaking(uint256 _amount) external { - IERC20(token).transferFrom(msg.sender, address(42), _amount); + if (doTransfer) { + IERC20(token).transferFrom(msg.sender, address(42), _amount); + } } function leaveStaking(uint256) external {} diff --git a/test/helpers/builders.js b/test/helpers/builders.js index 89074cf7..e47a8703 100644 --- a/test/helpers/builders.js +++ b/test/helpers/builders.js @@ -45,6 +45,7 @@ function buildPancakeMasterChefRouterConfig(cake) { return { cake }; } +// BAKERY function buildBakeryChefRouterConfig(token) { return { token }; } @@ -53,6 +54,11 @@ function buildMasterChefRouterConfig(token, masterChefPid) { return { token, masterChefPid }; } +// AUTO +function buildAutoRouterConfig(AUTO) { + return { AUTO }; +} + const BasicConfig = { poolRestrictions: 'address', powerPoke: 'address', @@ -136,6 +142,7 @@ module.exports = { buildPancakeMasterChefRouterConfig, buildBakeryChefRouterConfig, buildMasterChefRouterConfig, + buildAutoRouterConfig, buildAaveAssetConfigInput, buildBasicRouterArgs, buildYearnRouterArgs, diff --git a/test/router/implementations/AutoRouter.unit.js b/test/router/implementations/AutoRouter.unit.js new file mode 100644 index 00000000..0eb4aa65 --- /dev/null +++ b/test/router/implementations/AutoRouter.unit.js @@ -0,0 +1,612 @@ +const { time, constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { ether, addBN, artifactFromBytecode } = require('../../helpers'); +const { buildBasicRouterConfig, buildAutoRouterConfig } = require('../../helpers/builders'); +const assert = require('chai').assert; +const MockERC20 = artifacts.require('MockERC20'); +const MockWETH = artifacts.require('MockWETH'); +const AutoPowerIndexRouter = artifacts.require('AutoPowerIndexRouter'); +const WrappedPiErc20 = artifacts.require('WrappedPiErc20'); +const PoolRestrictions = artifacts.require('PoolRestrictions'); +const MockAutoMasterChef = artifacts.require('MockAutoMasterChef'); +const MockGulpingBPool = artifacts.require('MockGulpingBPool'); +const MockPoke = artifacts.require('MockPoke'); +const MockPancakeMasterChef = artifacts.require('MockPancakeMasterChef'); +const MockPancakeRouter = artifacts.require('MockPancakeRouter'); + +MockERC20.numberFormat = 'String'; +AutoPowerIndexRouter.numberFormat = 'String'; +WrappedPiErc20.numberFormat = 'String'; +MockWETH.numberFormat = 'String'; + +const AutoFarmV2_CrossChain = artifactFromBytecode('bsc/AutoFarmV2_CrossChain'); +const StratX2_AUTO = artifactFromBytecode('bsc/StratX2_AUTO'); + +const DEAD = '0x000000000000000000000000000000000000dead'; + +const { web3 } = MockERC20; + +describe('AutoRouter Tests', () => { + let autoOwner, bob, alice, piGov, stub, pvp, pool1, pool2; + + before(async function () { + [, autoOwner, bob, alice, piGov, stub, pvp, pool1, pool2] = await web3.eth.getAccounts(); + }); + + let auto, autoFarm, autoStrategy, poolRestrictions, piAuto, pancakeRouter, autoRouter, poke, wbnb; + + beforeEach(async function () { + // bsc: 0xa184088a740c695e156f91f5cc086a06bb78b827 + auto = await MockERC20.new('AUTOv2', 'AUTO', '18', ether('10000000')); + + pancakeRouter = await MockPancakeRouter.new(); + + const pancakeMasterChef = await MockPancakeMasterChef.new(auto.address); + await pancakeMasterChef.setDoTransfer(false); + wbnb = await MockWETH.new(); + + // bsc: 0x763a05bdb9f8946d8c3fa72d1e0d3f5e68647e5c + autoFarm = await AutoFarmV2_CrossChain.new(); + // bsc: 0xB27150dc6EE59ad4464cC7A89229b5870e568Be2 + autoStrategy = await StratX2_AUTO.new( + [ + // wbnb + wbnb.address, + // gov + autoOwner, + // autoFarm + autoFarm.address, + // AUTO + auto.address, + // want + auto.address, + // token0 + DEAD, + // token1 + DEAD, + // earned (bnb) + wbnb.address, + // fromContract, (set to the pancake mock in order to allow calling farm() which updates actual wantLockedTotal) + pancakeMasterChef.address, + // uniRouter + pancakeRouter.address, + // rewards + DEAD, + // buyBack + DEAD + ], + // pid + 0, + // isCAKEStaking + false, + // isSameAssetDeposit + true, + // isAutoComp, + true, + [alice, bob], + [], + [], + [], + [], + // controllerFee + 0, + // buyBackRate + 0, + // _entranceFeeFactor + 10000, + // _withdrawFeeFactor + 10000, + // _minTimeToWithdraw + 604800, + ); + + poolRestrictions = await PoolRestrictions.new(); + piAuto = await WrappedPiErc20.new(auto.address, stub, 'Wrapped AUTO', 'piAUTO'); + poke = await MockPoke.new(true); + autoRouter = await AutoPowerIndexRouter.new( + piAuto.address, + buildBasicRouterConfig( + poolRestrictions.address, + poke.address, + constants.ZERO_ADDRESS, + autoFarm.address, + ether('0.2'), + ether('0.02'), + '0', + pvp, + ether('0.15'), + [pool1, pool2] + ), + buildAutoRouterConfig( + auto.address + ), + ); + + await autoFarm.add(0, auto.address, false, autoStrategy.address); + await piAuto.changeRouter(autoRouter.address, { from: stub }); + + await auto.transfer(bob, ether(42000)); + await auto.approve(autoFarm.address, ether(42000), { from: bob }); + await autoFarm.deposit(0, ether(42000), { from: bob }); + + await autoRouter.transferOwnership(piGov); + + assert.equal(await autoRouter.owner(), piGov); + }); + + describe('owner methods', async () => { + beforeEach(async () => { + await autoRouter.transferOwnership(piGov, { from: piGov }); + }); + + describe('stake()/redeem()', () => { + beforeEach(async () => { + await auto.transfer(alice, ether('10000')); + await auto.approve(piAuto.address, ether('10000'), { from: alice }); + await piAuto.deposit(ether('10000'), { from: alice }); + + await autoRouter.poke(false); + + assert.equal(await auto.balanceOf(piAuto.address), ether(2000)); + assert.equal(await auto.balanceOf(autoStrategy.address), ether(50000)); + assert.equal(await autoFarm.stakedWantTokens(0, piAuto.address), ether(8000)); + }); + + describe('stake()', () => { + + it('should allow the owner staking any amount of reserve tokens', async () => { + const res = await autoRouter.stake(ether(2000), { from: piGov }); + expectEvent(res, 'Stake', { + sender: piGov, + amount: ether(2000), + }); + assert.equal(await auto.balanceOf(piAuto.address), ether(0)); + assert.equal(await auto.balanceOf(autoStrategy.address), ether(52000)); + assert.equal(await autoFarm.stakedWantTokens(0, piAuto.address), ether(10000)); + }); + + it('should deny staking 0', async () => { + await expectRevert(autoRouter.stake(ether(0), { from: piGov }), 'CANT_STAKE_0'); + }); + + it('should deny non-owner staking any amount of reserve tokens', async () => { + await expectRevert(autoRouter.stake(ether(1), { from: alice }), 'Ownable: caller is not the owner'); + }); + }) + + describe('redeem()', () => { + beforeEach(async () => { + await time.increase(time.duration.weeks(1)); + }); + + it('should allow the owner redeeming any amount of reserve tokens', async () => { + const res = await autoRouter.redeem(ether(3000), { from: piGov }); + expectEvent(res, 'Redeem', { + sender: piGov, + amount: ether(3000), + }); + assert.equal(await auto.balanceOf(piAuto.address), ether(5000)); + assert.equal(await autoFarm.stakedWantTokens(0, piAuto.address), ether(5000)); + assert.equal(await auto.balanceOf(autoStrategy.address), ether(47000)); + }); + + it('should deny redeeming 0', async () => { + await expectRevert(autoRouter.redeem(ether(0), { from: piGov }), 'CANT_REDEEM_0'); + }); + + it('should deny non-owner staking any amount of reserve tokens', async () => { + await expectRevert(autoRouter.redeem(ether(1), { from: alice }), 'Ownable: caller is not the owner'); + }); + }) + }); + + describe('setRewardPools()', () => { + it('should allow the owner setting a new reward pool', async () => { + const res = await autoRouter.setRewardPools([alice, bob], { from: piGov }); + expectEvent(res, 'SetRewardPools', { + len: '2', + rewardPools: [alice, bob], + }); + }); + + it('should deny setting an empty reward pool', async () => { + await expectRevert(autoRouter.setRewardPools([], { from: piGov }), 'AT_LEAST_ONE_EXPECTED'); + }); + + it('should deny non-owner setting a new reward pool', async () => { + await expectRevert(autoRouter.setRewardPools([alice, bob], { from: alice }), 'Ownable: caller is not the owner'); + }); + }); + + describe('setPvpFee()', () => { + it('should allow the owner setting a new pvpFee', async () => { + const res = await autoRouter.setPvpFee(ether('0.1'), { from: piGov }); + expectEvent(res, 'SetPvpFee', { + pvpFee: ether('0.1'), + }); + }); + + it('should deny setting a fee greater or equal 100%', async () => { + await expectRevert(autoRouter.setPvpFee(ether('1'), { from: piGov }), 'PVP_FEE_OVER_THE_LIMIT'); + }); + + it('should deny non-owner setting a new pvpFee', async () => { + await expectRevert(autoRouter.setPvpFee(ether('0'), { from: alice }), 'Ownable: caller is not the owner'); + }); + }); + }); + + describe('viewers', () => { + it('should return the same amount for getPiEquivalentForUnderlying()', async () => { + assert.equal(await autoRouter.getPiEquivalentForUnderlying(123, alice, 789), 123); + }); + + it('should return the same amount for getUnderlyingEquivalentForPi()', async () => { + assert.equal(await autoRouter.getUnderlyingEquivalentForPi(123, alice, 789), 123); + }); + + it('should return the same amount for getPiEquivalentForUnderlyingPure()', async () => { + assert.equal(await autoRouter.getPiEquivalentForUnderlyingPure(123, 456, 789), 123); + }); + + it('should return the same amount for getUnderlyingEquivalentForPiPure()', async () => { + assert.equal(await autoRouter.getUnderlyingEquivalentForPiPure(123, 456, 789), 123); + }); + }); + + describe('reserve management', () => { + beforeEach(async () => { + await auto.transfer(alice, ether(100000)); + await auto.approve(piAuto.address, ether(10000), { from: alice }); + await piAuto.deposit(ether(10000), { from: alice }); + + await autoRouter.poke(false); + + assert.equal(await auto.balanceOf(autoStrategy.address), ether(50000)); + assert.equal(await auto.balanceOf(piAuto.address), ether(2000)); + }); + + describe('non-modified auto/share ratio', () => { + it('should increase reserve on deposit', async () => { + assert.equal(await piAuto.balanceOf(alice), ether(10000)); + await auto.approve(piAuto.address, ether(1000), { from: alice }); + await piAuto.deposit(ether(1000), { from: alice }); + + await autoRouter.poke(false, { from: bob }); + + assert.equal(await piAuto.balanceOf(alice), ether(11000)); + assert.equal(await auto.balanceOf(autoStrategy.address), ether(50800)); + assert.equal(await autoFarm.stakedWantTokens(0, piAuto.address), ether(8800)); + assert.equal(await auto.balanceOf(piAuto.address), ether(2200)); + }); + + it('should decrease reserve on withdrawal', async () => { + assert.equal(await piAuto.balanceOf(alice), ether(10000)); + + await time.increase(time.duration.weeks(1)); + await piAuto.withdraw(ether(1000), { from: alice }); + + await autoRouter.poke(false, { from: bob }); + + assert.equal(await piAuto.balanceOf(alice), ether(9000)); + assert.equal(await auto.balanceOf(autoStrategy.address), ether(49200)); + assert.equal(await autoFarm.stakedWantTokens(0, piAuto.address), ether(7200)); + assert.equal(await auto.balanceOf(piAuto.address), ether(1800)); + }); + }); + + describe('modified auto/share ratio', () => { + beforeEach(async () => { + assert.equal(await piAuto.balanceOf(alice), ether(10000)); + assert.equal(await auto.balanceOf(autoStrategy.address), ether(50000)); + assert.equal(await autoFarm.stakedWantTokens(0, piAuto.address), ether(8000)); + assert.equal(await autoFarm.userInfo(0, piAuto.address), ether(8000)); + assert.equal(await auto.balanceOf(piAuto.address), ether(2000)); + // share/auto ratio is same + assert.equal(await autoRouter.getAutoForShares(ether(3160)), ether(3160)); + + // before AUTO/Shares ratio was 1 + await auto.transfer(autoStrategy.address, ether(30000)); + // after AUTO/Shares ratio increased to 1.6 + // call earn with a fake Pancake router in order to make wantLockedTotal update balance cache + await autoStrategy.earn({ from: autoOwner }); + + assert.equal(await piAuto.balanceOf(alice), ether(10000)); + assert.equal(await auto.balanceOf(autoStrategy.address), ether(80000)); + assert.equal(await autoFarm.stakedWantTokens(0, piAuto.address), ether(12800)); + assert.equal(await autoFarm.userInfo(0, piAuto.address), ether(8000)); + assert.equal(await auto.balanceOf(piAuto.address), ether(2000)); + assert.equal(await autoRouter.getUnderlyingStaked(), ether(8000)); + assert.equal(await autoStrategy.sharesTotal(), ether(50000)); + assert.equal(await autoStrategy.wantLockedTotal(), ether(80000)); + assert.equal(await autoRouter.getUnderlyingOnAutoFarm(), ether(12800)); + assert.equal(await autoRouter.getAutoForShares(ether(2000)), ether(3200)); + }); + + it('should mint a smaller amount of xSushi', async () => { + await auto.approve(piAuto.address, ether(1000), { from: alice }); + await piAuto.deposit(ether(1000), { from: alice }); + + await autoRouter.poke(false, { from: bob }); + + assert.equal(await piAuto.balanceOf(alice), ether(11000)); + assert.equal(await auto.balanceOf(autoStrategy.address), ether(80800)); + assert.equal(await autoFarm.userInfo(0, piAuto.address), ether(8500)); + assert.equal(await autoFarm.stakedWantTokens(0, piAuto.address), ether(13600)); + assert.equal(await auto.balanceOf(piAuto.address), ether(2200)); + assert.equal(await autoRouter.getUnderlyingStaked(), ether(8800)); + assert.equal(await autoRouter.getUnderlyingOnAutoFarm(), ether(13600)); + assert.equal(await autoRouter.getPendingRewards(), ether(4800)); + assert.equal(await autoRouter.getAutoForShares(ether(3160)), ether(5056)); + }); + + it('should decrease reserve on withdrawal', async () => { + await time.increase(time.duration.weeks(1)); + await piAuto.withdraw(ether(1000), { from: alice }); + + await autoRouter.poke(false, { from: bob }); + + assert.equal(await piAuto.balanceOf(alice), ether(9000)); + assert.equal(await auto.balanceOf(autoStrategy.address), ether(79200)); + assert.equal(await autoFarm.userInfo(0, piAuto.address), ether(7500)); + assert.equal(await autoFarm.stakedWantTokens(0, piAuto.address), ether(12000)); + assert.equal(await auto.balanceOf(piAuto.address), ether(1800)); + assert.equal(await autoRouter.getUnderlyingStaked(), ether(7200)); + assert.equal(await autoRouter.getUnderlyingOnAutoFarm(), ether(12000)); + assert.equal(await autoRouter.getPendingRewards(), ether(4800)); + assert.equal(await autoRouter.getAutoForShares(ether(3160)), ether(5056)); + }); + }); + + it('should revert rebalancing if the staking address is 0', async () => { + await time.increase(time.duration.weeks(1)); + await autoRouter.redeem(ether(8000), { from: piGov }); + await autoRouter.setVotingAndStaking(autoFarm.address, constants.ZERO_ADDRESS, { from: piGov }); + + assert.equal(await auto.balanceOf(autoStrategy.address), ether(42000)); + assert.equal(await auto.balanceOf(piAuto.address), ether(10000)); + assert.equal(await piAuto.balanceOf(alice), ether(10000)); + assert.equal(await piAuto.totalSupply(), ether(10000)); + + await piAuto.withdraw(ether(1000), { from: alice }); + + await expectRevert(autoRouter.poke(false, { from: bob }), 'STAKING_IS_NULL'); + + assert.equal(await auto.balanceOf(autoStrategy.address), ether(42000)); + assert.equal(await autoFarm.stakedWantTokens(0, piAuto.address), ether(0)); + assert.equal(await auto.balanceOf(piAuto.address), ether(9000)); + }); + + describe('when interval enabled', () => { + beforeEach(async () => { + await time.increase(time.duration.weeks(1)); + await autoRouter.setReserveConfig(ether('0.2'), time.duration.hours(1), { from: piGov }); + await poke.setMinMaxReportIntervals(time.duration.hours(1), time.duration.hours(2)); + await autoRouter.poke(false, { from: bob }); + }); + + it('should DO rebalance on deposit if the rebalancing interval has passed', async () => { + await time.increase(time.duration.minutes(61)); + + await auto.approve(piAuto.address, ether(1000), { from: alice }); + await piAuto.deposit(ether(1000), { from: alice }); + await autoRouter.pokeFromReporter('0', false, '0x', { from: bob }); + + assert.equal(await auto.balanceOf(autoStrategy.address), ether(50800)); + assert.equal(await autoFarm.stakedWantTokens(0, piAuto.address), ether(8800)); + assert.equal(await auto.balanceOf(piAuto.address), ether(2200)); + }); + + it('should DO rebalance on withdrawal if the rebalancing interval has passed', async () => { + await time.increase(time.duration.minutes(61)); + + await piAuto.withdraw(ether(1000), { from: alice }); + await autoRouter.pokeFromReporter('0', false, '0x', { from: bob }); + + assert.equal(await auto.balanceOf(autoStrategy.address), ether(49200)); + assert.equal(await autoFarm.stakedWantTokens(0, piAuto.address), ether(7200)); + assert.equal(await auto.balanceOf(piAuto.address), ether(1800)); + }); + + it('should NOT rebalance if the rebalancing interval hasn\'t passed', async () => { + await time.increase(time.duration.minutes(59)); + + await auto.approve(piAuto.address, ether(1000), { from: alice }); + await piAuto.deposit(ether(1000), { from: alice }); + + assert.equal(await autoRouter.getReserveStatusForStakedBalance().then(s => s.forceRebalance), false); + await expectRevert(autoRouter.pokeFromReporter('0', false, '0x', { from: bob }), 'MIN_INTERVAL_NOT_REACHED'); + + await time.increase(60); + + await autoRouter.pokeFromReporter('0', false, '0x', { from: bob }); + }); + + it('should rebalance if the rebalancing interval not passed but reserveRatioToForceRebalance has reached', async () => { + await time.increase(time.duration.minutes(59)); + + assert.equal(await autoRouter.getReserveStatusForStakedBalance().then(s => s.forceRebalance), false); + await piAuto.withdraw(ether(2000), { from: alice }); + assert.equal(await autoRouter.getReserveStatusForStakedBalance().then(s => s.forceRebalance), true); + await autoRouter.pokeFromReporter('0', false, '0x', { from: bob }); + + assert.equal(await auto.balanceOf(autoStrategy.address), ether(48400)); + assert.equal(await autoFarm.stakedWantTokens(0, piAuto.address), ether(6400)); + assert.equal(await auto.balanceOf(piAuto.address), ether(1600)); + }); + }); + + describe('on poke', async () => { + it('should do nothing when nothing has changed', async () => { + await autoRouter.poke(false, { from: bob }); + + assert.equal(await auto.balanceOf(autoStrategy.address), ether(50000)); + assert.equal(await autoFarm.stakedWantTokens(0, piAuto.address), ether(8000)); + assert.equal(await auto.balanceOf(piAuto.address), ether(2000)); + }); + + it('should increase reserve if required', async () => { + await auto.transfer(piAuto.address, ether(1000), { from: alice }); + + assert.equal(await auto.balanceOf(autoStrategy.address), ether(50000)); + assert.equal(await autoFarm.stakedWantTokens(0, piAuto.address), ether(8000)); + assert.equal(await auto.balanceOf(piAuto.address), ether(3000)); + assert.equal(await piAuto.totalSupply(), ether(10000)); + assert.equal(await autoRouter.getUnderlyingStaked(), ether(7000)); + assert.equal(await autoRouter.getUnderlyingOnAutoFarm(), ether(8000)); + assert.equal(await autoRouter.getPendingRewards(), ether(1000)); + + await autoRouter.poke(false, { from: bob }); + + assert.equal(await auto.balanceOf(autoStrategy.address), ether(51000)); + assert.equal(await autoFarm.stakedWantTokens(0, piAuto.address), ether(9000)); + assert.equal(await auto.balanceOf(piAuto.address), ether(2000)); + assert.equal(await piAuto.totalSupply(), ether(10000)); + assert.equal(await autoRouter.getUnderlyingStaked(), ether(8000)); + assert.equal(await autoRouter.getUnderlyingOnAutoFarm(), ether(9000)); + assert.equal(await autoRouter.getPendingRewards(), ether(1000)); + }); + }); + + it('should stake all the underlying tokens with 0 RR', async () => { + await autoRouter.setReserveConfig(ether(0), 0, { from: piGov }); + + await autoRouter.poke(false, { from: bob }); + assert.equal(await auto.balanceOf(autoStrategy.address), ether(52000)); + assert.equal(await auto.balanceOf(piAuto.address), ether(0)); + }) + + it('should keep all the underlying tokens on piToken with 1 RR', async () => { + await autoRouter.setReserveConfig(ether(1), 0, { from: piGov }); + await time.increase(time.duration.weeks(1)); + + await autoRouter.poke(false, { from: bob }); + assert.equal(await auto.balanceOf(autoStrategy.address), ether(42000)); + assert.equal(await auto.balanceOf(piAuto.address), ether(10000)); + }) + }); + + describe('reward distribution', async () => { + let poolA, poolB, poolC, poolD; + + beforeEach(async function () { + poolA = await MockGulpingBPool.new(); + poolB = await MockGulpingBPool.new(); + poolC = await MockGulpingBPool.new(); + poolD = await MockGulpingBPool.new(); + await autoRouter.setRewardPools([poolA.address, poolB.address, poolC.address], { from: piGov }); + + await poolRestrictions.setVotingAllowedForSenders(autoFarm.address, [alice], [true]); + + await auto.transfer(alice, ether('10000')); + await auto.approve(piAuto.address, ether('10000'), { from: alice }); + await piAuto.deposit(ether('10000'), { from: alice }); + + await autoRouter.poke(false); + await autoStrategy.earn({ from: autoOwner }); + + assert.equal(await piAuto.totalSupply(), ether('10000')); + assert.equal(await piAuto.balanceOf(alice), ether('10000')); + assert.equal(await autoStrategy.sharesTotal(), ether(50000)); + assert.equal(await autoStrategy.wantLockedTotal(), ether(50000)); + + await piAuto.transfer(poolA.address, 10, { from: alice }); + await piAuto.transfer(poolB.address, 20, { from: alice }); + }); + + it('should allow withdrawing rewards from the governance', async () => { + await auto.transfer(autoStrategy.address, ether(2000)); + await autoStrategy.earn({ from: autoOwner }); + + await time.increase(time.duration.days(8)); + assert.equal(await auto.balanceOf(piAuto.address), ether(2000)); + assert.equal(await autoRouter.getUnderlyingStaked(), ether(8000)); + assert.equal(await autoRouter.getUnderlyingOnAutoFarm(), ether(8320)); + assert.equal(await autoRouter.getPendingRewards(), ether(320)); + assert.equal(await autoRouter.getAutoForShares(ether(320)), ether('332.8')); + + let res = await autoRouter.poke(true, { from: bob }); + expectEvent(res, 'ClaimRewards', { + sender: bob, + expectedAutoReward: ether(320), + releasedAutoReward: ether(320) + }) + + expectEvent(res, 'DistributeRewards', { + sender: bob, + autoReward: ether(320), + pvpReward: ether(48), + poolRewardsUnderlying: ether(272), + poolRewardsPi: ether(272), + pools: [poolA.address, poolB.address, poolC.address], + }); + + assert.equal(await auto.balanceOf(piAuto.address), addBN(ether(2000), ether(272))); + assert.equal(await auto.balanceOf(autoRouter.address), '0'); + + assert.isTrue(parseInt(res.logs[3].args.poolRewardsUnderlying) > 1); + assert.isTrue(parseInt(res.logs[3].args.poolRewardsPi.length) > 1); + + await expectEvent.inTransaction(res.tx, poolA, 'Gulp'); + await expectEvent.inTransaction(res.tx, poolB, 'Gulp'); + await expectEvent.notEmitted.inTransaction(res.tx, poolC, 'Gulp'); + await expectEvent.notEmitted.inTransaction(res.tx, poolD, 'Gulp'); + + assert.equal(res.logs.length, 4); + assert.equal(res.logs[1].args.pool, poolA.address); + assert.equal(res.logs[1].args.amount, '90666666666666666666'); + assert.equal(res.logs[2].args.pool, poolB.address); + assert.equal(res.logs[2].args.amount, '181333333333333333333'); + + assert.equal(await piAuto.balanceOf(poolA.address), 90666666666666666666 + 10); + assert.equal(await piAuto.balanceOf(poolB.address), 181333333333333333333 + 20); + assert.equal(await piAuto.balanceOf(poolC.address), '0'); + assert.equal(await piAuto.balanceOf(poolD.address), '0'); + + assert.equal(await auto.balanceOf(autoRouter.address), '0'); + assert.equal(await auto.balanceOf(autoRouter.address), '0'); + }); + + it('should revert poke if there is no reward available', async () => { + await expectRevert(autoRouter.poke(true, { from: alice }), 'NOTHING_TO_CLAIM'); + }); + + it('should revert poke if there is nothing released', async () => { + const scammyChef = await MockAutoMasterChef.new(auto.address, ether(8320)); + await autoRouter.setReserveConfig(ether(1), 0, { from: piGov }); + await time.increase(time.duration.weeks(1)); + await autoRouter.poke(false); + await autoRouter.setVotingAndStaking(constants.ZERO_ADDRESS, scammyChef.address, { from: piGov }); + await autoRouter.setReserveConfig(ether('0.2'), 0, { from: piGov }); + await autoRouter.poke(false); + await auto.transfer(scammyChef.address, ether(1000)); + await expectRevert(autoRouter.poke(true, { from: alice }), 'NOTHING_RELEASED'); + }); + + it('should revert distributing rewards when missing reward pools config', async () => { + poke = await MockPoke.new(true); + const router = await AutoPowerIndexRouter.new( + piAuto.address, + buildBasicRouterConfig( + poolRestrictions.address, + poke.address, + autoFarm.address, + autoFarm.address, + ether('0.2'), + ether('0.02'), + '0', + pvp, + ether('0.2'), + [], + ), + buildAutoRouterConfig( + auto.address + ), + ); + await autoRouter.migrateToNewRouter(piAuto.address, router.address, [], { from: piGov }); + await auto.transfer(autoStrategy.address, ether(2000)); + await autoStrategy.earn({ from: autoOwner }); + await time.increase(time.duration.weeks(1)); + await expectRevert(router.poke(true, { from: bob }), 'MISSING_REWARD_POOLS'); + }); + }); +}); From bac692d9c69e5bf1bae06c0b40f07e457a18e5d1 Mon Sep 17 00:00:00 2001 From: Poli Paul Date: Mon, 2 Aug 2021 16:59:06 +0200 Subject: [PATCH 08/33] Move Bakery and Pancake Chef mocks to test/bsc --- contracts/test/{ => bsc}/MockBakeryMasterChef.sol | 0 contracts/test/{sushi => bsc}/MockPancakeMasterChef.sol | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename contracts/test/{ => bsc}/MockBakeryMasterChef.sol (100%) rename contracts/test/{sushi => bsc}/MockPancakeMasterChef.sol (100%) diff --git a/contracts/test/MockBakeryMasterChef.sol b/contracts/test/bsc/MockBakeryMasterChef.sol similarity index 100% rename from contracts/test/MockBakeryMasterChef.sol rename to contracts/test/bsc/MockBakeryMasterChef.sol diff --git a/contracts/test/sushi/MockPancakeMasterChef.sol b/contracts/test/bsc/MockPancakeMasterChef.sol similarity index 100% rename from contracts/test/sushi/MockPancakeMasterChef.sol rename to contracts/test/bsc/MockPancakeMasterChef.sol From 00d8063c3f162dc8868bfc657013fd754715e473 Mon Sep 17 00:00:00 2001 From: Poli Paul Date: Mon, 2 Aug 2021 17:26:40 +0200 Subject: [PATCH 09/33] Fix missing compiler version error --- contracts/interfaces/IAutoFarmStrategy.sol | 2 ++ 1 file changed, 2 insertions(+) diff --git a/contracts/interfaces/IAutoFarmStrategy.sol b/contracts/interfaces/IAutoFarmStrategy.sol index 2112805e..bf01ef13 100644 --- a/contracts/interfaces/IAutoFarmStrategy.sol +++ b/contracts/interfaces/IAutoFarmStrategy.sol @@ -1,5 +1,7 @@ // SPDX-License-Identifier: MIT +pragma solidity ^0.6.0; + interface IAutoFarmStrategy { function wantLockedTotal() external view returns (uint256); From accdcdb66759a52f9f334e930309795efd992464 Mon Sep 17 00:00:00 2001 From: Poli Paul Date: Mon, 2 Aug 2021 19:07:03 +0200 Subject: [PATCH 10/33] Remove MockERC20 ownable checks --- contracts/test/MockERC20.sol | 2 -- 1 file changed, 2 deletions(-) diff --git a/contracts/test/MockERC20.sol b/contracts/test/MockERC20.sol index 0da0bb84..26cb39cf 100644 --- a/contracts/test/MockERC20.sol +++ b/contracts/test/MockERC20.sol @@ -20,12 +20,10 @@ contract MockERC20 is ERC20 { } function mint(address account, uint256 amount) public { - require(msg.sender == tx.origin, "MockERC20: mint from non-EOA"); _mint(account, amount); } function burn(uint256 amount) public { - require(msg.sender == tx.origin, "MockERC20: burn from non-EOA"); _burn(msg.sender, amount); } } From ca72436c27139098f07f13a4cd12c0e0bd8e6e34 Mon Sep 17 00:00:00 2001 From: Poli Paul Date: Thu, 19 Aug 2021 09:19:21 +0200 Subject: [PATCH 11/33] Add BSC:Venus Router --- assets/bsc/ComptrollerV1.json | 1094 +++++++++++++++++ assets/bsc/ComptrollerV4.json | 4 + assets/bsc/Unitroller.json | 125 ++ assets/bsc/VBep20Delegate.json | 700 +++++++++++ assets/bsc/VBep20Delegator.json | 696 +++++++++++ assets/bsc/WhitePaperInterestRateModel.json | 99 ++ .../interfaces/WrappedPiErc20Interface.sol | 4 +- .../interfaces/venus/VBep20Interface.sol | 25 + .../venus/VenusComptrollerInterface.sol | 27 + .../PowerIndexBasicRouter.sol | 23 +- .../powerindex-router/WrappedPiErc20.sol | 18 +- .../VenusVBep20SupplyRouter.sol | 286 +++++ contracts/test/MockOracle.sol | 9 + test/helpers/builders.js | 6 + test/helpers/index.js | 47 +- .../implementations/VenusRouter.unit.js | 687 +++++++++++ 16 files changed, 3831 insertions(+), 19 deletions(-) create mode 100644 assets/bsc/ComptrollerV1.json create mode 100644 assets/bsc/ComptrollerV4.json create mode 100644 assets/bsc/Unitroller.json create mode 100644 assets/bsc/VBep20Delegate.json create mode 100644 assets/bsc/VBep20Delegator.json create mode 100644 assets/bsc/WhitePaperInterestRateModel.json create mode 100644 contracts/interfaces/venus/VBep20Interface.sol create mode 100644 contracts/interfaces/venus/VenusComptrollerInterface.sol create mode 100644 contracts/powerindex-router/implementations/VenusVBep20SupplyRouter.sol create mode 100644 test/router/implementations/VenusRouter.unit.js diff --git a/assets/bsc/ComptrollerV1.json b/assets/bsc/ComptrollerV1.json new file mode 100644 index 00000000..0134303d --- /dev/null +++ b/assets/bsc/ComptrollerV1.json @@ -0,0 +1,1094 @@ +{ + "bytecode": "608060405234801561001057600080fd5b50600080546001600160a01b03191633179055615eca80620000336000396000f3fe608060405234801561001057600080fd5b50600436106104a05760003560e01c80636d35bf911161026d578063bdcdc25811610151578063dce15449116100ce578063e6de652811610092578063e6de6528146111a9578063e8755446146111c6578063eabe7d91146111ce578063ede4edd014611204578063f851a4401461122a578063fd51a3ad14611232576104a0565b8063dce154491461111b578063dcfbc0c714611147578063e37d4b791461114f578063e4028eee14611175578063e6653f3d146111a1576104a0565b8063c5b4db5511610115578063c5b4db5514610f32578063d02f735114610f56578063d09c54ba14610f9c578063d9226ced146110c8578063da3d454c146110e5576104a0565b8063bdcdc25814610e42578063bec04f7214610e7e578063bf32442d14610e86578063c299823814610e8e578063c488847b14610efc576104a0565b80639254f5e5116101ea578063abfceffc116101ae578063abfceffc14610d40578063ac0b0bb714610db6578063adcd5fb914610dbe578063b0772d0b14610de4578063b8324c7c14610dec578063bb82aa5e14610e3a576104a0565b80639254f5e514610cb6578063929fe9a114610cbe57806394b2294b14610cec5780639cfdd9e614610cf4578063a76b3fda14610d1a576104a0565b806386df31ee1161023157806386df31ee14610b87578063879c2e1d14610c3857806387f7630314610c405780638a7dc16514610c485780638e8f294b14610c6e576104a0565b80636d35bf9114610aee5780636fe74a2114610b34578063731f0c2b14610b515780637655138314610b775780637dc0d1d014610b7f576104a0565b806341c728b9116103945780634fd42e17116103115780635c778605116102d55780635c778605146109e25780635ec88c7914610a185780635fc7e71e14610a3e57806365af42e314610a845780636a56947e14610a8c5780636d154ea514610ac8576104a0565b80634fd42e17146109295780635035920a1461094657806351dff9891461096357806352d84d1e1461099f57806355ee1fe1146109bc576104a0565b80634712ee7d116103585780634712ee7d1461082857806347ef3b3b146108455780634ada90af146108915780634e79238f146108995780634ef4c3e1146108f3576104a0565b806341c728b914610748578063425fad581461078457806342cbb15c1461078c57806343eb1b641461079457806344927f4914610802576104a0565b806326782247116104225780633785d1d6116103e65780633785d1d6146106c3578063399cc80c146107025780633c94786f1461070a5780634088c73e1461071257806341a18d2c1461071a576104a0565b8063267822471461063c5780632a6a6065146106445780632bc7e29e146106635780632ec0412414610689578063317b0b77146106a6576104a0565b80631d504dc6116104695780631d504dc6146105575780631ededc911461057d57806320fa42b1146105bf57806324008a62146105dc57806324a3d62214610618576104a0565b80627e3dd2146104a557806308e0225c146104c157806312a2adc7146105015780631abcaa771461050b5780631cb8126e14610531575b600080fd5b6104ad61125e565b604080519115158252519081900360200190f35b6104ef600480360360408110156104d757600080fd5b506001600160a01b0381358116916020013516611263565b60408051918252519081900360200190f35b610509611280565b005b6104ef6004803603602081101561052157600080fd5b50356001600160a01b03166112c8565b6105096004803603602081101561054757600080fd5b50356001600160a01b03166112da565b6105096004803603602081101561056d57600080fd5b50356001600160a01b03166113ef565b610509600480360360a081101561059357600080fd5b506001600160a01b0381358116916020810135821691604082013516906060810135906080013561155d565b610509600480360360208110156105d557600080fd5b5035611564565b6104ef600480360360808110156105f257600080fd5b506001600160a01b038135811691602081013582169160408201351690606001356115ff565b610620611717565b604080516001600160a01b039092168252519081900360200190f35b610620611726565b6104ad6004803603602081101561065a57600080fd5b50351515611735565b6104ef6004803603602081101561067957600080fd5b50356001600160a01b03166117dc565b6104ef6004803603602081101561069f57600080fd5b50356117ee565b6104ef600480360360208110156106bc57600080fd5b5035611861565b6106e9600480360360208110156106d957600080fd5b50356001600160a01b031661196b565b6040805192835260208301919091528051918290030190f35b6104ef6119f5565b6104ad6119fb565b6104ad611a0b565b6104ef6004803603604081101561073057600080fd5b506001600160a01b0381358116916020013516611a14565b6105096004803603608081101561075e57600080fd5b506001600160a01b03813581169160208101359091169060408101359060600135611a31565b6104ad611a37565b6104ef611a46565b610509600480360360208110156107aa57600080fd5b810190602081018135600160201b8111156107c457600080fd5b8201836020820111156107d657600080fd5b803590602001918460208302840111600160201b831117156107f757600080fd5b509092509050611a4b565b6104ef6004803603602081101561081857600080fd5b50356001600160a01b0316611adb565b6104ef6004803603602081101561083e57600080fd5b5035611af6565b610509600480360360c081101561085b57600080fd5b506001600160a01b0381358116916020810135821691604082013581169160608101359091169060808101359060a00135611c2a565b6104ef611c32565b6108d5600480360360808110156108af57600080fd5b506001600160a01b03813581169160208101359091169060408101359060600135611c38565b60408051938452602084019290925282820152519081900360600190f35b6104ef6004803603606081101561090957600080fd5b506001600160a01b03813581169160208101359091169060400135611c72565b6104ef6004803603602081101561093f57600080fd5b5035611d69565b6105096004803603602081101561095c57600080fd5b5035611e5d565b6105096004803603608081101561097957600080fd5b506001600160a01b03813581169160208101359091169060408101359060600135611f3b565b610620600480360360208110156109b557600080fd5b5035611f8c565b6104ef600480360360208110156109d257600080fd5b50356001600160a01b0316611fb3565b610509600480360360608110156109f857600080fd5b506001600160a01b03813581169160208101359091169060400135611f36565b6108d560048036036020811015610a2e57600080fd5b50356001600160a01b0316612038565b6104ef600480360360a0811015610a5457600080fd5b506001600160a01b038135811691602081013582169160408201358116916060810135909116906080013561206d565b6104ef612248565b61050960048036036080811015610aa257600080fd5b506001600160a01b03813581169160208101358216916040820135169060600135612253565b6104ad60048036036020811015610ade57600080fd5b50356001600160a01b0316612258565b610509600480360360a0811015610b0457600080fd5b506001600160a01b038135811691602081013582169160408201358116916060810135909116906080013561155d565b6104ef60048036036020811015610b4a57600080fd5b503561226d565b6104ad60048036036020811015610b6757600080fd5b50356001600160a01b0316612375565b6104ad61238a565b610620612398565b61050960048036036040811015610b9d57600080fd5b6001600160a01b038235169190810190604081016020820135600160201b811115610bc757600080fd5b820183602082011115610bd957600080fd5b803590602001918460208302840111600160201b83111715610bfa57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295506123a7945050505050565b6104ef612404565b6104ad61240a565b6104ef60048036036020811015610c5e57600080fd5b50356001600160a01b031661241a565b610c9460048036036020811015610c8457600080fd5b50356001600160a01b031661242c565b6040805193151584526020840192909252151582820152519081900360600190f35b610620612452565b6104ad60048036036040811015610cd457600080fd5b506001600160a01b0381358116916020013516612461565b6104ef612495565b6104ef60048036036020811015610d0a57600080fd5b50356001600160a01b031661249b565b6104ef60048036036020811015610d3057600080fd5b50356001600160a01b031661251f565b610d6660048036036020811015610d5657600080fd5b50356001600160a01b031661267c565b60408051602080825283518183015283519192839290830191858101910280838360005b83811015610da2578181015183820152602001610d8a565b505050509050019250505060405180910390f35b6104ad6126f2565b61050960048036036020811015610dd457600080fd5b50356001600160a01b0316612702565b610d66612766565b610e1260048036036020811015610e0257600080fd5b50356001600160a01b03166127c8565b604080516001600160e01b03909316835263ffffffff90911660208301528051918290030190f35b6106206127f2565b6104ef60048036036080811015610e5857600080fd5b506001600160a01b03813581169160208101358216916040820135169060600135612801565b6104ef6128e1565b6106206128e7565b610d6660048036036020811015610ea457600080fd5b810190602081018135600160201b811115610ebe57600080fd5b820183602082011115610ed057600080fd5b803590602001918460208302840111600160201b83111715610ef157600080fd5b5090925090506128ff565b6106e960048036036060811015610f1257600080fd5b506001600160a01b03813581169160208101359091169060400135612995565b610f3a612c0a565b604080516001600160e01b039092168252519081900360200190f35b6104ef600480360360a0811015610f6c57600080fd5b506001600160a01b0381358116916020810135821691604082013581169160608101359091169060800135612c1d565b61050960048036036080811015610fb257600080fd5b810190602081018135600160201b811115610fcc57600080fd5b820183602082011115610fde57600080fd5b803590602001918460208302840111600160201b83111715610fff57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b81111561104e57600080fd5b82018360208201111561106057600080fd5b803590602001918460208302840111600160201b8311171561108157600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550505050803515159150602001351515612e21565b6104ef600480360360208110156110de57600080fd5b5035613000565b6104ef600480360360608110156110fb57600080fd5b506001600160a01b03813581169160208101359091169060400135613069565b6106206004803603604081101561113157600080fd5b506001600160a01b038135169060200135613372565b6106206133a7565b610e126004803603602081101561116557600080fd5b50356001600160a01b03166133b6565b6104ef6004803603604081101561118b57600080fd5b506001600160a01b0381351690602001356133e0565b6104ad613590565b610509600480360360208110156111bf57600080fd5b50356135a0565b6104ef613637565b6104ef600480360360608110156111e457600080fd5b506001600160a01b0381358116916020810135909116906040013561363d565b6104ef6004803603602081101561121a57600080fd5b50356001600160a01b03166136c8565b610620613984565b6104ef6004803603604081101561124857600080fd5b506001600160a01b038135169060200135613993565b600181565b601360209081526000928352604080842090915290825290205481565b3332146112be5760405162461bcd60e51b8152600401808060200182810382526022815260200180615e746022913960400191505060405180910390fd5b6112c6613a7e565b565b600f6020526000908152604090205481565b6000546001600160a01b0316331461132a576040805162461bcd60e51b815260206004820152600e60248201526d37b7363c9030b236b4b71031b0b760911b604482015290519081900360640190fd5b6001600160a01b0381166000908152600960205260409020600381015460ff161515600114611393576040805162461bcd60e51b815260206004820152601060248201526f1b9bdd081d995b9d5cc81b585c9ad95d60821b604482015290519081900360640190fd5b60038101805460ff19169055604080516001600160a01b03841681526000602082015281517f5f4087bd98874c2fa3ea4474bc7c58b711b23fff45cd2f456e358b4b33ee9025929181900390910190a16113eb613a7e565b5050565b806001600160a01b031663f851a4406040518163ffffffff1660e01b815260040160206040518083038186803b15801561142857600080fd5b505afa15801561143c573d6000803e3d6000fd5b505050506040513d602081101561145257600080fd5b50516001600160a01b031633146114b0576040805162461bcd60e51b815260206004820152601960248201527f6f6e6c7920756e6974726f6c6c65722061646d696e2063616e00000000000000604482015290519081900360640190fd5b806001600160a01b031663c1e803346040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156114eb57600080fd5b505af11580156114ff573d6000803e3d6000fd5b505050506040513d602081101561151557600080fd5b50511561155a576040805162461bcd60e51b815260206004820152600e60248201526d1b9bdd08185d5d1a1bdc9a5e995960921b604482015290519081900360640190fd5b50565b5050505050565b6000546001600160a01b031633146115b4576040805162461bcd60e51b815260206004820152600e60248201526d37b7363c9030b236b4b71031b0b760911b604482015290519081900360640190fd5b600e805490829055604080518281526020810184905281517f5c37806eedc7b8c869503478c1753afec9fe3a9847d6b4ff288080bebe15dd34929181900390910190a16113eb613a7e565b60185460009062010000900460ff161561164e576040805162461bcd60e51b81526020600482015260126024820152600080516020615e54833981519152604482015290519081900360640190fd5b6001600160a01b03851660009081526009602052604090205460ff166116765750600961170f565b61167e615d94565b6040518060200160405280876001600160a01b031663aa5af0fd6040518163ffffffff1660e01b815260040160206040518083038186803b1580156116c257600080fd5b505afa1580156116d6573d6000803e3d6000fd5b505050506040513d60208110156116ec57600080fd5b5051905290506116fc8682613dfa565b611709868583600061408e565b60009150505b949350505050565b600a546001600160a01b031681565b6001546001600160a01b031681565b600080546001600160a01b03163314611786576040805162461bcd60e51b815260206004820152600e60248201526d37b7363c9030b236b4b71031b0b760911b604482015290519081900360640190fd5b6018805483151562010000810262ff0000199092169190911790915560408051918252517fd7500633dd3ddd74daa7af62f8c8404c7fe4a81da179998db851696bed004b389181900360200190a150805b919050565b60166020526000908152604090205481565b600080546001600160a01b031633146118145761180d60016014614279565b90506117d7565b6017805490839055604080518281526020810185905281517f73747d68b346dce1e932bcd238282e7ac84c01569e1f8d0469c222fdc6e9d5a4929181900390910190a160005b9392505050565b600080546001600160a01b031633146118805761180d60016004614279565b611888615d94565b50604080516020810190915282815261189f615d94565b50604080516020810190915266b1a2bc2ec5000081526118bf82826142df565b156118d8576118cf600580614279565b925050506117d7565b6118e0615d94565b506040805160208101909152670c7d713b49da0000815261190181846142e7565b1561191b57611911600580614279565b93505050506117d7565b6005805490869055604080518281526020810188905281517f3b9670cf975d26958e754b57098eaa2ac914d8d2a31b83257997b9f346110fd9929181900390910190a160005b9695505050505050565b60155460408051631bc2e8eb60e11b81526001600160a01b03848116600483015282516000948594921692633785d1d6926024808301939192829003018186803b1580156119b857600080fd5b505afa1580156119cc573d6000803e3d6000fd5b505050506040513d60408110156119e257600080fd5b5080516020909101519092509050915091565b60195481565b600a54600160a01b900460ff1681565b60185460ff1681565b601260209081526000928352604080842090915290825290205481565b50505050565b60185462010000900460ff1681565b435b90565b6000546001600160a01b03163314611a9b576040805162461bcd60e51b815260206004820152600e60248201526d37b7363c9030b236b4b71031b0b760911b604482015290519081900360640190fd5b60005b81811015611ad257611aca838383818110611ab557fe5b905060200201356001600160a01b03166142ee565b600101611a9e565b506113eb613a7e565b6001600160a01b031660009081526016602052604090205490565b60185460009062010000900460ff1615611b45576040805162461bcd60e51b81526020600482015260126024820152600080516020615e54833981519152604482015290519081900360640190fd5b60185460ff1615611b91576040805162461bcd60e51b81526020600482015260116024820152701b5a5b9d159052481a5cc81c185d5cd959607a1b604482015290519081900360640190fd5b611b9961460f565b611ba433600061469a565b60155460408051630d00083160e01b81523360048201526024810185905290516001600160a01b0390921691630d000831916044808201926020929091908290030181600087803b158015611bf857600080fd5b505af1158015611c0c573d6000803e3d6000fd5b505050506040513d6020811015611c2257600080fd5b505192915050565b505050505050565b60065481565b600080600080600080611c4d8a8a8a8a6147c8565b925092509250826013811115611c5f57fe5b95509093509150505b9450945094915050565b60185460009062010000900460ff1615611cc1576040805162461bcd60e51b81526020600482015260126024820152600080516020615e54833981519152604482015290519081900360640190fd5b6001600160a01b0384166000908152600b602052604090205460ff1615611d20576040805162461bcd60e51b815260206004820152600e60248201526d1b5a5b9d081a5cc81c185d5cd95960921b604482015290519081900360640190fd5b6001600160a01b03841660009081526009602052604090205460ff16611d4a5760095b905061185a565b611d5384614c45565b611d5f84846000614ecf565b6000949350505050565b600080546001600160a01b03163314611d885761180d6001600b614279565b611d90615d94565b506040805160208101909152828152611da7615d94565b506040805160208101909152670de0b6b3a76400008152611dc882826142e7565b15611dd9576118cf6007600c614279565b611de1615d94565b5060408051602081019091526714d1120d7b1600008152611e0281846142e7565b15611e13576119116007600c614279565b6006805490869055604080518281526020810188905281517faeba5a6c40a8ac138134bff1aaa65debf25971188a58804bad717f82f0ec1316929181900390910190a16000611961565b6000546001600160a01b03163314611ead576040805162461bcd60e51b815260206004820152600e60248201526d37b7363c9030b236b4b71031b0b760911b604482015290519081900360640190fd5b6015546001600160a01b03161561155a576015546040805163281ac90560e11b81526004810184905290516001600160a01b0390921691635035920a916024808201926020929091908290030181600087803b158015611f0c57600080fd5b505af1158015611f20573d6000803e3d6000fd5b505050506040513d6020811015611f3657600080fd5b505050565b80151580611f47575081155b611a31576040805162461bcd60e51b815260206004820152601160248201527072656465656d546f6b656e73207a65726f60781b604482015290519081900360640190fd5b600d8181548110611f9957fe5b6000918252602090912001546001600160a01b0316905081565b600080546001600160a01b03163314611fd25761180d60016010614279565b600480546001600160a01b038481166001600160a01b0319831681179093556040805191909216808252602082019390935281517fd52b2b9b7e9ee655fcb95d2e5b9e0c9f69e7ef2b8e9d2d0ea78402d576d22e22929181900390910190a1600061185a565b60008060008060008061204f8760008060006147c8565b92509250925082601381111561206157fe5b97919650945092505050565b60185460009062010000900460ff16156120bc576040805162461bcd60e51b81526020600482015260126024820152600080516020615e54833981519152604482015290519081900360640190fd5b6001600160a01b03861660009081526009602052604090205460ff1615806120fd57506001600160a01b03851660009081526009602052604090205460ff16155b1561210c5760095b905061223f565b60008061211d8560008060006147c8565b9193509091506000905082601381111561213357fe5b1461214d5781601381111561214457fe5b9250505061223f565b80612159576003612144565b6000886001600160a01b03166395dd9193876040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b1580156121b157600080fd5b505afa1580156121c5573d6000803e3d6000fd5b505050506040513d60208110156121db57600080fd5b50516040805160208101909152600554815290915060009081906121ff90846150c7565b9092509050600082600381111561221257fe5b1461222657600b5b9550505050505061223f565b8087111561223557601161221a565b6000955050505050505b95945050505050565b66038d7ea4c6800081565b611a31565b600c6020526000908152604090205460ff1681565b60185460009062010000900460ff16156122bc576040805162461bcd60e51b81526020600482015260126024820152600080516020615e54833981519152604482015290519081900360640190fd5b601854610100900460ff161561230e576040805162461bcd60e51b81526020600482015260126024820152711c995c185e559052481a5cc81c185d5cd95960721b604482015290519081900360640190fd5b61231661460f565b61232133600061469a565b6015546040805163bca07ad560e01b81523360048201526024810185905290516001600160a01b039092169163bca07ad5916044808201926020929091908290030181600087803b158015611bf857600080fd5b600b6020526000908152604090205460ff1681565b601854610100900460ff1681565b6004546001600160a01b031681565b6040805160018082528183019092526060916020808301908038833901905050905082816000815181106123d757fe5b60200260200101906001600160a01b031690816001600160a01b031681525050611f368183600180612e21565b600e5481565b600a54600160b01b900460ff1681565b60146020526000908152604090205481565b60096020526000908152604090208054600182015460039092015460ff91821692911683565b6015546001600160a01b031681565b6001600160a01b038082166000908152600960209081526040808320938616835260029093019052205460ff165b92915050565b60075481565b600080546001600160a01b031633146124ba5761180d60016015614279565b601580546001600160a01b038481166001600160a01b0319831681179093556040805191909216808252602082019390935281517fe1ddcb2dab8e5b03cfc8c67a0d5861d91d16f7bd2612fd381faf4541d212c9b2929181900390910190a150919050565b600080546001600160a01b0316331461253e5761180d60016012614279565b6001600160a01b03821660009081526009602052604090205460ff161561256b5761180d600a6011614279565b816001600160a01b0316633d9ea3a16040518163ffffffff1660e01b815260040160206040518083038186803b1580156125a457600080fd5b505afa1580156125b8573d6000803e3d6000fd5b505050506040513d60208110156125ce57600080fd5b5050604080516060810182526001808252600060208381018281528486018381526001600160a01b03891684526009909252949091209251835490151560ff199182161784559351918301919091555160039091018054911515919092161790556126388261511b565b604080516001600160a01b038416815290517fcf583bb0c569eb967f806b11601c4cb93c10310485c67add5f8362c2f212321f9181900360200190a1600092915050565b6001600160a01b0381166000908152600860209081526040918290208054835181840281018401909452808452606093928301828280156126e657602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116126c8575b50505050509050919050565b600a54600160b81b900460ff1681565b61155a81600d80548060200260200160405190810160405280929190818152602001828054801561275c57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161273e575b50505050506123a7565b6060600d8054806020026020016040519081016040528092919081815260200182805480156127be57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116127a0575b5050505050905090565b6010602052600090815260409020546001600160e01b03811690600160e01b900463ffffffff1682565b6002546001600160a01b031681565b60185460009062010000900460ff1615612850576040805162461bcd60e51b81526020600482015260126024820152600080516020615e54833981519152604482015290519081900360640190fd5b600a54600160b01b900460ff16156128a4576040805162461bcd60e51b81526020600482015260126024820152711d1c985b9cd9995c881a5cc81c185d5cd95960721b604482015290519081900360640190fd5b60006128b18686856151f9565b905080156128c057905061170f565b6128c986614c45565b6128d586866000614ecf565b61170986856000614ecf565b60175481565b73cf6bb5389c92bdda8a3747ddb454cb7a64626c6390565b6040805182815260208084028201019091526060908290829082801561292f578160200160208202803883390190505b50905060005b8281101561298c5761296286868381811061294c57fe5b905060200201356001600160a01b03163361529c565b601381111561296d57fe5b82828151811061297957fe5b6020908102919091010152600101612935565b50949350505050565b600480546040805163fc57d4df60e01b81526001600160a01b038781169482019490945290516000938493849391169163fc57d4df91602480820192602092909190829003018186803b1580156129eb57600080fd5b505afa1580156129ff573d6000803e3d6000fd5b505050506040513d6020811015612a1557600080fd5b5051600480546040805163fc57d4df60e01b81526001600160a01b038a8116948201949094529051939450600093929091169163fc57d4df91602480820192602092909190829003018186803b158015612a6e57600080fd5b505afa158015612a82573d6000803e3d6000fd5b505050506040513d6020811015612a9857600080fd5b50519050811580612aa7575080155b15612abc57600d935060009250612c02915050565b6000866001600160a01b031663182df0f56040518163ffffffff1660e01b815260040160206040518083038186803b158015612af757600080fd5b505afa158015612b0b573d6000803e3d6000fd5b505050506040513d6020811015612b2157600080fd5b505190506000612b2f615d94565b612b37615d94565b612b3f615d94565b6000612b4d600654896153b8565b945090506000816003811115612b5f57fe5b14612b7b57600b5b995060009850612c02975050505050505050565b612b8587876153b8565b935090506000816003811115612b9757fe5b14612ba357600b612b67565b612bad84846153f3565b925090506000816003811115612bbf57fe5b14612bcb57600b612b67565b612bd5828c6150c7565b955090506000816003811115612be757fe5b14612bf357600b612b67565b60009950939750505050505050505b935093915050565b6ec097ce7bc90715b34b9f100000000081565b60185460009062010000900460ff1615612c6c576040805162461bcd60e51b81526020600482015260126024820152600080516020615e54833981519152604482015290519081900360640190fd5b600a54600160b81b900460ff1615612cbd576040805162461bcd60e51b815260206004820152600f60248201526e1cd95a5e99481a5cc81c185d5cd959608a1b604482015290519081900360640190fd5b6001600160a01b03861660009081526009602052604090205460ff161580612cfe57506001600160a01b03851660009081526009602052604090205460ff16155b15612d0a576009612105565b846001600160a01b0316635fe3b5676040518163ffffffff1660e01b815260040160206040518083038186803b158015612d4357600080fd5b505afa158015612d57573d6000803e3d6000fd5b505050506040513d6020811015612d6d57600080fd5b505160408051635fe3b56760e01b815290516001600160a01b0392831692891691635fe3b567916004808301926020929190829003018186803b158015612db357600080fd5b505afa158015612dc7573d6000803e3d6000fd5b505050506040513d6020811015612ddd57600080fd5b50516001600160a01b031614612df4576002612105565b612dfd86614c45565b612e0986846000614ecf565b612e1586856000614ecf565b60009695505050505050565b6000612e2b61460f565b5060005b8451811015612e5e57612e56858281518110612e4757fe5b6020026020010151600161469a565b600101612e2f565b60005b8451811015611c2a576000858281518110612e7857fe5b6020908102919091018101516001600160a01b0381166000908152600990925260409091205490915060ff16612ee9576040805162461bcd60e51b81526020600482015260116024820152701b9bdd081b1a5cdd1959081b585c9ad95d607a1b604482015290519081900360640190fd5b8415612fb057612ef7615d94565b6040518060200160405280836001600160a01b031663aa5af0fd6040518163ffffffff1660e01b815260040160206040518083038186803b158015612f3b57600080fd5b505afa158015612f4f573d6000803e3d6000fd5b505050506040513d6020811015612f6557600080fd5b505190529050612f758282613dfa565b600093505b8751841015612fae57612fa382898681518110612f9357fe5b602002602001015183600161408e565b600190930192612f7a565b505b8315612ff757612fbf81614c45565b600092505b8651831015612ff757612fec81888581518110612fdd57fe5b60200260200101516001614ecf565b600190920191612fc4565b50600101612e61565b600080546001600160a01b0316331461301f5761180d6001600d614279565b6007805490839055604080518281526020810185905281517f7093cf1eb653f749c3ff531d6df7f92764536a7fa0d13530cd26e070780c32ea929181900390910190a1600061185a565b60185460009062010000900460ff16156130b8576040805162461bcd60e51b81526020600482015260126024820152600080516020615e54833981519152604482015290519081900360640190fd5b6001600160a01b0384166000908152600c602052604090205460ff1615613119576040805162461bcd60e51b815260206004820152601060248201526f189bdc9c9bddc81a5cc81c185d5cd95960821b604482015290519081900360640190fd5b6001600160a01b03841660009081526009602052604090205460ff16613140576009611d43565b6001600160a01b038085166000908152600960209081526040808320938716835260029093019052205460ff166131fd57336001600160a01b038516146131c6576040805162461bcd60e51b815260206004820152601560248201527439b2b73232b91036bab9ba103132903b2a37b5b2b760591b604482015290519081900360640190fd5b60006131d2858561529c565b905060008160138111156131e257fe5b146131fb578060138111156131f357fe5b91505061185a565b505b600480546040805163fc57d4df60e01b81526001600160a01b03888116948201949094529051929091169163fc57d4df91602480820192602092909190829003018186803b15801561324e57600080fd5b505afa158015613262573d6000803e3d6000fd5b505050506040513d602081101561327857600080fd5b505161328557600d611d43565b60008061329585876000876147c8565b919350909150600090508260138111156132ab57fe5b146132c5578160138111156132bc57fe5b9250505061185a565b80156132d25760046132bc565b6132da615d94565b6040518060200160405280886001600160a01b031663aa5af0fd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561331e57600080fd5b505afa158015613332573d6000803e3d6000fd5b505050506040513d602081101561334857600080fd5b5051905290506133588782613dfa565b613365878783600061408e565b6000979650505050505050565b6008602052816000526040600020818154811061338b57fe5b6000918252602090912001546001600160a01b03169150829050565b6003546001600160a01b031681565b6011602052600090815260409020546001600160e01b03811690600160e01b900463ffffffff1682565b600080546001600160a01b03163314613406576133ff60016006614279565b905061248f565b6001600160a01b0383166000908152600960205260409020805460ff1661343b5761343360096007614279565b91505061248f565b613443615d94565b50604080516020810190915283815261345a615d94565b506040805160208101909152670c7d713b49da0000815261347b81836142e7565b156134965761348c60066008614279565b935050505061248f565b841580159061351f5750600480546040805163fc57d4df60e01b81526001600160a01b038a8116948201949094529051929091169163fc57d4df91602480820192602092909190829003018186803b1580156134f157600080fd5b505afa158015613505573d6000803e3d6000fd5b505050506040513d602081101561351b57600080fd5b5051155b156135305761348c600d6009614279565b60018301805490869055604080516001600160a01b03891681526020810183905280820188905290517f70483e6592cd5182d45ac970e05bc62cdcc90e9d8ef2c2dbe686cf383bcd7fc59181900360600190a16000979650505050505050565b600a54600160a81b900460ff1681565b6000546001600160a01b031633146135f0576040805162461bcd60e51b815260206004820152600e60248201526d37b7363c9030b236b4b71031b0b760911b604482015290519081900360640190fd5b6019805490829055604080518281526020810184905281517f75c84862cb29e997a2ed3ab3c3db0f5af24a181e6bf58897c5ea676668511c19929181900390910190a15050565b60055481565b60185460009062010000900460ff161561368c576040805162461bcd60e51b81526020600482015260126024820152600080516020615e54833981519152604482015290519081900360640190fd5b60006136998585856151f9565b905080156136a857905061185a565b6136b185614c45565b6136bd85856000614ecf565b600095945050505050565b6000808290506000806000836001600160a01b031663c37f68e2336040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060806040518083038186803b15801561372957600080fd5b505afa15801561373d573d6000803e3d6000fd5b505050506040513d608081101561375357600080fd5b5080516020820151604090920151909450909250905082156137bc576040805162461bcd60e51b815260206004820152601960248201527f6765744163636f756e74536e617073686f74206661696c656400000000000000604482015290519081900360640190fd5b80156137d9576137ce600c6002614279565b9450505050506117d7565b60006137e68733856151f9565b90508015613807576137fb600e60038361540b565b955050505050506117d7565b6001600160a01b0385166000908152600960209081526040808320338452600281019092529091205460ff1661384657600096505050505050506117d7565b3360009081526002820160209081526040808320805460ff1916905560089091528120805490915b8181101561392757886001600160a01b031683828154811061388c57fe5b6000918252602090912001546001600160a01b0316141561391f578260018303815481106138b657fe5b9060005260206000200160009054906101000a90046001600160a01b03168382815481106138e057fe5b600091825260209091200180546001600160a01b0319166001600160a01b03929092169190911790558254613919846000198301615da7565b50613927565b60010161386e565b81811061393057fe5b604080516001600160a01b038b16815233602082015281517fe699a64c18b07ac5b7301aa273f36a2287239eb9501d81950672794afba29a0d929181900390910190a160009b9a5050505050505050505050565b6000546001600160a01b031681565b60185460009062010000900460ff16156139e2576040805162461bcd60e51b81526020600482015260126024820152600080516020615e54833981519152604482015290519081900360640190fd5b60185460ff161580156139fd5750601854610100900460ff16155b613a3e576040805162461bcd60e51b815260206004820152600d60248201526c159052481a5cc81c185d5cd959609a1b604482015290519081900360640190fd5b6015546001600160a01b03163314613a5c576133ff600e6016614279565b6001600160a01b03831660009081526016602052604081208390559392505050565b6000805b600d54821015613b4b57600d8281548110613a9957fe5b6000918252602090912001546001600160a01b03169050613ab8615d94565b6040518060200160405280836001600160a01b031663aa5af0fd6040518163ffffffff1660e01b815260040160206040518083038186803b158015613afc57600080fd5b505afa158015613b10573d6000803e3d6000fd5b505050506040513d6020811015613b2657600080fd5b505190529050613b3582614c45565b613b3f8282613dfa565b50600190910190613a82565b613b53615d94565b6040518060200160405280600081525090506060600d80549050604051908082528060200260200182016040528015613ba657816020015b613b93615d94565b815260200190600190039081613b8b5790505b509050600093505b600d54841015613d2f57600d8481548110613bc557fe5b60009182526020808320909101546001600160a01b0316808352600990915260409091206003015490935060ff1615613d2457613c00615d94565b60408051602080820180845260045463fc57d4df60e01b9091526001600160a01b03888116602485015293519293849391169163fc57d4df916044808601929190818703018186803b158015613c5557600080fd5b505afa158015613c69573d6000803e3d6000fd5b505050506040513d6020811015613c7f57600080fd5b505190529050613c8d615d94565b613cfb82866001600160a01b03166347bd37186040518163ffffffff1660e01b815260040160206040518083038186803b158015613cca57600080fd5b505afa158015613cde573d6000803e3d6000fd5b505050506040513d6020811015613cf457600080fd5b5051615471565b905080838781518110613d0a57fe5b6020026020010181905250613d1f848261549b565b935050505b600190930192613bae565b600093505b600d54841015611a3157600d8481548110613d4b57fe5b600091825260208220015483516001600160a01b039091169450613d70576000613d98565b613d98600e54613d93848881518110613d8557fe5b6020026020010151866154c0565b6154f3565b6001600160a01b0385166000818152600f60209081526040918290208490558151848152915193945091927f2a0ce45ba05a83e75ba21e1a10d6b48a8395028cc6e1ae66f6c313648379d548929181900390910190a250600190930192613d34565b6001600160a01b0382166000908152601160209081526040808320600f9092528220549091613e27611a46565b8354909150600090613e47908390600160e01b900463ffffffff1661551b565b9050600081118015613e595750600083115b15614029576000613ece876001600160a01b03166347bd37186040518163ffffffff1660e01b815260040160206040518083038186803b158015613e9c57600080fd5b505afa158015613eb0573d6000803e3d6000fd5b505050506040513d6020811015613ec657600080fd5b505187615555565b90506000613edc8386615573565b9050613ee6615d94565b60008311613f035760405180602001604052806000815250613f0d565b613f0d82846155b5565b9050613f17615d94565b604080516020810190915288546001600160e01b03168152613f39908361549b565b90506040518060400160405280613f7f8360000151604051806040016040528060138152602001726e657720696e646578206f766572666c6f777360681b8152506155ea565b6001600160e01b03168152602001613fc58860405180604001604052806016815260200175626c6f636b206e756d626572206f766572666c6f777360501b815250615684565b63ffffffff9081169091526001600160a01b038c166000908152601160209081526040909120835181549490920151909216600160e01b026001600160e01b039182166001600160e01b0319909416939093171691909117905550611c2a92505050565b8015611c2a576140678260405180604001604052806016815260200175626c6f636b206e756d626572206f766572666c6f777360501b815250615684565b845463ffffffff91909116600160e01b026001600160e01b03909116178455505050505050565b6001600160a01b03841660009081526011602052604090206140ae615d94565b50604080516020810190915281546001600160e01b031681526140cf615d94565b5060408051602080820183526001600160a01b03808a16600090815260138352848120918a16808252828452948120805485528651959091529152919091558051156142705761411d615d94565b61412783836156d9565b905060006141b6896001600160a01b03166395dd91938a6040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561418457600080fd5b505afa158015614198573d6000803e3d6000fd5b505050506040513d60208110156141ae57600080fd5b505188615555565b905060006141c482846156fe565b6001600160a01b038a16600090815260146020526040812054919250906141eb908361571e565b905061420c8a828a6142045766038d7ea4c68000614207565b60005b615754565b6001600160a01b03808c1660008181526014602090815260409182902094909455895181518781529485015280519193928f16927f837bdc11fca9f17ce44167944475225a205279b17e88c791c3b1f66f354668fb929081900390910190a3505050505b50505050505050565b60007f45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa08360138111156142a857fe5b8360168111156142b457fe5b604080519283526020830191909152600082820152519081900360600190a182601381111561185a57fe5b519051111590565b5190511090565b6001600160a01b0381166000908152600960205260409020805460ff1661435c576040805162461bcd60e51b815260206004820152601a60248201527f76656e7573206d61726b6574206973206e6f74206c6973746564000000000000604482015290519081900360640190fd5b600381015460ff16156143b6576040805162461bcd60e51b815260206004820152601a60248201527f76656e7573206d61726b657420616c7265616479206164646564000000000000604482015290519081900360640190fd5b60038101805460ff19166001908117909155604080516001600160a01b0385168152602081019290925280517f5f4087bd98874c2fa3ea4474bc7c58b711b23fff45cd2f456e358b4b33ee90259281900390910190a16001600160a01b0382166000908152601060205260409020546001600160e01b031615801561445e57506001600160a01b038216600090815260106020526040902054600160e01b900463ffffffff16155b156145265760405180604001604052806ec097ce7bc90715b34b9f10000000006001600160e01b031681526020016144cb614497611a46565b60405180604001604052806016815260200175626c6f636b206e756d626572206f766572666c6f777360501b815250615684565b63ffffffff9081169091526001600160a01b0384166000908152601060209081526040909120835181549490920151909216600160e01b026001600160e01b039182166001600160e01b031990941693909317169190911790555b6001600160a01b0382166000908152601160205260409020546001600160e01b031615801561457857506001600160a01b038216600090815260116020526040902054600160e01b900463ffffffff16155b156113eb5760405180604001604052806ec097ce7bc90715b34b9f10000000006001600160e01b031681526020016145b1614497611a46565b63ffffffff9081169091526001600160a01b0384166000908152601160209081526040909120835181549490920151909216600160e01b026001600160e01b039182166001600160e01b031990941693909317169190911790555050565b6015546001600160a01b0316156112c657601560009054906101000a90046001600160a01b03166001600160a01b031663d244b0816040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561467057600080fd5b505af1158015614684573d6000803e3d6000fd5b505050506040513d60208110156113eb57600080fd5b6015546001600160a01b0316156113eb576015546040805163d178273b60e01b81526001600160a01b0385811660048301529151600093849384938493919092169163d178273b91602480830192608092919082900301818787803b15801561470257600080fd5b505af1158015614716573d6000803e3d6000fd5b505050506040513d608081101561472c57600080fd5b50805160208201516040830151606090930151909650919450909250905080611c2a576147668685876142045766038d7ea4c68000614207565b6001600160a01b038716600081815260146020908152604091829020939093558051868152928301859052805191927f2fb3baf25f3d9fc9f9eb9dfd7da8567731a91413437d91bc1b8a839d0a1ba88f929081900390910190a2505050505050565b60008060006147d5615dcb565b6001600160a01b03881660009081526008602090815260408083208054825181850281018501909352808352849360609392919083018282801561484257602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311614824575b50939450600093505050505b8151811015614b9e57600082828151811061486557fe5b60200260200101519050806001600160a01b031663c37f68e28e6040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060806040518083038186803b1580156148c557600080fd5b505afa1580156148d9573d6000803e3d6000fd5b505050506040513d60808110156148ef57600080fd5b508051602082015160408084015160609485015160808c0152938a019390935291880191909152945084156149355750600f975060009650869550611c68945050505050565b60408051602080820183526001600160a01b0380851660008181526009845285902060010154845260c08b01939093528351808301855260808b0151815260e08b015260048054855163fc57d4df60e01b815291820194909452935192169263fc57d4df9260248083019392829003018186803b1580156149b557600080fd5b505afa1580156149c9573d6000803e3d6000fd5b505050506040513d60208110156149df57600080fd5b505160a08701819052614a035750600d975060009650869550611c68945050505050565b604080516020810190915260a08701518152610100870181905260c087015160e0880151614a3092615899565b61012088015293506000846003811115614a4657fe5b14614a625750600b975060009650869550611c68945050505050565b614a7a866101200151876040015188600001516158f1565b875293506000846003811115614a8c57fe5b14614aa85750600b975060009650869550611c68945050505050565b614ac0866101000151876060015188602001516158f1565b602088015293506000846003811115614ad557fe5b14614af15750600b975060009650869550611c68945050505050565b8b6001600160a01b0316816001600160a01b03161415614b9557614b1f8661012001518c88602001516158f1565b602088015293506000846003811115614b3457fe5b14614b505750600b975060009650869550611c68945050505050565b614b648661010001518b88602001516158f1565b602088015293506000846003811115614b7957fe5b14614b955750600b975060009650869550611c68945050505050565b5060010161484e565b50614bd28460200151601660008e6001600160a01b03166001600160a01b031681526020019081526020016000205461593a565b602086015291506000826003811115614be757fe5b14614c015750600b955060009450849350611c6892505050565b602084015184511115614c27575050506020810151905160009450039150829050611c68565b5050815160209092015160009550859450919091039150611c689050565b6001600160a01b0381166000908152601060209081526040808320600f9092528220549091614c72611a46565b8354909150600090614c92908390600160e01b900463ffffffff1661551b565b9050600081118015614ca45750600083115b15614e6b576000856001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b158015614ce457600080fd5b505afa158015614cf8573d6000803e3d6000fd5b505050506040513d6020811015614d0e57600080fd5b505190506000614d1e8386615573565b9050614d28615d94565b60008311614d455760405180602001604052806000815250614d4f565b614d4f82846155b5565b9050614d59615d94565b604080516020810190915288546001600160e01b03168152614d7b908361549b565b90506040518060400160405280614dc18360000151604051806040016040528060138152602001726e657720696e646578206f766572666c6f777360681b8152506155ea565b6001600160e01b03168152602001614e078860405180604001604052806016815260200175626c6f636b206e756d626572206f766572666c6f777360501b815250615684565b63ffffffff9081169091526001600160a01b038b166000908152601060209081526040909120835181549490920151909216600160e01b026001600160e01b039182166001600160e01b031990941693909317169190911790555061155d92505050565b801561155d57614ea98260405180604001604052806016815260200175626c6f636b206e756d626572206f766572666c6f777360501b815250615684565b845463ffffffff91909116600160e01b026001600160e01b039091161784555050505050565b6001600160a01b0383166000908152601060205260409020614eef615d94565b50604080516020810190915281546001600160e01b03168152614f10615d94565b5060408051602080820183526001600160a01b03808916600090815260128352848120918916808252828452948120805485528651959091529152919091558051158015614f5e5750815115155b15614f76576ec097ce7bc90715b34b9f100000000081525b614f7e615d94565b614f8883836156d9565b90506000876001600160a01b03166370a08231886040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b158015614fe257600080fd5b505afa158015614ff6573d6000803e3d6000fd5b505050506040513d602081101561500c57600080fd5b50519050600061501c82846156fe565b6001600160a01b03891660009081526014602052604081205491925090615043908361571e565b905061505c89828a6142045766038d7ea4c68000614207565b6001600160a01b03808b1660008181526014602090815260409182902094909455895181518781529485015280519193928e16927ffa9d964d891991c113b49e3db1932abd6c67263d387119707aafdd6c4010a3a9929081900390910190a350505050505050505050565b60008060006150d4615d94565b6150de8686615960565b909250905060008260038111156150f157fe5b146151025750915060009050615114565b600061510d826159c8565b9350935050505b9250929050565b60005b600d548110156151a657816001600160a01b0316600d828154811061513f57fe5b6000918252602090912001546001600160a01b0316141561519e576040805162461bcd60e51b81526020600482015260146024820152731b585c9ad95d08185b1c9958591e48185919195960621b604482015290519081900360640190fd5b60010161511e565b50600d80546001810182556000919091527fd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb50180546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b03831660009081526009602052604081205460ff16615220576009611d43565b6001600160a01b038085166000908152600960209081526040808320938716835260029093019052205460ff16615258576000611d43565b60008061526885878660006147c8565b9193509091506000905082601381111561527e57fe5b1461528f578160138111156132bc57fe5b8015612e155760046132bc565b6001600160a01b0382166000908152600960205260408120805460ff166152c757600991505061248f565b6001600160a01b038316600090815260028201602052604090205460ff16156152f457600091505061248f565b6007546001600160a01b0384166000908152600860205260409020541061531f57601091505061248f565b6001600160a01b0380841660008181526002840160209081526040808320805460ff19166001908117909155600883528184208054918201815584529282902090920180549489166001600160a01b031990951685179055815193845283019190915280517f3ab23ab0d51cccc0c3085aec51f99228625aa1a922b3a8ca89a26b0f2027a1a59281900390910190a15060009392505050565b60006153c2615d94565b6153e86040518060200160405280868152506040518060200160405280868152506159d7565b915091509250929050565b60006153fd615d94565b835183516153e89190615ac0565b60007f45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa084601381111561543a57fe5b84601681111561544657fe5b604080519283526020830191909152818101859052519081900360600190a183601381111561170f57fe5b615479615d94565b6040518060200160405280615492856000015185615573565b90529392505050565b6154a3615d94565b60405180602001604052806154928560000151856000015161571e565b6154c8615d94565b60405180602001604052806154926154ec8660000151670de0b6b3a7640000615573565b8551615b70565b6000670de0b6b3a764000061550c848460000151615573565b8161551357fe5b049392505050565b600061185a8383604051806040016040528060158152602001747375627472616374696f6e20756e646572666c6f7760581b815250615ba3565b600061185a61556c84670de0b6b3a7640000615573565b8351615b70565b600061185a83836040518060400160405280601781526020017f6d756c7469706c69636174696f6e206f766572666c6f77000000000000000000815250615bfd565b6155bd615d94565b60405180602001604052806154926155e4866ec097ce7bc90715b34b9f1000000000615573565b85615b70565b600081600160e01b841061567c5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015615641578181015183820152602001615629565b50505050905090810190601f16801561566e5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b509192915050565b600081600160201b841061567c5760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315615641578181015183820152602001615629565b6156e1615d94565b60405180602001604052806154928560000151856000015161551b565b60006ec097ce7bc90715b34b9f100000000061550c848460000151615573565b600061185a8383604051806040016040528060118152602001706164646974696f6e206f766572666c6f7760781b815250615c73565b60008183101580156157665750600083115b156158915760006157756128e7565b604080516370a0823160e01b815230600482015290519192506000916001600160a01b038416916370a08231916024808301926020929190829003018186803b1580156157c157600080fd5b505afa1580156157d5573d6000803e3d6000fd5b505050506040513d60208110156157eb57600080fd5b5051905080851161588e57816001600160a01b031663a9059cbb87876040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050602060405180830381600087803b15801561585657600080fd5b505af115801561586a573d6000803e3d6000fd5b505050506040513d602081101561588057600080fd5b506000935061185a92505050565b50505b509092915050565b60006158a3615d94565b60006158ad615d94565b6158b787876159d7565b909250905060008260038111156158ca57fe5b146158d9579092509050612c02565b6158e381866159d7565b935093505050935093915050565b60008060006158fe615d94565b6159088787615960565b9092509050600082600381111561591b57fe5b1461592c5750915060009050612c02565b6158e3615938826159c8565b865b60008083830184811061595257600092509050615114565b506002915060009050615114565b600061596a615d94565b60008061597b866000015186615cc8565b9092509050600082600381111561598e57fe5b146159ad57506040805160208101909152600081529092509050615114565b60408051602081019091529081526000969095509350505050565b51670de0b6b3a7640000900490565b60006159e1615d94565b6000806159f686600001518660000151615cc8565b90925090506000826003811115615a0957fe5b14615a2857506040805160208101909152600081529092509050615114565b600080615a3d6706f05b59d3b200008461593a565b90925090506000826003811115615a5057fe5b14615a7257506040805160208101909152600081529094509250615114915050565b600080615a8783670de0b6b3a7640000615d07565b90925090506000826003811115615a9a57fe5b14615aa157fe5b604080516020810190915290815260009a909950975050505050505050565b6000615aca615d94565b600080615adf86670de0b6b3a7640000615cc8565b90925090506000826003811115615af257fe5b14615b1157506040805160208101909152600081529092509050615114565b600080615b1e8388615d07565b90925090506000826003811115615b3157fe5b14615b5357506040805160208101909152600081529094509250615114915050565b604080516020810190915290815260009890975095505050505050565b600061185a83836040518060400160405280600e81526020016d646976696465206279207a65726f60901b815250615d32565b60008184841115615bf55760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315615641578181015183820152602001615629565b505050900390565b6000831580615c0a575082155b15615c175750600061185a565b83830283858281615c2457fe5b0414839061298c5760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315615641578181015183820152602001615629565b6000838301828582101561298c5760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315615641578181015183820152602001615629565b60008083615cdb57506000905080615114565b83830283858281615ce857fe5b0414615cfc57506002915060009050615114565b600092509050615114565b60008082615d1b5750600190506000615114565b6000838581615d2657fe5b04915091509250929050565b60008183615d815760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315615641578181015183820152602001615629565b50828481615d8b57fe5b04949350505050565b6040518060200160405280600081525090565b815481835581811115611f3657600083815260209020611f36918101908301615e35565b604051806101400160405280600081526020016000815260200160008152602001600081526020016000815260200160008152602001615e09615d94565b8152602001615e16615d94565b8152602001615e23615d94565b8152602001615e30615d94565b905290565b611a4891905b80821115615e4f5760008155600101615e3b565b509056fe70726f746f636f6c2069732070617573656400000000000000000000000000006f6e6c792065787465726e616c6c79206f776e6564206163636f756e74732063616ea265627a7a723158209b016c78a8bc1ad9ac63eb79f36acd3c457cf2c3e02eb27f52e413b499e9fb3464736f6c63430005110032", + "abi": [ + { "inputs": [], "payable": false, "stateMutability": "nonpayable", "type": "constructor" }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "string", "name": "action", "type": "string" }, + { "indexed": false, "internalType": "bool", "name": "pauseState", "type": "bool" } + ], + "name": "ActionPaused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "contract VToken", "name": "vToken", "type": "address" }, + { "indexed": false, "internalType": "string", "name": "action", "type": "string" }, + { "indexed": false, "internalType": "bool", "name": "pauseState", "type": "bool" } + ], + "name": "ActionPaused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [{ "indexed": false, "internalType": "bool", "name": "state", "type": "bool" }], + "name": "ActionProtocolPaused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "contract VToken", "name": "vToken", "type": "address" }, + { "indexed": true, "internalType": "address", "name": "borrower", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "venusDelta", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "venusBorrowIndex", "type": "uint256" } + ], + "name": "DistributedBorrowerVenus", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "contract VToken", "name": "vToken", "type": "address" }, + { "indexed": true, "internalType": "address", "name": "supplier", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "venusDelta", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "venusSupplyIndex", "type": "uint256" } + ], + "name": "DistributedSupplierVenus", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "vaiMinter", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "venusDelta", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "venusVAIMintIndex", "type": "uint256" } + ], + "name": "DistributedVAIMinterVenus", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "uint256", "name": "error", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "info", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "detail", "type": "uint256" } + ], + "name": "Failure", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "contract VToken", "name": "vToken", "type": "address" }, + { "indexed": false, "internalType": "address", "name": "account", "type": "address" } + ], + "name": "MarketEntered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "contract VToken", "name": "vToken", "type": "address" }, + { "indexed": false, "internalType": "address", "name": "account", "type": "address" } + ], + "name": "MarketExited", + "type": "event" + }, + { + "anonymous": false, + "inputs": [{ "indexed": false, "internalType": "contract VToken", "name": "vToken", "type": "address" }], + "name": "MarketListed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "contract VToken", "name": "vToken", "type": "address" }, + { "indexed": false, "internalType": "bool", "name": "isVenus", "type": "bool" } + ], + "name": "MarketVenus", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "uint256", "name": "oldCloseFactorMantissa", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "newCloseFactorMantissa", "type": "uint256" } + ], + "name": "NewCloseFactor", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "contract VToken", "name": "vToken", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "oldCollateralFactorMantissa", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "newCollateralFactorMantissa", "type": "uint256" } + ], + "name": "NewCollateralFactor", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "uint256", "name": "oldLiquidationIncentiveMantissa", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "newLiquidationIncentiveMantissa", "type": "uint256" } + ], + "name": "NewLiquidationIncentive", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "uint256", "name": "oldMaxAssets", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "newMaxAssets", "type": "uint256" } + ], + "name": "NewMaxAssets", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "address", "name": "oldPauseGuardian", "type": "address" }, + { "indexed": false, "internalType": "address", "name": "newPauseGuardian", "type": "address" } + ], + "name": "NewPauseGuardian", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "contract PriceOracle", "name": "oldPriceOracle", "type": "address" }, + { "indexed": false, "internalType": "contract PriceOracle", "name": "newPriceOracle", "type": "address" } + ], + "name": "NewPriceOracle", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "contract VAIControllerInterface", + "name": "oldVAIController", + "type": "address" + }, + { + "indexed": false, + "internalType": "contract VAIControllerInterface", + "name": "newVAIController", + "type": "address" + } + ], + "name": "NewVAIController", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "uint256", "name": "oldVAIMintRate", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "newVAIMintRate", "type": "uint256" } + ], + "name": "NewVAIMintRate", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "uint256", "name": "oldVenusRate", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "newVenusRate", "type": "uint256" } + ], + "name": "NewVenusRate", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "uint256", "name": "oldVenusVAIRate", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "newVenusVAIRate", "type": "uint256" } + ], + "name": "NewVenusVAIRate", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "contract VToken", "name": "vToken", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "newSpeed", "type": "uint256" } + ], + "name": "VenusSpeedUpdated", + "type": "event" + }, + { + "constant": false, + "inputs": [{ "internalType": "address[]", "name": "vTokens", "type": "address[]" }], + "name": "_addVenusMarkets", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "internalType": "contract Unitroller", "name": "unitroller", "type": "address" }], + "name": "_become", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "_borrowGuardianPaused", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "internalType": "address", "name": "vToken", "type": "address" }], + "name": "_dropVenusMarket", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "internalType": "uint256", "name": "blockNumber", "type": "uint256" }], + "name": "_initializeVenusVAIState", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "_mintGuardianPaused", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "internalType": "uint256", "name": "newCloseFactorMantissa", "type": "uint256" }], + "name": "_setCloseFactor", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { "internalType": "contract VToken", "name": "vToken", "type": "address" }, + { "internalType": "uint256", "name": "newCollateralFactorMantissa", "type": "uint256" } + ], + "name": "_setCollateralFactor", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "internalType": "uint256", "name": "newLiquidationIncentiveMantissa", "type": "uint256" }], + "name": "_setLiquidationIncentive", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "internalType": "uint256", "name": "newMaxAssets", "type": "uint256" }], + "name": "_setMaxAssets", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "internalType": "contract PriceOracle", "name": "newOracle", "type": "address" }], + "name": "_setPriceOracle", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "internalType": "bool", "name": "state", "type": "bool" }], + "name": "_setProtocolPaused", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "internalType": "contract VAIControllerInterface", "name": "vaiController_", "type": "address" }], + "name": "_setVAIController", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "internalType": "uint256", "name": "newVAIMintRate", "type": "uint256" }], + "name": "_setVAIMintRate", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "internalType": "uint256", "name": "venusRate_", "type": "uint256" }], + "name": "_setVenusRate", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "internalType": "uint256", "name": "venusVAIRate_", "type": "uint256" }], + "name": "_setVenusVAIRate", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "internalType": "contract VToken", "name": "vToken", "type": "address" }], + "name": "_supportMarket", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { "internalType": "address", "name": "", "type": "address" }, + { "internalType": "uint256", "name": "", "type": "uint256" } + ], + "name": "accountAssets", + "outputs": [{ "internalType": "contract VToken", "name": "", "type": "address" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "admin", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "name": "allMarkets", + "outputs": [{ "internalType": "contract VToken", "name": "", "type": "address" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { "internalType": "address", "name": "vToken", "type": "address" }, + { "internalType": "address", "name": "borrower", "type": "address" }, + { "internalType": "uint256", "name": "borrowAmount", "type": "uint256" } + ], + "name": "borrowAllowed", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [{ "internalType": "address", "name": "", "type": "address" }], + "name": "borrowGuardianPaused", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { "internalType": "address", "name": "vToken", "type": "address" }, + { "internalType": "address", "name": "borrower", "type": "address" }, + { "internalType": "uint256", "name": "borrowAmount", "type": "uint256" } + ], + "name": "borrowVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { "internalType": "address", "name": "account", "type": "address" }, + { "internalType": "contract VToken", "name": "vToken", "type": "address" } + ], + "name": "checkMembership", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { "internalType": "address", "name": "holder", "type": "address" }, + { "internalType": "contract VToken[]", "name": "vTokens", "type": "address[]" } + ], + "name": "claimVenus", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "internalType": "address", "name": "holder", "type": "address" }], + "name": "claimVenus", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { "internalType": "address[]", "name": "holders", "type": "address[]" }, + { "internalType": "contract VToken[]", "name": "vTokens", "type": "address[]" }, + { "internalType": "bool", "name": "borrowers", "type": "bool" }, + { "internalType": "bool", "name": "suppliers", "type": "bool" } + ], + "name": "claimVenus", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "closeFactorMantissa", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "comptrollerImplementation", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "internalType": "address[]", "name": "vTokens", "type": "address[]" }], + "name": "enterMarkets", + "outputs": [{ "internalType": "uint256[]", "name": "", "type": "uint256[]" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "internalType": "address", "name": "vTokenAddress", "type": "address" }], + "name": "exitMarket", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [{ "internalType": "address", "name": "account", "type": "address" }], + "name": "getAccountLiquidity", + "outputs": [ + { "internalType": "uint256", "name": "", "type": "uint256" }, + { "internalType": "uint256", "name": "", "type": "uint256" }, + { "internalType": "uint256", "name": "", "type": "uint256" } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "getAllMarkets", + "outputs": [{ "internalType": "contract VToken[]", "name": "", "type": "address[]" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [{ "internalType": "address", "name": "account", "type": "address" }], + "name": "getAssetsIn", + "outputs": [{ "internalType": "contract VToken[]", "name": "", "type": "address[]" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "getBlockNumber", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { "internalType": "address", "name": "account", "type": "address" }, + { "internalType": "address", "name": "vTokenModify", "type": "address" }, + { "internalType": "uint256", "name": "redeemTokens", "type": "uint256" }, + { "internalType": "uint256", "name": "borrowAmount", "type": "uint256" } + ], + "name": "getHypotheticalAccountLiquidity", + "outputs": [ + { "internalType": "uint256", "name": "", "type": "uint256" }, + { "internalType": "uint256", "name": "", "type": "uint256" }, + { "internalType": "uint256", "name": "", "type": "uint256" } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [{ "internalType": "address", "name": "minter", "type": "address" }], + "name": "getMintableVAI", + "outputs": [ + { "internalType": "uint256", "name": "", "type": "uint256" }, + { "internalType": "uint256", "name": "", "type": "uint256" } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "getXVSAddress", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "isComptroller", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { "internalType": "address", "name": "vTokenBorrowed", "type": "address" }, + { "internalType": "address", "name": "vTokenCollateral", "type": "address" }, + { "internalType": "address", "name": "liquidator", "type": "address" }, + { "internalType": "address", "name": "borrower", "type": "address" }, + { "internalType": "uint256", "name": "repayAmount", "type": "uint256" } + ], + "name": "liquidateBorrowAllowed", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { "internalType": "address", "name": "vTokenBorrowed", "type": "address" }, + { "internalType": "address", "name": "vTokenCollateral", "type": "address" }, + { "internalType": "address", "name": "liquidator", "type": "address" }, + { "internalType": "address", "name": "borrower", "type": "address" }, + { "internalType": "uint256", "name": "actualRepayAmount", "type": "uint256" }, + { "internalType": "uint256", "name": "seizeTokens", "type": "uint256" } + ], + "name": "liquidateBorrowVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { "internalType": "address", "name": "vTokenBorrowed", "type": "address" }, + { "internalType": "address", "name": "vTokenCollateral", "type": "address" }, + { "internalType": "uint256", "name": "actualRepayAmount", "type": "uint256" } + ], + "name": "liquidateCalculateSeizeTokens", + "outputs": [ + { "internalType": "uint256", "name": "", "type": "uint256" }, + { "internalType": "uint256", "name": "", "type": "uint256" } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "liquidationIncentiveMantissa", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [{ "internalType": "address", "name": "", "type": "address" }], + "name": "markets", + "outputs": [ + { "internalType": "bool", "name": "isListed", "type": "bool" }, + { "internalType": "uint256", "name": "collateralFactorMantissa", "type": "uint256" }, + { "internalType": "bool", "name": "isVenus", "type": "bool" } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "maxAssets", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { "internalType": "address", "name": "vToken", "type": "address" }, + { "internalType": "address", "name": "minter", "type": "address" }, + { "internalType": "uint256", "name": "mintAmount", "type": "uint256" } + ], + "name": "mintAllowed", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [{ "internalType": "address", "name": "", "type": "address" }], + "name": "mintGuardianPaused", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "internalType": "uint256", "name": "mintVAIAmount", "type": "uint256" }], + "name": "mintVAI", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "mintVAIGuardianPaused", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { "internalType": "address", "name": "vToken", "type": "address" }, + { "internalType": "address", "name": "minter", "type": "address" }, + { "internalType": "uint256", "name": "actualMintAmount", "type": "uint256" }, + { "internalType": "uint256", "name": "mintTokens", "type": "uint256" } + ], + "name": "mintVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [{ "internalType": "address", "name": "owner", "type": "address" }], + "name": "mintedVAIOf", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [{ "internalType": "address", "name": "", "type": "address" }], + "name": "mintedVAIs", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "oracle", + "outputs": [{ "internalType": "contract PriceOracle", "name": "", "type": "address" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "pauseGuardian", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "pendingAdmin", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "pendingComptrollerImplementation", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "protocolPaused", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { "internalType": "address", "name": "vToken", "type": "address" }, + { "internalType": "address", "name": "redeemer", "type": "address" }, + { "internalType": "uint256", "name": "redeemTokens", "type": "uint256" } + ], + "name": "redeemAllowed", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { "internalType": "address", "name": "vToken", "type": "address" }, + { "internalType": "address", "name": "redeemer", "type": "address" }, + { "internalType": "uint256", "name": "redeemAmount", "type": "uint256" }, + { "internalType": "uint256", "name": "redeemTokens", "type": "uint256" } + ], + "name": "redeemVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [], + "name": "refreshVenusSpeeds", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { "internalType": "address", "name": "vToken", "type": "address" }, + { "internalType": "address", "name": "payer", "type": "address" }, + { "internalType": "address", "name": "borrower", "type": "address" }, + { "internalType": "uint256", "name": "repayAmount", "type": "uint256" } + ], + "name": "repayBorrowAllowed", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { "internalType": "address", "name": "vToken", "type": "address" }, + { "internalType": "address", "name": "payer", "type": "address" }, + { "internalType": "address", "name": "borrower", "type": "address" }, + { "internalType": "uint256", "name": "actualRepayAmount", "type": "uint256" }, + { "internalType": "uint256", "name": "borrowerIndex", "type": "uint256" } + ], + "name": "repayBorrowVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "internalType": "uint256", "name": "repayVAIAmount", "type": "uint256" }], + "name": "repayVAI", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "repayVAIGuardianPaused", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { "internalType": "address", "name": "vTokenCollateral", "type": "address" }, + { "internalType": "address", "name": "vTokenBorrowed", "type": "address" }, + { "internalType": "address", "name": "liquidator", "type": "address" }, + { "internalType": "address", "name": "borrower", "type": "address" }, + { "internalType": "uint256", "name": "seizeTokens", "type": "uint256" } + ], + "name": "seizeAllowed", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "seizeGuardianPaused", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { "internalType": "address", "name": "vTokenCollateral", "type": "address" }, + { "internalType": "address", "name": "vTokenBorrowed", "type": "address" }, + { "internalType": "address", "name": "liquidator", "type": "address" }, + { "internalType": "address", "name": "borrower", "type": "address" }, + { "internalType": "uint256", "name": "seizeTokens", "type": "uint256" } + ], + "name": "seizeVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { "internalType": "address", "name": "owner", "type": "address" }, + { "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "setMintedVAIOf", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { "internalType": "address", "name": "vToken", "type": "address" }, + { "internalType": "address", "name": "src", "type": "address" }, + { "internalType": "address", "name": "dst", "type": "address" }, + { "internalType": "uint256", "name": "transferTokens", "type": "uint256" } + ], + "name": "transferAllowed", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "transferGuardianPaused", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { "internalType": "address", "name": "vToken", "type": "address" }, + { "internalType": "address", "name": "src", "type": "address" }, + { "internalType": "address", "name": "dst", "type": "address" }, + { "internalType": "uint256", "name": "transferTokens", "type": "uint256" } + ], + "name": "transferVerify", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "vaiController", + "outputs": [{ "internalType": "contract VAIControllerInterface", "name": "", "type": "address" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "vaiMintRate", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [{ "internalType": "address", "name": "", "type": "address" }], + "name": "venusAccrued", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [{ "internalType": "address", "name": "", "type": "address" }], + "name": "venusBorrowState", + "outputs": [ + { "internalType": "uint224", "name": "index", "type": "uint224" }, + { "internalType": "uint32", "name": "block", "type": "uint32" } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { "internalType": "address", "name": "", "type": "address" }, + { "internalType": "address", "name": "", "type": "address" } + ], + "name": "venusBorrowerIndex", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "venusClaimThreshold", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "venusInitialIndex", + "outputs": [{ "internalType": "uint224", "name": "", "type": "uint224" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "venusRate", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [{ "internalType": "address", "name": "", "type": "address" }], + "name": "venusSpeeds", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { "internalType": "address", "name": "", "type": "address" }, + { "internalType": "address", "name": "", "type": "address" } + ], + "name": "venusSupplierIndex", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [{ "internalType": "address", "name": "", "type": "address" }], + "name": "venusSupplyState", + "outputs": [ + { "internalType": "uint224", "name": "index", "type": "uint224" }, + { "internalType": "uint32", "name": "block", "type": "uint32" } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "venusVAIRate", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + } + ] +} diff --git a/assets/bsc/ComptrollerV4.json b/assets/bsc/ComptrollerV4.json new file mode 100644 index 00000000..aad9dd66 --- /dev/null +++ b/assets/bsc/ComptrollerV4.json @@ -0,0 +1,4 @@ +{ + "bytecode": "608060405234801561001057600080fd5b50600080546001600160a01b03191633179055615dce80620000336000396000f3fe608060405234801561001057600080fd5b50600436106104f85760003560e01c80637d172bd511610299578063bf32442d11610167578063ddfd287e116100d9578063eabe7d9111610092578063eabe7d91146112f2578063ede4edd014611328578063f4b8d5fe1461134e578063f851a44014611374578063fa6331d81461137c578063fd51a3ad14611384576104f8565b8063ddfd287e1461126b578063e37d4b7914611273578063e4028eee14611299578063e6653f3d146112c5578063e6de6528146112cd578063e8755446146112ea576104f8565b8063d02f73511161012b578063d02f735114611059578063d09c54ba1461109f578063d24febad146111cb578063da3d454c14611201578063dce1544914611237578063dcfbc0c714611263576104f8565b8063bf32442d14610f81578063c299823814610f89578063c488847b14610ff7578063c5b4db551461102d578063c5f956af14611051576104f8565b8063a06a87f11161020b578063b0772d0b116101c4578063b0772d0b14610ed7578063b2eafc3914610edf578063b8324c7c14610ee7578063bb82aa5e14610f35578063bdcdc25814610f3d578063bec04f7214610f79576104f8565b8063a06a87f114610d9c578063a76b3fda14610dc8578063a78dc77514610dee578063abfceffc14610e33578063ac0b0bb714610ea9578063adcd5fb914610eb1576104f8565b80638a7dc1651161025d5780638a7dc16514610cca5780638e8f294b14610cf05780639254f5e514610d38578063929fe9a114610d4057806394b2294b14610d6e5780639cfdd9e614610d76576104f8565b80637d172bd514610bf95780637dc0d1d014610c0157806386df31ee14610c09578063879c2e1d14610cba57806387f7630314610cc2576104f8565b806342cbb15c116103d65780635c778605116103485780636a56947e116103015780636a56947e14610b1b5780636d154ea514610b575780636d35bf9114610b7d578063719f701b14610bc3578063731f0c2b14610bcb5780637655138314610bf1576104f8565b80635c778605146109785780635ec88c79146109ae5780635f5af1aa146109d45780635fc7e71e146109fa578063607ef6c114610a405780636662c7c914610afe576104f8565b80634e79238f1161039a5780634e79238f1461084c5780634ef4c3e1146108a65780634fd42e17146108dc57806351dff989146108f957806352d84d1e1461093557806355ee1fe114610952576104f8565b806342cbb15c1461079857806347ef3b3b146107a05780634a584432146107ec5780634ada90af146108125780634e0853db1461081a576104f8565b80632a6a60651161046f578063399cc80c11610433578063399cc80c1461070e5780633c94786f146107165780634088c73e1461071e57806341a18d2c1461072657806341c728b914610754578063425fad5814610790576104f8565b80632a6a6065146106695780632bc7e29e146106885780632ec04124146106ae578063317b0b77146106cb578063391957d7146106e8576104f8565b80631d504dc6116104c15780631d504dc61461058f5780631ededc91146105b757806321af4569146105f957806324008a621461061d57806324a3d622146106595780632678224714610661576104f8565b80627e3dd2146104fd57806304ef9d581461051957806308e0225c146105335780630db4b4e5146105615780631abcaa7714610569575b600080fd5b6105056113b0565b604080519115158252519081900360200190f35b6105216113b5565b60408051918252519081900360200190f35b6105216004803603604081101561054957600080fd5b506001600160a01b03813581169160200135166113bb565b6105216113d8565b6105216004803603602081101561057f57600080fd5b50356001600160a01b03166113de565b6105b5600480360360208110156105a557600080fd5b50356001600160a01b03166113f0565b005b6105b5600480360360a08110156105cd57600080fd5b506001600160a01b0381358116916020810135821691604082013516906060810135906080013561155e565b610601611565565b604080516001600160a01b039092168252519081900360200190f35b6105216004803603608081101561063357600080fd5b506001600160a01b03813581169160208101358216916040820135169060600135611574565b610601611691565b6106016116a0565b6105056004803603602081101561067f57600080fd5b503515156116af565b6105216004803603602081101561069e57600080fd5b50356001600160a01b03166117cc565b610521600480360360208110156106c457600080fd5b50356117de565b610521600480360360208110156106e157600080fd5b5035611853565b6105b5600480360360208110156106fe57600080fd5b50356001600160a01b03166118fd565b6105216119b0565b6105056119b6565b6105056119c6565b6105216004803603604081101561073c57600080fd5b506001600160a01b03813581169160200135166119cf565b6105b56004803603608081101561076a57600080fd5b506001600160a01b038135811691602081013590911690604081013590606001356119ec565b6105056119f2565b610521611a01565b6105b5600480360360c08110156107b657600080fd5b506001600160a01b0381358116916020810135821691604082013581169160608101359091169060808101359060a00135611a06565b6105216004803603602081101561080257600080fd5b50356001600160a01b0316611a0e565b610521611a20565b6105b56004803603606081101561083057600080fd5b506001600160a01b038135169060208101359060400135611a26565b6108886004803603608081101561086257600080fd5b506001600160a01b03813581169160208101359091169060408101359060600135611ae3565b60408051938452602084019290925282820152519081900360600190f35b610521600480360360608110156108bc57600080fd5b506001600160a01b03813581169160208101359091169060400135611b1d565b610521600480360360208110156108f257600080fd5b5035611c1c565b6105b56004803603608081101561090f57600080fd5b506001600160a01b03813581169160208101359091169060408101359060600135611c85565b6106016004803603602081101561094b57600080fd5b5035611cd6565b6105216004803603602081101561096857600080fd5b50356001600160a01b0316611cfd565b6105b56004803603606081101561098e57600080fd5b506001600160a01b03813581169160208101359091169060400135611d82565b610888600480360360208110156109c457600080fd5b50356001600160a01b0316611d87565b610521600480360360208110156109ea57600080fd5b50356001600160a01b0316611dbc565b610521600480360360a0811015610a1057600080fd5b506001600160a01b0381358116916020810135821691604082013581169160608101359091169060800135611e41565b6105b560048036036040811015610a5657600080fd5b810190602081018135600160201b811115610a7057600080fd5b820183602082011115610a8257600080fd5b803590602001918460208302840111600160201b83111715610aa357600080fd5b919390929091602081019035600160201b811115610ac057600080fd5b820183602082011115610ad257600080fd5b803590602001918460208302840111600160201b83111715610af357600080fd5b50909250905061204d565b6105b560048036036020811015610b1457600080fd5b50356121dd565b6105b560048036036080811015610b3157600080fd5b506001600160a01b03813581169160208101358216916040820135169060600135612274565b61050560048036036020811015610b6d57600080fd5b50356001600160a01b0316612279565b6105b5600480360360a0811015610b9357600080fd5b506001600160a01b038135811691602081013582169160408201358116916060810135909116906080013561155e565b61052161228e565b61050560048036036020811015610be157600080fd5b50356001600160a01b0316612294565b6105056122a9565b6106016122b7565b6106016122c6565b6105b560048036036040811015610c1f57600080fd5b6001600160a01b038235169190810190604081016020820135600160201b811115610c4957600080fd5b820183602082011115610c5b57600080fd5b803590602001918460208302840111600160201b83111715610c7c57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295506122d5945050505050565b610521612332565b610505612338565b61052160048036036020811015610ce057600080fd5b50356001600160a01b0316612348565b610d1660048036036020811015610d0657600080fd5b50356001600160a01b031661235a565b6040805193151584526020840192909252151582820152519081900360600190f35b610601612380565b61050560048036036040811015610d5657600080fd5b506001600160a01b038135811691602001351661238f565b6105216123c3565b61052160048036036020811015610d8c57600080fd5b50356001600160a01b03166123c9565b6105b560048036036040811015610db257600080fd5b506001600160a01b03813516906020013561244d565b61052160048036036020811015610dde57600080fd5b50356001600160a01b03166124b4565b610e1a60048036036040811015610e0457600080fd5b506001600160a01b038135169060200135612611565b6040805192835260208301919091528051918290030190f35b610e5960048036036020811015610e4957600080fd5b50356001600160a01b03166127b6565b60408051602080825283518183015283519192839290830191858101910280838360005b83811015610e95578181015183820152602001610e7d565b505050509050019250505060405180910390f35b61050561282c565b6105b560048036036020811015610ec757600080fd5b50356001600160a01b031661283c565b610e596128a0565b610601612902565b610f0d60048036036020811015610efd57600080fd5b50356001600160a01b0316612911565b604080516001600160e01b03909316835263ffffffff90911660208301528051918290030190f35b61060161293b565b61052160048036036080811015610f5357600080fd5b506001600160a01b0381358116916020810135821691604082013516906060013561294a565b610521612a2d565b610601612a33565b610e5960048036036020811015610f9f57600080fd5b810190602081018135600160201b811115610fb957600080fd5b820183602082011115610fcb57600080fd5b803590602001918460208302840111600160201b83111715610fec57600080fd5b509092509050612a4b565b610e1a6004803603606081101561100d57600080fd5b506001600160a01b03813581169160208101359091169060400135612ae1565b611035612d09565b604080516001600160e01b039092168252519081900360200190f35b610601612d1c565b610521600480360360a081101561106f57600080fd5b506001600160a01b0381358116916020810135821691604082013581169160608101359091169060800135612d2b565b6105b5600480360360808110156110b557600080fd5b810190602081018135600160201b8111156110cf57600080fd5b8201836020820111156110e157600080fd5b803590602001918460208302840111600160201b8311171561110257600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050600160201b81111561115157600080fd5b82018360208201111561116357600080fd5b803590602001918460208302840111600160201b8311171561118457600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550505050803515159150602001351515612f4a565b610521600480360360608110156111e157600080fd5b506001600160a01b038135811691602081013590911690604001356132e9565b6105216004803603606081101561121757600080fd5b506001600160a01b0381358116916020810135909116906040013561347e565b6106016004803603604081101561124d57600080fd5b506001600160a01b03813516906020013561387b565b6106016138b0565b6105b56138bf565b610f0d6004803603602081101561128957600080fd5b50356001600160a01b0316613aef565b610521600480360360408110156112af57600080fd5b506001600160a01b038135169060200135613b19565b610505613cc9565b6105b5600480360360208110156112e357600080fd5b5035613cd9565b610521613d70565b6105216004803603606081101561130857600080fd5b506001600160a01b03813581169160208101359091169060400135613d76565b6105216004803603602081101561133e57600080fd5b50356001600160a01b0316613e06565b6105b56004803603602081101561136457600080fd5b50356001600160a01b03166140c2565b6106016141ee565b6105216141fd565b6105216004803603604081101561139a57600080fd5b506001600160a01b038135169060200135614203565b600181565b60225481565b601360209081526000928352604080842090915290825290205481565b601d5481565b600f6020526000908152604090205481565b806001600160a01b031663f851a4406040518163ffffffff1660e01b815260040160206040518083038186803b15801561142957600080fd5b505afa15801561143d573d6000803e3d6000fd5b505050506040513d602081101561145357600080fd5b50516001600160a01b031633146114b1576040805162461bcd60e51b815260206004820152601960248201527f6f6e6c7920756e6974726f6c6c65722061646d696e2063616e00000000000000604482015290519081900360640190fd5b806001600160a01b031663c1e803346040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156114ec57600080fd5b505af1158015611500573d6000803e3d6000fd5b505050506040513d602081101561151657600080fd5b50511561155b576040805162461bcd60e51b815260206004820152600e60248201526d1b9bdd08185d5d1a1bdc9a5e995960921b604482015290519081900360640190fd5b50565b5050505050565b601e546001600160a01b031681565b60185460009062010000900460ff16156115ca576040805162461bcd60e51b81526020600482015260126024820152711c1c9bdd1bd8dbdb081a5cc81c185d5cd95960721b604482015290519081900360640190fd5b6001600160a01b03851660009081526009602052604090205460ff166115f257506009611689565b6115fa615c84565b6040518060200160405280876001600160a01b031663aa5af0fd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561163e57600080fd5b505afa158015611652573d6000803e3d6000fd5b505050506040513d602081101561166857600080fd5b50519052905061167886826142f5565b611683868583614589565b60009150505b949350505050565b600a546001600160a01b031681565b6001546001600160a01b031681565b600a5460009082906001600160a01b03163314806116d757506000546001600160a01b031633145b6117125760405162461bcd60e51b8152600401808060200182810382526021815260200180615d446021913960400191505060405180910390fd5b6000546001600160a01b031633148061172d57506001811515145b611777576040805162461bcd60e51b81526020600482015260166024820152756f6e6c792061646d696e2063616e20756e706175736560501b604482015290519081900360640190fd5b6018805484151562010000810262ff0000199092169190911790915560408051918252517fd7500633dd3ddd74daa7af62f8c8404c7fe4a81da179998db851696bed004b389181900360200190a15090919050565b60166020526000908152604090205481565b600080546001600160a01b03163314611804576117fd60016014614739565b905061184e565b6017805490839055604080518281526020810185905281517f73747d68b346dce1e932bcd238282e7ac84c01569e1f8d0469c222fdc6e9d5a4929181900390910190a160005b9150505b919050565b600080546001600160a01b031633146118b3576040805162461bcd60e51b815260206004820152601f60248201527f6f6e6c792061646d696e2063616e2073657420636c6f736520666163746f7200604482015290519081900360640190fd5b6005805490839055604080518281526020810185905281517f3b9670cf975d26958e754b57098eaa2ac914d8d2a31b83257997b9f346110fd9929181900390910190a1600061184a565b6000546001600160a01b0316331461194d576040805162461bcd60e51b815260206004820152600e60248201526d37b7363c9030b236b4b71031b0b760911b604482015290519081900360640190fd5b601e80546001600160a01b038381166001600160a01b0319831681179093556040805191909216808252602082019390935281517feda98690e518e9a05f8ec6837663e188211b2da8f4906648b323f2c1d4434e29929181900390910190a15050565b60195481565b600a54600160a01b900460ff1681565b60185460ff1681565b601260209081526000928352604080842090915290825290205481565b50505050565b60185462010000900460ff1681565b435b90565b505050505050565b601f6020526000908152604090205481565b60065481565b6000546001600160a01b03163314611a76576040805162461bcd60e51b815260206004820152600e60248201526d37b7363c9030b236b4b71031b0b760911b604482015290519081900360640190fd5b601b80546001600160a01b0385166001600160a01b03199091168117909155601c839055601d8290556040805191825260208201849052818101839052517f7059037d74ee16b0fb06a4a30f3348dd2635f301f92e373c92899a25a522ef6e9181900360600190a1505050565b600080600080600080611af88a8a8a8a61479f565b925092509250826012811115611b0a57fe5b95509093509150505b9450945094915050565b60185460009062010000900460ff1615611b73576040805162461bcd60e51b81526020600482015260126024820152711c1c9bdd1bd8dbdb081a5cc81c185d5cd95960721b604482015290519081900360640190fd5b6001600160a01b0384166000908152600b602052604090205460ff1615611bd2576040805162461bcd60e51b815260206004820152600e60248201526d1b5a5b9d081a5cc81c185d5cd95960921b604482015290519081900360640190fd5b6001600160a01b03841660009081526009602052604090205460ff16611bfc5760095b9050611c15565b611c0584614b0c565b611c0f8484614d96565b60005b90505b9392505050565b600080546001600160a01b03163314611c3b576117fd6001600b614739565b6006805490839055604080518281526020810185905281517faeba5a6c40a8ac138134bff1aaa65debf25971188a58804bad717f82f0ec1316929181900390910190a1600061184a565b80151580611c91575081155b6119ec576040805162461bcd60e51b815260206004820152601160248201527072656465656d546f6b656e73207a65726f60781b604482015290519081900360640190fd5b600d8181548110611ce357fe5b6000918252602090912001546001600160a01b0316905081565b600080546001600160a01b03163314611d1c576117fd60016010614739565b600480546001600160a01b038481166001600160a01b0319831681179093556040805191909216808252602082019390935281517fd52b2b9b7e9ee655fcb95d2e5b9e0c9f69e7ef2b8e9d2d0ea78402d576d22e22929181900390910190a1600061184a565b505050565b600080600080600080611d9e87600080600061479f565b925092509250826012811115611db057fe5b97919650945092505050565b600080546001600160a01b03163314611ddb576117fd60016013614739565b600a80546001600160a01b038481166001600160a01b0319831681179093556040805191909216808252602082019390935281517f0613b6ee6a04f0d09f390e4d9318894b9f6ac7fd83897cd8d18896ba579c401e929181900390910190a1600061184a565b60185460009062010000900460ff1615611e97576040805162461bcd60e51b81526020600482015260126024820152711c1c9bdd1bd8dbdb081a5cc81c185d5cd95960721b604482015290519081900360640190fd5b6001600160a01b03861660009081526009602052604090205460ff1680611ecb57506015546001600160a01b038781169116145b1580611ef057506001600160a01b03851660009081526009602052604090205460ff16155b15611eff5760095b9050612044565b600080611f1085600080600061479f565b91935090915060009050826012811115611f2657fe5b14611f4057816012811115611f3757fe5b92505050612044565b80611f4c576003611f37565b6015546000906001600160a01b038a8116911614611fed57886001600160a01b03166395dd9193876040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b158015611fba57600080fd5b505afa158015611fce573d6000803e3d6000fd5b505050506040513d6020811015611fe457600080fd5b50519050612008565b506001600160a01b0385166000908152601660205260409020545b6000612024604051806020016040528060055481525083614f8e565b90508086111561203b576011945050505050612044565b60009450505050505b95945050505050565b6000546001600160a01b03163314806120705750601e546001600160a01b031633145b6120ab5760405162461bcd60e51b8152600401808060200182810382526035815260200180615d656035913960400191505060405180910390fd5b828181158015906120bb57508082145b6120fc576040805162461bcd60e51b815260206004820152600d60248201526c1a5b9d985b1a59081a5b9c1d5d609a1b604482015290519081900360640190fd5b60005b828110156121d45784848281811061211357fe5b90506020020135601f600089898581811061212a57fe5b905060200201356001600160a01b03166001600160a01b03166001600160a01b031681526020019081526020016000208190555086868281811061216a57fe5b905060200201356001600160a01b03166001600160a01b03167f6f1951b2aad10f3fc81b86d91105b413a5b3f847a34bbc5ce1904201b14438f68686848181106121b057fe5b905060200201356040518082815260200191505060405180910390a26001016120ff565b50505050505050565b6000546001600160a01b0316331461222d576040805162461bcd60e51b815260206004820152600e60248201526d37b7363c9030b236b4b71031b0b760911b604482015290519081900360640190fd5b601a805490829055604080518281526020810184905281517fe81d4ac15e5afa1e708e66664eddc697177423d950d133bda8262d8885e6da3b929181900390910190a15050565b6119ec565b600c6020526000908152604090205460ff1681565b601c5481565b600b6020526000908152604090205460ff1681565b601854610100900460ff1681565b601b546001600160a01b031681565b6004546001600160a01b031681565b60408051600180825281830190925260609160208083019080388339019050509050828160008151811061230557fe5b60200260200101906001600160a01b031690816001600160a01b031681525050611d828183600180612f4a565b600e5481565b600a54600160b01b900460ff1681565b60146020526000908152604090205481565b60096020526000908152604090208054600182015460039092015460ff91821692911683565b6015546001600160a01b031681565b6001600160a01b038082166000908152600960209081526040808320938616835260029093019052205460ff165b92915050565b60075481565b600080546001600160a01b031633146123e8576117fd60016015614739565b601580546001600160a01b038481166001600160a01b0319831681179093556040805191909216808252602082019390935281517fe1ddcb2dab8e5b03cfc8c67a0d5861d91d16f7bd2612fd381faf4541d212c9b2929181900390910190a150919050565b612455614fad565b6124a6576040805162461bcd60e51b815260206004820152601e60248201527f6f6e6c792061646d696e2063616e207365742076656e75732073706565640000604482015290519081900360640190fd5b6124b08282614fd6565b5050565b600080546001600160a01b031633146124d3576117fd60016012614739565b6001600160a01b03821660009081526009602052604090205460ff1615612500576117fd600a6011614739565b816001600160a01b0316633d9ea3a16040518163ffffffff1660e01b815260040160206040518083038186803b15801561253957600080fd5b505afa15801561254d573d6000803e3d6000fd5b505050506040513d602081101561256357600080fd5b5050604080516060810182526001808252600060208381018281528486018381526001600160a01b03891684526009909252949091209251835490151560ff199182161784559351918301919091555160039091018054911515919092161790556125cd82615368565b604080516001600160a01b038416815290517fcf583bb0c569eb967f806b11601c4cb93c10310485c67add5f8362c2f212321f9181900360200190a1600092915050565b600480546040805163fc57d4df60e01b81526001600160a01b038681169482019490945290516000938493670de0b6b3a7640000938593929091169163fc57d4df91602480820192602092909190829003018186803b15801561267357600080fd5b505afa158015612687573d6000803e3d6000fd5b505050506040513d602081101561269d57600080fd5b50519050806126b657600d9350600092506127af915050565b6000866001600160a01b031663182df0f56040518163ffffffff1660e01b815260040160206040518083038186803b1580156126f157600080fd5b505afa158015612705573d6000803e3d6000fd5b505050506040513d602081101561271b57600080fd5b505190506000612729615c84565b612731615c84565b612739615c84565b612761604051806020016040528060065481525060405180602001604052808a815250615446565b9250612789604051806020016040528088815250604051806020016040528088815250615446565b91506127958383615485565b90506127a1818b614f8e565b600099509750505050505050505b9250929050565b6001600160a01b03811660009081526008602090815260409182902080548351818402810184019094528084526060939283018282801561282057602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612802575b50505050509050919050565b600a54600160b81b900460ff1681565b61155b81600d80548060200260200160405190810160405280929190818152602001828054801561289657602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612878575b50505050506122d5565b6060600d8054806020026020016040519081016040528092919081815260200182805480156128f857602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116128da575b5050505050905090565b6020546001600160a01b031681565b6010602052600090815260409020546001600160e01b03811690600160e01b900463ffffffff1682565b6002546001600160a01b031681565b60185460009062010000900460ff16156129a0576040805162461bcd60e51b81526020600482015260126024820152711c1c9bdd1bd8dbdb081a5cc81c185d5cd95960721b604482015290519081900360640190fd5b600a54600160b01b900460ff16156129f4576040805162461bcd60e51b81526020600482015260126024820152711d1c985b9cd9995c881a5cc81c185d5cd95960721b604482015290519081900360640190fd5b6000612a018686856154c1565b90508015612a10579050611689565b612a1986614b0c565b612a238686614d96565b6116838685614d96565b60175481565b73cf6bb5389c92bdda8a3747ddb454cb7a64626c6390565b60408051828152602080840282010190915260609082908290828015612a7b578160200160208202803883390190505b50905060005b82811015612ad857612aae868683818110612a9857fe5b905060200201356001600160a01b03163361556d565b6012811115612ab957fe5b828281518110612ac557fe5b6020908102919091010152600101612a81565b50949350505050565b600480546040805163fc57d4df60e01b81526001600160a01b038781169482019490945290516000938493849391169163fc57d4df91602480820192602092909190829003018186803b158015612b3757600080fd5b505afa158015612b4b573d6000803e3d6000fd5b505050506040513d6020811015612b6157600080fd5b5051600480546040805163fc57d4df60e01b81526001600160a01b038a8116948201949094529051939450600093929091169163fc57d4df91602480820192602092909190829003018186803b158015612bba57600080fd5b505afa158015612bce573d6000803e3d6000fd5b505050506040513d6020811015612be457600080fd5b50519050811580612bf3575080155b15612c0857600d935060009250612d01915050565b6000866001600160a01b031663182df0f56040518163ffffffff1660e01b815260040160206040518083038186803b158015612c4357600080fd5b505afa158015612c57573d6000803e3d6000fd5b505050506040513d6020811015612c6d57600080fd5b505190506000612c7b615c84565b612c83615c84565b612c8b615c84565b612cb3604051806020016040528060065481525060405180602001604052808a815250615446565b9250612cdb604051806020016040528088815250604051806020016040528088815250615446565b9150612ce78383615485565b9050612cf3818b614f8e565b600099509750505050505050505b935093915050565b6ec097ce7bc90715b34b9f100000000081565b6021546001600160a01b031681565b60185460009062010000900460ff1615612d81576040805162461bcd60e51b81526020600482015260126024820152711c1c9bdd1bd8dbdb081a5cc81c185d5cd95960721b604482015290519081900360640190fd5b600a54600160b81b900460ff1615612dd2576040805162461bcd60e51b815260206004820152600f60248201526e1cd95a5e99481a5cc81c185d5cd959608a1b604482015290519081900360640190fd5b6001600160a01b03861660009081526009602052604090205460ff161580612e2b57506001600160a01b03851660009081526009602052604090205460ff1680612e2957506015546001600160a01b038681169116145b155b15612e37576009611ef8565b846001600160a01b0316635fe3b5676040518163ffffffff1660e01b815260040160206040518083038186803b158015612e7057600080fd5b505afa158015612e84573d6000803e3d6000fd5b505050506040513d6020811015612e9a57600080fd5b505160408051635fe3b56760e01b815290516001600160a01b0392831692891691635fe3b567916004808301926020929190829003018186803b158015612ee057600080fd5b505afa158015612ef4573d6000803e3d6000fd5b505050506040513d6020811015612f0a57600080fd5b50516001600160a01b031614612f21576002611ef8565b612f2a86614b0c565b612f348684614d96565b612f3e8685614d96565b60009695505050505050565b6015546000906001600160a01b031615612fdb57601560009054906101000a90046001600160a01b03166001600160a01b031663d244b0816040518163ffffffff1660e01b8152600401602060405180830381600087803b158015612fae57600080fd5b505af1158015612fc2573d6000803e3d6000fd5b505050506040513d6020811015612fd857600080fd5b50505b5060005b845181101561309557613004858281518110612ff757fe5b60200260200101516140c2565b61305985828151811061301357fe5b60200260200101516014600088858151811061302b57fe5b60200260200101516001600160a01b03166001600160a01b031681526020019081526020016000205461565e565b6014600087848151811061306957fe5b6020908102919091018101516001600160a01b0316825281019190915260400160002055600101612fdf565b60005b8451811015611a065760008582815181106130af57fe5b6020908102919091018101516001600160a01b0381166000908152600990925260409091205490915060ff16613120576040805162461bcd60e51b81526020600482015260116024820152701b9bdd081b1a5cdd1959081b585c9ad95d607a1b604482015290519081900360640190fd5b84156132405761312e615c84565b6040518060200160405280836001600160a01b031663aa5af0fd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561317257600080fd5b505afa158015613186573d6000803e3d6000fd5b505050506040513d602081101561319c57600080fd5b5051905290506131ac82826142f5565b600093505b875184101561323e576131d8828986815181106131ca57fe5b602002602001015183614589565b6131ff8885815181106131e757fe5b6020026020010151601460008b888151811061302b57fe5b601460008a878151811061320f57fe5b6020908102919091018101516001600160a01b03168252810191909152604001600020556001909301926131b1565b505b83156132e05761324f81614b0c565b600092505b86518310156132e05761327a8188858151811061326d57fe5b6020026020010151614d96565b6132a187848151811061328957fe5b6020026020010151601460008a878151811061302b57fe5b601460008986815181106132b157fe5b6020908102919091018101516001600160a01b0316825281019190915260400160002055600190920191613254565b50600101613098565b600080546001600160a01b031633148061330d57506020546001600160a01b031633145b61331d57611bf560016017614739565b670de0b6b3a76400008210613379576040805162461bcd60e51b815260206004820152601d60248201527f74726561737572792070657263656e7420636170206f766572666c6f77000000604482015290519081900360640190fd5b6020805460218054602280546001600160a01b038a81166001600160a01b0319808816821789558b8316908616179095559188905560408051958316808752968601949094528351929091169390927f29f06ea15931797ebaed313d81d100963dc22cb213cb4ce2737b5a62b1a8b1e892918290030190a1604080516001600160a01b0380851682528816602082015281517f8de763046d7b8f08b6c3d03543de1d615309417842bb5d2d62f110f65809ddac929181900390910190a1604080518281526020810187905281517f0893f8f4101baaabbeb513f96761e7a36eb837403c82cc651c292a4abdc94ed7929181900390910190a16000979650505050505050565b60185460009062010000900460ff16156134d4576040805162461bcd60e51b81526020600482015260126024820152711c1c9bdd1bd8dbdb081a5cc81c185d5cd95960721b604482015290519081900360640190fd5b6001600160a01b0384166000908152600c602052604090205460ff1615613535576040805162461bcd60e51b815260206004820152601060248201526f189bdc9c9bddc81a5cc81c185d5cd95960821b604482015290519081900360640190fd5b6001600160a01b03841660009081526009602052604090205460ff1661355c576009611bf5565b6001600160a01b038085166000908152600960209081526040808320938716835260029093019052205460ff1661361957336001600160a01b038516146135e2576040805162461bcd60e51b815260206004820152601560248201527439b2b73232b91036bab9ba103132903b2a37b5b2b760591b604482015290519081900360640190fd5b60006135ee858561556d565b905060008160128111156135fe57fe5b146136175780601281111561360f57fe5b915050611c15565b505b600480546040805163fc57d4df60e01b81526001600160a01b03888116948201949094529051929091169163fc57d4df91602480820192602092909190829003018186803b15801561366a57600080fd5b505afa15801561367e573d6000803e3d6000fd5b505050506040513d602081101561369457600080fd5b50516136a157600d611bf5565b6001600160a01b0384166000908152601f6020526040902054801561378e576000856001600160a01b03166347bd37186040518163ffffffff1660e01b815260040160206040518083038186803b1580156136fb57600080fd5b505afa15801561370f573d6000803e3d6000fd5b505050506040513d602081101561372557600080fd5b5051905060006137358286615798565b905082811061378b576040805162461bcd60e51b815260206004820152601960248201527f6d61726b657420626f72726f7720636170207265616368656400000000000000604482015290519081900360640190fd5b50505b60008061379e868860008861479f565b919350909150600090508260128111156137b457fe5b146137cf578160128111156137c557fe5b9350505050611c15565b80156137dc5760046137c5565b6137e4615c84565b6040518060200160405280896001600160a01b031663aa5af0fd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561382857600080fd5b505afa15801561383c573d6000803e3d6000fd5b505050506040513d602081101561385257600080fd5b50519052905061386288826142f5565b61386d888883614589565b600098975050505050505050565b6008602052816000526040600020818154811061389457fe5b6000918252602090912001546001600160a01b03169150829050565b6003546001600160a01b031681565b601c5415806138d65750601c546138d4611a01565b105b156138e057613aed565b60006138ea612a33565b604080516370a0823160e01b815230600482015290519192506000916001600160a01b038416916370a08231916024808301926020929190829003018186803b15801561393657600080fd5b505afa15801561394a573d6000803e3d6000fd5b505050506040513d602081101561396057600080fd5b5051905080613970575050613aed565b60008061398661397e611a01565b601c546157ce565b90506000613996601a5483615808565b9050601d548110156139ac575050505050613aed565b8084106139bb578092506139bf565b8392505b6139c7611a01565b601c55601b546040805163a9059cbb60e01b81526001600160a01b0392831660048201526024810186905290519187169163a9059cbb916044808201926020929091908290030181600087803b158015613a2057600080fd5b505af1158015613a34573d6000803e3d6000fd5b505050506040513d6020811015613a4a57600080fd5b50506040805184815290517ff6d4b8f74d85a6e2d7a50225957b8a6cfec69ad92f5905627260541aa0a5565d9181900360200190a1601b60009054906101000a90046001600160a01b03166001600160a01b031663faa1809e6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015613acf57600080fd5b505af1158015613ae3573d6000803e3d6000fd5b5050505050505050505b565b6011602052600090815260409020546001600160e01b03811690600160e01b900463ffffffff1682565b600080546001600160a01b03163314613b3f57613b3860016006614739565b90506123bd565b6001600160a01b0383166000908152600960205260409020805460ff16613b7457613b6c60096007614739565b9150506123bd565b613b7c615c84565b506040805160208101909152838152613b93615c84565b506040805160208101909152670c7d713b49da00008152613bb4818361584a565b15613bcf57613bc560066008614739565b93505050506123bd565b8415801590613c585750600480546040805163fc57d4df60e01b81526001600160a01b038a8116948201949094529051929091169163fc57d4df91602480820192602092909190829003018186803b158015613c2a57600080fd5b505afa158015613c3e573d6000803e3d6000fd5b505050506040513d6020811015613c5457600080fd5b5051155b15613c6957613bc5600d6009614739565b60018301805490869055604080516001600160a01b03891681526020810183905280820188905290517f70483e6592cd5182d45ac970e05bc62cdcc90e9d8ef2c2dbe686cf383bcd7fc59181900360600190a16000979650505050505050565b600a54600160a81b900460ff1681565b6000546001600160a01b03163314613d29576040805162461bcd60e51b815260206004820152600e60248201526d37b7363c9030b236b4b71031b0b760911b604482015290519081900360640190fd5b6019805490829055604080518281526020810184905281517f75c84862cb29e997a2ed3ab3c3db0f5af24a181e6bf58897c5ea676668511c19929181900390910190a15050565b60055481565b60185460009062010000900460ff1615613dcc576040805162461bcd60e51b81526020600482015260126024820152711c1c9bdd1bd8dbdb081a5cc81c185d5cd95960721b604482015290519081900360640190fd5b6000613dd98585856154c1565b90508015613de8579050611c15565b613df185614b0c565b613dfb8585614d96565b600095945050505050565b6000808290506000806000836001600160a01b031663c37f68e2336040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060806040518083038186803b158015613e6757600080fd5b505afa158015613e7b573d6000803e3d6000fd5b505050506040513d6080811015613e9157600080fd5b508051602082015160409092015190945090925090508215613efa576040805162461bcd60e51b815260206004820152601960248201527f6765744163636f756e74536e617073686f74206661696c656400000000000000604482015290519081900360640190fd5b8015613f1757613f0c600c6002614739565b94505050505061184e565b6000613f248733856154c1565b90508015613f4557613f39600e600383615851565b9550505050505061184e565b6001600160a01b0385166000908152600960209081526040808320338452600281019092529091205460ff16613f84576000965050505050505061184e565b3360009081526002820160209081526040808320805460ff1916905560089091528120805490915b8181101561406557886001600160a01b0316838281548110613fca57fe5b6000918252602090912001546001600160a01b0316141561405d57826001830381548110613ff457fe5b9060005260206000200160009054906101000a90046001600160a01b031683828154811061401e57fe5b600091825260209091200180546001600160a01b0319166001600160a01b03929092169190911790558254614057846000198301615c97565b50614065565b600101613fac565b81811061406e57fe5b604080516001600160a01b038b16815233602082015281517fe699a64c18b07ac5b7301aa273f36a2287239eb9501d81950672794afba29a0d929181900390910190a160009b9a5050505050505050505050565b601b546001600160a01b0316156140db576140db6138bf565b6015546001600160a01b03161561155b576015546040805163d178273b60e01b81526001600160a01b0384811660048301529151600093849384938493919092169163d178273b91602480830192608092919082900301818787803b15801561414357600080fd5b505af1158015614157573d6000803e3d6000fd5b505050506040513d608081101561416d57600080fd5b5080516020820151604083015160609093015190965091945090925090508061155e576001600160a01b038516600081815260146020908152604091829020879055815186815290810185905281517f2fb3baf25f3d9fc9f9eb9dfd7da8567731a91413437d91bc1b8a839d0a1ba88f929181900390910190a25050505050565b6000546001600160a01b031681565b601a5481565b60185460009062010000900460ff1615614259576040805162461bcd60e51b81526020600482015260126024820152711c1c9bdd1bd8dbdb081a5cc81c185d5cd95960721b604482015290519081900360640190fd5b60185460ff161580156142745750601854610100900460ff16155b6142b5576040805162461bcd60e51b815260206004820152600d60248201526c159052481a5cc81c185d5cd959609a1b604482015290519081900360640190fd5b6015546001600160a01b031633146142d357613b38600e6016614739565b6001600160a01b03831660009081526016602052604081208390559392505050565b6001600160a01b0382166000908152601160209081526040808320600f9092528220549091614322611a01565b8354909150600090614342908390600160e01b900463ffffffff166157ce565b90506000811180156143545750600083115b156145245760006143c9876001600160a01b03166347bd37186040518163ffffffff1660e01b815260040160206040518083038186803b15801561439757600080fd5b505afa1580156143ab573d6000803e3d6000fd5b505050506040513d60208110156143c157600080fd5b5051876158b7565b905060006143d78386615808565b90506143e1615c84565b600083116143fe5760405180602001604052806000815250614408565b61440882846158d5565b9050614412615c84565b604080516020810190915288546001600160e01b03168152614434908361590a565b9050604051806040016040528061447a8360000151604051806040016040528060138152602001726e657720696e646578206f766572666c6f777360681b81525061592f565b6001600160e01b031681526020016144c08860405180604001604052806016815260200175626c6f636b206e756d626572206f766572666c6f777360501b8152506159c9565b63ffffffff9081169091526001600160a01b038c166000908152601160209081526040909120835181549490920151909216600160e01b026001600160e01b039182166001600160e01b0319909416939093171691909117905550611a0692505050565b8015611a06576145628260405180604001604052806016815260200175626c6f636b206e756d626572206f766572666c6f777360501b8152506159c9565b845463ffffffff91909116600160e01b026001600160e01b03909116178455505050505050565b601b546001600160a01b0316156145a2576145a26138bf565b6001600160a01b03831660009081526011602052604090206145c2615c84565b50604080516020810190915281546001600160e01b031681526145e3615c84565b5060408051602080820183526001600160a01b0380891660009081526013835284812091891680825282845294812080548552865195909152915291909155805115611a0657614631615c84565b61463b8383615a1e565b90506000614698886001600160a01b03166395dd9193896040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561439757600080fd5b905060006146a68284615a43565b6001600160a01b038916600090815260146020526040812054919250906146cd9083615798565b6001600160a01b03808b166000818152601460209081526040918290208590558a5182518881529182015281519495509193928e16927f837bdc11fca9f17ce44167944475225a205279b17e88c791c3b1f66f354668fb9281900390910190a350505050505050505050565b60007f45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa083601281111561476857fe5b83601781111561477457fe5b604080519283526020830191909152600082820152519081900360600190a1826012811115611c1557fe5b60008060006147ac615cbb565b6001600160a01b0388166000908152600860209081526040808320805482518185028101850190935280835260609383018282801561481457602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116147f6575b50939450600093505050505b8151811015614a9857600082828151811061483757fe5b60200260200101519050806001600160a01b031663c37f68e28d6040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060806040518083038186803b15801561489757600080fd5b505afa1580156148ab573d6000803e3d6000fd5b505050506040513d60808110156148c157600080fd5b508051602082015160408084015160609485015160808b01529389019390935291870191909152935083156149065750600f965060009550859450611b139350505050565b60408051602080820183526001600160a01b0380851660008181526009845285902060010154845260c08a01939093528351808301855260808a0151815260e08a015260048054855163fc57d4df60e01b815291820194909452935192169263fc57d4df9260248083019392829003018186803b15801561498657600080fd5b505afa15801561499a573d6000803e3d6000fd5b505050506040513d60208110156149b057600080fd5b505160a086018190526149d35750600d965060009550859450611b139350505050565b604080516020810190915260a0860151815261010086015260c085015160e0860151614a0d91614a0291615446565b866101000151615446565b610120860181905260408601518651614a27929190615a72565b855261010085015160608601516020870151614a44929190615a72565b60208601526001600160a01b03818116908c161415614a8f57614a718561012001518b8760200151615a72565b60208601819052610100860151614a89918b90615a72565b60208601525b50600101614820565b50614acc8360200151601660008d6001600160a01b03166001600160a01b0316815260200190815260200160002054615798565b6020840181905283511115614af35750506020810151905160009450039150829050611b13565b5050805160209091015160009450849350039050611b13565b6001600160a01b0381166000908152601060209081526040808320600f9092528220549091614b39611a01565b8354909150600090614b59908390600160e01b900463ffffffff166157ce565b9050600081118015614b6b5750600083115b15614d32576000856001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b158015614bab57600080fd5b505afa158015614bbf573d6000803e3d6000fd5b505050506040513d6020811015614bd557600080fd5b505190506000614be58386615808565b9050614bef615c84565b60008311614c0c5760405180602001604052806000815250614c16565b614c1682846158d5565b9050614c20615c84565b604080516020810190915288546001600160e01b03168152614c42908361590a565b90506040518060400160405280614c888360000151604051806040016040528060138152602001726e657720696e646578206f766572666c6f777360681b81525061592f565b6001600160e01b03168152602001614cce8860405180604001604052806016815260200175626c6f636b206e756d626572206f766572666c6f777360501b8152506159c9565b63ffffffff9081169091526001600160a01b038b166000908152601060209081526040909120835181549490920151909216600160e01b026001600160e01b039182166001600160e01b031990941693909317169190911790555061155e92505050565b801561155e57614d708260405180604001604052806016815260200175626c6f636b206e756d626572206f766572666c6f777360501b8152506159c9565b845463ffffffff91909116600160e01b026001600160e01b039091161784555050505050565b601b546001600160a01b031615614daf57614daf6138bf565b6001600160a01b0382166000908152601060205260409020614dcf615c84565b50604080516020810190915281546001600160e01b03168152614df0615c84565b5060408051602080820183526001600160a01b03808816600090815260128352848120918816808252828452948120805485528651959091529152919091558051158015614e3e5750815115155b15614e56576ec097ce7bc90715b34b9f100000000081525b614e5e615c84565b614e688383615a1e565b90506000866001600160a01b03166370a08231876040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b158015614ec257600080fd5b505afa158015614ed6573d6000803e3d6000fd5b505050506040513d6020811015614eec57600080fd5b505190506000614efc8284615a43565b6001600160a01b03881660009081526014602052604081205491925090614f239083615798565b6001600160a01b03808a166000818152601460209081526040918290208590558a5182518881529182015281519495509193928d16927ffa9d964d891991c113b49e3db1932abd6c67263d387119707aafdd6c4010a3a99281900390910190a3505050505050505050565b6000614f98615c84565b614fa28484615a9a565b905061168981615abb565b600080546001600160a01b0316331480614fd157506002546001600160a01b031633145b905090565b6001600160a01b0382166000908152600f6020526040902054801561508a57614ffd615c84565b6040518060200160405280856001600160a01b031663aa5af0fd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561504157600080fd5b505afa158015615055573d6000803e3d6000fd5b505050506040513d602081101561506b57600080fd5b50519052905061507a84614b0c565b61508484826142f5565b5061530c565b811561530c576001600160a01b0383166000908152600960205260409020805460ff161515600114615103576040805162461bcd60e51b815260206004820152601a60248201527f76656e7573206d61726b6574206973206e6f74206c6973746564000000000000604482015290519081900360640190fd5b6001600160a01b0384166000908152601060205260409020546001600160e01b031615801561515557506001600160a01b038416600090815260106020526040902054600160e01b900463ffffffff16155b156152245760405180604001604052806ec097ce7bc90715b34b9f10000000006001600160e01b031681526020016151c961518e611a01565b6040518060400160405280601c81526020017f626c6f636b206e756d62657220657863656564732033322062697473000000008152506159c9565b63ffffffff9081169091526001600160a01b0386166000908152601060209081526040909120835181549490920151909216600160e01b026001600160e01b039182166001600160e01b031990941693909317169190911790555b6001600160a01b0384166000908152601160205260409020546001600160e01b031615801561527657506001600160a01b038416600090815260116020526040902054600160e01b900463ffffffff16155b1561530a5760405180604001604052806ec097ce7bc90715b34b9f10000000006001600160e01b031681526020016152af61518e611a01565b63ffffffff9081169091526001600160a01b0386166000908152601160209081526040909120835181549490920151909216600160e01b026001600160e01b039182166001600160e01b031990941693909317169190911790555b505b818114611d82576001600160a01b0383166000818152600f6020908152604091829020859055815185815291517f2a0ce45ba05a83e75ba21e1a10d6b48a8395028cc6e1ae66f6c313648379d5489281900390910190a2505050565b60005b600d548110156153f357816001600160a01b0316600d828154811061538c57fe5b6000918252602090912001546001600160a01b031614156153eb576040805162461bcd60e51b81526020600482015260146024820152731b585c9ad95d08185b1c9958591e48185919195960621b604482015290519081900360640190fd5b60010161536b565b50600d80546001810182556000919091527fd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb50180546001600160a01b0319166001600160a01b0392909216919091179055565b61544e615c84565b6040518060200160405280670de0b6b3a764000061547486600001518660000151615808565b8161547b57fe5b0490529392505050565b61548d615c84565b60405180602001604052806154b86154b18660000151670de0b6b3a7640000615808565b8551615aca565b90529392505050565b6001600160a01b03831660009081526009602052604081205460ff166154e8576009611bf5565b6001600160a01b038085166000908152600960209081526040808320938716835260029093019052205460ff16615520576000611bf5565b600080615530858786600061479f565b9193509091506000905082601281111561554657fe5b146155605781601281111561555757fe5b92505050611c15565b8015612f3e576004615557565b6001600160a01b0382166000908152600960205260408120805460ff166155985760099150506123bd565b6001600160a01b038316600090815260028201602052604090205460ff16156155c55760009150506123bd565b6001600160a01b0380841660008181526002840160209081526040808320805460ff19166001908117909155600883528184208054918201815584529282902090920180549489166001600160a01b031990951685179055815193845283019190915280517f3ab23ab0d51cccc0c3085aec51f99228625aa1a922b3a8ca89a26b0f2027a1a59281900390910190a15060009392505050565b600080615669612a33565b604080516370a0823160e01b815230600482015290519192506000916001600160a01b038416916370a08231916024808301926020929190829003018186803b1580156156b557600080fd5b505afa1580156156c9573d6000803e3d6000fd5b505050506040513d60208110156156df57600080fd5b5051905083158015906156f25750808411155b1561578f57816001600160a01b031663a9059cbb86866040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050602060405180830381600087803b15801561575757600080fd5b505af115801561576b573d6000803e3d6000fd5b505050506040513d602081101561578157600080fd5b50600093506123bd92505050565b50919392505050565b6000611c158383604051806040016040528060118152602001706164646974696f6e206f766572666c6f7760781b815250615afd565b6000611c158383604051806040016040528060158152602001747375627472616374696f6e20756e646572666c6f7760581b815250615b52565b6000611c1583836040518060400160405280601781526020017f6d756c7469706c69636174696f6e206f766572666c6f77000000000000000000815250615bac565b5190511090565b60007f45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa084601281111561588057fe5b84601781111561588c57fe5b604080519283526020830191909152818101859052519081900360600190a1836012811115611c1257fe5b6000611c156158ce84670de0b6b3a7640000615808565b8351615aca565b6158dd615c84565b60405180602001604052806154b8615904866ec097ce7bc90715b34b9f1000000000615808565b85615aca565b615912615c84565b60405180602001604052806154b885600001518560000151615798565b600081600160e01b84106159c15760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561598657818101518382015260200161596e565b50505050905090810190601f1680156159b35780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b509192915050565b600081600160201b84106159c15760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561598657818101518382015260200161596e565b615a26615c84565b60405180602001604052806154b8856000015185600001516157ce565b60006ec097ce7bc90715b34b9f1000000000615a63848460000151615808565b81615a6a57fe5b049392505050565b6000615a7c615c84565b615a868585615a9a565b9050612044615a9482615abb565b84615798565b615aa2615c84565b60405180602001604052806154b8856000015185615808565b51670de0b6b3a7640000900490565b6000611c1583836040518060400160405280600e81526020016d646976696465206279207a65726f60901b815250615c22565b60008383018285821015612ad85760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561598657818101518382015260200161596e565b60008184841115615ba45760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561598657818101518382015260200161596e565b505050900390565b6000831580615bb9575082155b15615bc657506000611c15565b83830283858281615bd357fe5b04148390612ad85760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561598657818101518382015260200161596e565b60008183615c715760405162461bcd60e51b815260206004820181815283516024840152835190928392604490910191908501908083836000831561598657818101518382015260200161596e565b50828481615c7b57fe5b04949350505050565b6040518060200160405280600081525090565b815481835581811115611d8257600083815260209020611d82918101908301615d25565b604051806101400160405280600081526020016000815260200160008152602001600081526020016000815260200160008152602001615cf9615c84565b8152602001615d06615c84565b8152602001615d13615c84565b8152602001615d20615c84565b905290565b611a0391905b80821115615d3f5760008155600101615d2b565b509056fe6f6e6c7920706175736520677561726469616e20616e642061646d696e2063616e6f6e6c792061646d696e206f7220626f72726f772063617020677561726469616e2063616e2073657420626f72726f772063617073a265627a7a72315820854ec136f575c0f509b5e3a3cb71f2a3be455e4452203fe10cc88c0673c6168564736f6c63430005110032", + "abi":[{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"action","type":"string"},{"indexed":false,"internalType":"bool","name":"pauseState","type":"bool"}],"name":"ActionPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract VToken","name":"vToken","type":"address"},{"indexed":false,"internalType":"string","name":"action","type":"string"},{"indexed":false,"internalType":"bool","name":"pauseState","type":"bool"}],"name":"ActionPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"state","type":"bool"}],"name":"ActionProtocolPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract VToken","name":"vToken","type":"address"},{"indexed":true,"internalType":"address","name":"borrower","type":"address"},{"indexed":false,"internalType":"uint256","name":"venusDelta","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"venusBorrowIndex","type":"uint256"}],"name":"DistributedBorrowerVenus","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract VToken","name":"vToken","type":"address"},{"indexed":true,"internalType":"address","name":"supplier","type":"address"},{"indexed":false,"internalType":"uint256","name":"venusDelta","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"venusSupplyIndex","type":"uint256"}],"name":"DistributedSupplierVenus","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"vaiMinter","type":"address"},{"indexed":false,"internalType":"uint256","name":"venusDelta","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"venusVAIMintIndex","type":"uint256"}],"name":"DistributedVAIMinterVenus","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"DistributedVAIVaultVenus","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"error","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"info","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"detail","type":"uint256"}],"name":"Failure","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract VToken","name":"vToken","type":"address"},{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"MarketEntered","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract VToken","name":"vToken","type":"address"},{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"MarketExited","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract VToken","name":"vToken","type":"address"}],"name":"MarketListed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract VToken","name":"vToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"newBorrowCap","type":"uint256"}],"name":"NewBorrowCap","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldBorrowCapGuardian","type":"address"},{"indexed":false,"internalType":"address","name":"newBorrowCapGuardian","type":"address"}],"name":"NewBorrowCapGuardian","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldCloseFactorMantissa","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newCloseFactorMantissa","type":"uint256"}],"name":"NewCloseFactor","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract VToken","name":"vToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"oldCollateralFactorMantissa","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newCollateralFactorMantissa","type":"uint256"}],"name":"NewCollateralFactor","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldLiquidationIncentiveMantissa","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newLiquidationIncentiveMantissa","type":"uint256"}],"name":"NewLiquidationIncentive","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldPauseGuardian","type":"address"},{"indexed":false,"internalType":"address","name":"newPauseGuardian","type":"address"}],"name":"NewPauseGuardian","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract PriceOracle","name":"oldPriceOracle","type":"address"},{"indexed":false,"internalType":"contract PriceOracle","name":"newPriceOracle","type":"address"}],"name":"NewPriceOracle","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldTreasuryAddress","type":"address"},{"indexed":false,"internalType":"address","name":"newTreasuryAddress","type":"address"}],"name":"NewTreasuryAddress","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldTreasuryGuardian","type":"address"},{"indexed":false,"internalType":"address","name":"newTreasuryGuardian","type":"address"}],"name":"NewTreasuryGuardian","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldTreasuryPercent","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newTreasuryPercent","type":"uint256"}],"name":"NewTreasuryPercent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract VAIControllerInterface","name":"oldVAIController","type":"address"},{"indexed":false,"internalType":"contract VAIControllerInterface","name":"newVAIController","type":"address"}],"name":"NewVAIController","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldVAIMintRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newVAIMintRate","type":"uint256"}],"name":"NewVAIMintRate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"vault_","type":"address"},{"indexed":false,"internalType":"uint256","name":"releaseStartBlock_","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"releaseInterval_","type":"uint256"}],"name":"NewVAIVaultInfo","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldVenusVAIRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newVenusVAIRate","type":"uint256"}],"name":"NewVenusVAIRate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldVenusVAIVaultRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newVenusVAIVaultRate","type":"uint256"}],"name":"NewVenusVAIVaultRate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract VToken","name":"vToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"newSpeed","type":"uint256"}],"name":"VenusSpeedUpdated","type":"event"},{"constant":false,"inputs":[{"internalType":"contract Unitroller","name":"unitroller","type":"address"}],"name":"_become","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"_borrowGuardianPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"_mintGuardianPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"newBorrowCapGuardian","type":"address"}],"name":"_setBorrowCapGuardian","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"newCloseFactorMantissa","type":"uint256"}],"name":"_setCloseFactor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"contract VToken","name":"vToken","type":"address"},{"internalType":"uint256","name":"newCollateralFactorMantissa","type":"uint256"}],"name":"_setCollateralFactor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"newLiquidationIncentiveMantissa","type":"uint256"}],"name":"_setLiquidationIncentive","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"contract VToken[]","name":"vTokens","type":"address[]"},{"internalType":"uint256[]","name":"newBorrowCaps","type":"uint256[]"}],"name":"_setMarketBorrowCaps","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"newPauseGuardian","type":"address"}],"name":"_setPauseGuardian","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"contract PriceOracle","name":"newOracle","type":"address"}],"name":"_setPriceOracle","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bool","name":"state","type":"bool"}],"name":"_setProtocolPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"newTreasuryGuardian","type":"address"},{"internalType":"address","name":"newTreasuryAddress","type":"address"},{"internalType":"uint256","name":"newTreasuryPercent","type":"uint256"}],"name":"_setTreasuryData","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"contract VAIControllerInterface","name":"vaiController_","type":"address"}],"name":"_setVAIController","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"newVAIMintRate","type":"uint256"}],"name":"_setVAIMintRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"vault_","type":"address"},{"internalType":"uint256","name":"releaseStartBlock_","type":"uint256"},{"internalType":"uint256","name":"minReleaseAmount_","type":"uint256"}],"name":"_setVAIVaultInfo","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"contract VToken","name":"vToken","type":"address"},{"internalType":"uint256","name":"venusSpeed","type":"uint256"}],"name":"_setVenusSpeed","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"venusVAIRate_","type":"uint256"}],"name":"_setVenusVAIRate","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"venusVAIVaultRate_","type":"uint256"}],"name":"_setVenusVAIVaultRate","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"contract VToken","name":"vToken","type":"address"}],"name":"_supportMarket","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"accountAssets","outputs":[{"internalType":"contract VToken","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"allMarkets","outputs":[{"internalType":"contract VToken","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"vToken","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"borrowAmount","type":"uint256"}],"name":"borrowAllowed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"borrowCapGuardian","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"borrowCaps","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"borrowGuardianPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"vToken","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"borrowAmount","type":"uint256"}],"name":"borrowVerify","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"contract VToken","name":"vToken","type":"address"}],"name":"checkMembership","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"holder","type":"address"},{"internalType":"contract VToken[]","name":"vTokens","type":"address[]"}],"name":"claimVenus","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"holder","type":"address"}],"name":"claimVenus","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address[]","name":"holders","type":"address[]"},{"internalType":"contract VToken[]","name":"vTokens","type":"address[]"},{"internalType":"bool","name":"borrowers","type":"bool"},{"internalType":"bool","name":"suppliers","type":"bool"}],"name":"claimVenus","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"closeFactorMantissa","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"comptrollerImplementation","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"vaiMinter","type":"address"}],"name":"distributeVAIMinterVenus","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address[]","name":"vTokens","type":"address[]"}],"name":"enterMarkets","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"vTokenAddress","type":"address"}],"name":"exitMarket","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getAccountLiquidity","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getAllMarkets","outputs":[{"internalType":"contract VToken[]","name":"","type":"address[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getAssetsIn","outputs":[{"internalType":"contract VToken[]","name":"","type":"address[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getBlockNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"address","name":"vTokenModify","type":"address"},{"internalType":"uint256","name":"redeemTokens","type":"uint256"},{"internalType":"uint256","name":"borrowAmount","type":"uint256"}],"name":"getHypotheticalAccountLiquidity","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getXVSAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isComptroller","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"vTokenBorrowed","type":"address"},{"internalType":"address","name":"vTokenCollateral","type":"address"},{"internalType":"address","name":"liquidator","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"repayAmount","type":"uint256"}],"name":"liquidateBorrowAllowed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"vTokenBorrowed","type":"address"},{"internalType":"address","name":"vTokenCollateral","type":"address"},{"internalType":"address","name":"liquidator","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"actualRepayAmount","type":"uint256"},{"internalType":"uint256","name":"seizeTokens","type":"uint256"}],"name":"liquidateBorrowVerify","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"vTokenBorrowed","type":"address"},{"internalType":"address","name":"vTokenCollateral","type":"address"},{"internalType":"uint256","name":"actualRepayAmount","type":"uint256"}],"name":"liquidateCalculateSeizeTokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"vTokenCollateral","type":"address"},{"internalType":"uint256","name":"actualRepayAmount","type":"uint256"}],"name":"liquidateVAICalculateSeizeTokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"liquidationIncentiveMantissa","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"markets","outputs":[{"internalType":"bool","name":"isListed","type":"bool"},{"internalType":"uint256","name":"collateralFactorMantissa","type":"uint256"},{"internalType":"bool","name":"isVenus","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"maxAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"minReleaseAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"vToken","type":"address"},{"internalType":"address","name":"minter","type":"address"},{"internalType":"uint256","name":"mintAmount","type":"uint256"}],"name":"mintAllowed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"mintGuardianPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"mintVAIGuardianPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"vToken","type":"address"},{"internalType":"address","name":"minter","type":"address"},{"internalType":"uint256","name":"actualMintAmount","type":"uint256"},{"internalType":"uint256","name":"mintTokens","type":"uint256"}],"name":"mintVerify","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"mintedVAIs","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"oracle","outputs":[{"internalType":"contract PriceOracle","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"pauseGuardian","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"pendingAdmin","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"pendingComptrollerImplementation","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"protocolPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"vToken","type":"address"},{"internalType":"address","name":"redeemer","type":"address"},{"internalType":"uint256","name":"redeemTokens","type":"uint256"}],"name":"redeemAllowed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"vToken","type":"address"},{"internalType":"address","name":"redeemer","type":"address"},{"internalType":"uint256","name":"redeemAmount","type":"uint256"},{"internalType":"uint256","name":"redeemTokens","type":"uint256"}],"name":"redeemVerify","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"releaseStartBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"releaseToVault","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"vToken","type":"address"},{"internalType":"address","name":"payer","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"repayAmount","type":"uint256"}],"name":"repayBorrowAllowed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"vToken","type":"address"},{"internalType":"address","name":"payer","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"actualRepayAmount","type":"uint256"},{"internalType":"uint256","name":"borrowerIndex","type":"uint256"}],"name":"repayBorrowVerify","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"repayVAIGuardianPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"vTokenCollateral","type":"address"},{"internalType":"address","name":"vTokenBorrowed","type":"address"},{"internalType":"address","name":"liquidator","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"seizeTokens","type":"uint256"}],"name":"seizeAllowed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"seizeGuardianPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"vTokenCollateral","type":"address"},{"internalType":"address","name":"vTokenBorrowed","type":"address"},{"internalType":"address","name":"liquidator","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"seizeTokens","type":"uint256"}],"name":"seizeVerify","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"setMintedVAIOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"vToken","type":"address"},{"internalType":"address","name":"src","type":"address"},{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"transferTokens","type":"uint256"}],"name":"transferAllowed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"transferGuardianPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"vToken","type":"address"},{"internalType":"address","name":"src","type":"address"},{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"transferTokens","type":"uint256"}],"name":"transferVerify","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"treasuryAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"treasuryGuardian","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"treasuryPercent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"vaiController","outputs":[{"internalType":"contract VAIControllerInterface","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"vaiMintRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"vaiVaultAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"venusAccrued","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"venusBorrowState","outputs":[{"internalType":"uint224","name":"index","type":"uint224"},{"internalType":"uint32","name":"block","type":"uint32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"venusBorrowerIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"venusInitialIndex","outputs":[{"internalType":"uint224","name":"","type":"uint224"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"venusRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"venusSpeeds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"venusSupplierIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"venusSupplyState","outputs":[{"internalType":"uint224","name":"index","type":"uint224"},{"internalType":"uint32","name":"block","type":"uint32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"venusVAIRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"venusVAIVaultRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"}] +} diff --git a/assets/bsc/Unitroller.json b/assets/bsc/Unitroller.json new file mode 100644 index 00000000..52fb25f1 --- /dev/null +++ b/assets/bsc/Unitroller.json @@ -0,0 +1,125 @@ +{ + "bytecode": "608060405234801561001057600080fd5b50600080546001600160a01b031916331790556105e4806100326000396000f3fe60806040526004361061007b5760003560e01c8063dcfbc0c71161004e578063dcfbc0c71461019e578063e992a041146101b3578063e9c714f2146101e6578063f851a440146101fb5761007b565b806326782247146100fe578063b71d1a0c1461012f578063bb82aa5e14610174578063c1e8033414610189575b6002546040516000916001600160a01b031690829036908083838082843760405192019450600093509091505080830381855af49150503d80600081146100de576040519150601f19603f3d011682016040523d82523d6000602084013e6100e3565b606091505b505090506040513d6000823e8180156100fa573d82f35b3d82fd5b34801561010a57600080fd5b50610113610210565b604080516001600160a01b039092168252519081900360200190f35b34801561013b57600080fd5b506101626004803603602081101561015257600080fd5b50356001600160a01b031661021f565b60408051918252519081900360200190f35b34801561018057600080fd5b506101136102b0565b34801561019557600080fd5b506101626102bf565b3480156101aa57600080fd5b506101136103ba565b3480156101bf57600080fd5b50610162600480360360208110156101d657600080fd5b50356001600160a01b03166103c9565b3480156101f257600080fd5b5061016261044d565b34801561020757600080fd5b50610113610533565b6001546001600160a01b031681565b600080546001600160a01b031633146102455761023e6001600e610542565b90506102ab565b600180546001600160a01b038481166001600160a01b0319831681179093556040805191909216808252602082019390935281517fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9929181900390910190a160005b9150505b919050565b6002546001600160a01b031681565b6003546000906001600160a01b0316331415806102e557506003546001600160a01b0316155b156102fc576102f5600180610542565b90506103b7565b60028054600380546001600160a01b038082166001600160a01b031980861682179687905590921690925560408051938316808552949092166020840152815190927fd604de94d45953f9138079ec1b82d533cb2160c906d1076d1f7ed54befbca97a92908290030190a1600354604080516001600160a01b038085168252909216602083015280517fe945ccee5d701fc83f9b8aa8ca94ea4219ec1fcbd4f4cab4f0ea57c5c3e1d8159281900390910190a160005b925050505b90565b6003546001600160a01b031681565b600080546001600160a01b031633146103e85761023e6001600f610542565b600380546001600160a01b038481166001600160a01b0319831617928390556040805192821680845293909116602083015280517fe945ccee5d701fc83f9b8aa8ca94ea4219ec1fcbd4f4cab4f0ea57c5c3e1d8159281900390910190a160006102a7565b6001546000906001600160a01b031633141580610468575033155b15610479576102f560016000610542565b60008054600180546001600160a01b038082166001600160a01b031980861682179687905590921690925560408051938316808552949092166020840152815190927ff9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc92908290030190a1600154604080516001600160a01b038085168252909216602083015280517fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a99281900390910190a160006103b2565b6000546001600160a01b031681565b60007f45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa083601381111561057157fe5b83601681111561057d57fe5b604080519283526020830191909152600082820152519081900360600190a18260138111156105a857fe5b939250505056fea265627a7a7231582032652b6a6ec48d80ae67bc555f3a9a1af782093d9b3fc91eb2e08ac56798924964736f6c63430005110032", + "abi": [ + { "inputs": [], "payable": false, "stateMutability": "nonpayable", "type": "constructor" }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "uint256", "name": "error", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "info", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "detail", "type": "uint256" } + ], + "name": "Failure", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "address", "name": "oldAdmin", "type": "address" }, + { "indexed": false, "internalType": "address", "name": "newAdmin", "type": "address" } + ], + "name": "NewAdmin", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "address", "name": "oldImplementation", "type": "address" }, + { "indexed": false, "internalType": "address", "name": "newImplementation", "type": "address" } + ], + "name": "NewImplementation", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "address", "name": "oldPendingAdmin", "type": "address" }, + { "indexed": false, "internalType": "address", "name": "newPendingAdmin", "type": "address" } + ], + "name": "NewPendingAdmin", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "address", "name": "oldPendingImplementation", "type": "address" }, + { "indexed": false, "internalType": "address", "name": "newPendingImplementation", "type": "address" } + ], + "name": "NewPendingImplementation", + "type": "event" + }, + { "payable": true, "stateMutability": "payable", "type": "fallback" }, + { + "constant": false, + "inputs": [], + "name": "_acceptAdmin", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [], + "name": "_acceptImplementation", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "internalType": "address", "name": "newPendingAdmin", "type": "address" }], + "name": "_setPendingAdmin", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "internalType": "address", "name": "newPendingImplementation", "type": "address" }], + "name": "_setPendingImplementation", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "admin", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "comptrollerImplementation", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "pendingAdmin", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "pendingComptrollerImplementation", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "payable": false, + "stateMutability": "view", + "type": "function" + } + ] +} diff --git a/assets/bsc/VBep20Delegate.json b/assets/bsc/VBep20Delegate.json new file mode 100644 index 00000000..2b3b85c5 --- /dev/null +++ b/assets/bsc/VBep20Delegate.json @@ -0,0 +1,700 @@ +{ + "bytecode": "608060405234801561001057600080fd5b5061542d806100206000396000f3fe608060405234801561001057600080fd5b50600436106102f15760003560e01c806370a082311161019d578063b71d1a0c116100e9578063e9c714f2116100a2578063f5e3c4621161007c578063f5e3c46214610b04578063f851a44014610b3a578063f8f9da2814610b42578063fca7820b14610b4a576102f1565b8063e9c714f214610ace578063f2b3abbd14610ad6578063f3fdb15a14610afc576102f1565b8063b71d1a0c146109ec578063bd6d894d14610a12578063c37f68e214610a1a578063c5ebeaec14610a66578063db006a7514610a83578063dd62ed3e14610aa0576102f1565b806399d8c1b411610156578063a9059cbb11610130578063a9059cbb1461097a578063aa5af0fd146109a6578063ae9d70b0146109ae578063b2a02ff1146109b6576102f1565b806399d8c1b414610807578063a0712d6814610955578063a6afed9514610972576102f1565b806370a082311461078657806373acee98146107ac578063852a12e3146107b45780638f840ddd146107d157806395d89b41146107d957806395dd9193146107e1576102f1565b8063313ce5671161025c57806347bd3718116102155780635fe3b567116101ef5780635fe3b56714610751578063601a0bf1146107595780636c540baf146107765780636f307dc31461077e576102f1565b806347bd37181461069d57806356e67728146106a55780635c60da1b14610749576102f1565b8063313ce567146106065780633af9e669146106245780633b1d21a21461064a5780633d9ea3a1146106525780633e9410101461065a5780634576b5db14610677576102f1565b806318160ddd116102ae57806318160ddd1461041a578063182df0f5146104225780631a31d4651461042a57806323b872dd146105805780632608f818146105b657806326782247146105e2576102f1565b806306fdde03146102f6578063095ea7b3146103735780630e752702146103b3578063153ab505146103e2578063173b9904146103ec57806317bfdfbc146103f4575b600080fd5b6102fe610b67565b6040805160208082528351818301528351919283929083019185019080838360005b83811015610338578181015183820152602001610320565b50505050905090810190601f1680156103655780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61039f6004803603604081101561038957600080fd5b506001600160a01b038135169060200135610bf4565b604080519115158252519081900360200190f35b6103d0600480360360208110156103c957600080fd5b5035610c61565b60408051918252519081900360200190f35b6103ea610c77565b005b6103d0610cc7565b6103d06004803603602081101561040a57600080fd5b50356001600160a01b0316610ccd565b6103d0610d8d565b6103d0610d93565b6103ea600480360360e081101561044057600080fd5b6001600160a01b03823581169260208101358216926040820135909216916060820135919081019060a081016080820135600160201b81111561048257600080fd5b82018360208201111561049457600080fd5b803590602001918460018302840111600160201b831117156104b557600080fd5b91908080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509295949360208101935035915050600160201b81111561050757600080fd5b82018360208201111561051957600080fd5b803590602001918460018302840111600160201b8311171561053a57600080fd5b91908080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509295505050903560ff169150610df69050565b61039f6004803603606081101561059657600080fd5b506001600160a01b03813581169160208101359091169060400135610e95565b6103d0600480360360408110156105cc57600080fd5b506001600160a01b038135169060200135610f07565b6105ea610f1d565b604080516001600160a01b039092168252519081900360200190f35b61060e610f2c565b6040805160ff9092168252519081900360200190f35b6103d06004803603602081101561063a57600080fd5b50356001600160a01b0316610f35565b6103d0610feb565b61039f610ffa565b6103d06004803603602081101561067057600080fd5b5035610fff565b6103d06004803603602081101561068d57600080fd5b50356001600160a01b031661100a565b6103d061115f565b6103ea600480360360208110156106bb57600080fd5b810190602081018135600160201b8111156106d557600080fd5b8201836020820111156106e757600080fd5b803590602001918460018302840111600160201b8311171561070857600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550611165945050505050565b6105ea6111b6565b6105ea6111c5565b6103d06004803603602081101561076f57600080fd5b50356111d4565b6103d061126f565b6105ea611275565b6103d06004803603602081101561079c57600080fd5b50356001600160a01b0316611284565b6103d061129f565b6103d0600480360360208110156107ca57600080fd5b5035611355565b6103d0611360565b6102fe611366565b6103d0600480360360208110156107f757600080fd5b50356001600160a01b03166113be565b6103ea600480360360c081101561081d57600080fd5b6001600160a01b03823581169260208101359091169160408201359190810190608081016060820135600160201b81111561085757600080fd5b82018360208201111561086957600080fd5b803590602001918460018302840111600160201b8311171561088a57600080fd5b91908080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509295949360208101935035915050600160201b8111156108dc57600080fd5b8201836020820111156108ee57600080fd5b803590602001918460018302840111600160201b8311171561090f57600080fd5b91908080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509295505050903560ff16915061141b9050565b6103d06004803603602081101561096b57600080fd5b5035611602565b6103d061160e565b61039f6004803603604081101561099057600080fd5b506001600160a01b038135169060200135611966565b6103d06119d7565b6103d06119dd565b6103d0600480360360608110156109cc57600080fd5b506001600160a01b03813581169160208101359091169060400135611a7c565b6103d060048036036020811015610a0257600080fd5b50356001600160a01b0316611aed565b6103d0611b79565b610a4060048036036020811015610a3057600080fd5b50356001600160a01b0316611c35565b604080519485526020850193909352838301919091526060830152519081900360800190f35b6103d060048036036020811015610a7c57600080fd5b5035611cca565b6103d060048036036020811015610a9957600080fd5b5035611cd5565b6103d060048036036040811015610ab657600080fd5b506001600160a01b0381358116916020013516611ce0565b6103d0611d0b565b6103d060048036036020811015610aec57600080fd5b50356001600160a01b0316611e0e565b6105ea611e48565b6103d060048036036060811015610b1a57600080fd5b506001600160a01b03813581169160208101359160409091013516611e57565b6105ea611e6f565b6103d0611e83565b6103d060048036036020811015610b6057600080fd5b5035611ee7565b60018054604080516020600284861615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015610bec5780601f10610bc157610100808354040283529160200191610bec565b820191906000526020600020905b815481529060010190602001808311610bcf57829003601f168201915b505050505081565b336000818152600f602090815260408083206001600160a01b03871680855290835281842086905581518681529151939493909284927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929081900390910190a360019150505b92915050565b600080610c6d83611f65565b509150505b919050565b60035461010090046001600160a01b03163314610cc55760405162461bcd60e51b815260040180806020018281038252602d8152602001806151ca602d913960400191505060405180910390fd5b565b60085481565b6000805460ff16610d12576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff19168155610d2461160e565b14610d6f576040805162461bcd60e51b81526020600482015260166024820152751858d8dc9d59481a5b9d195c995cdd0819985a5b195960521b604482015290519081900360640190fd5b610d78826113be565b90505b6000805460ff19166001179055919050565b600d5481565b6000806000610da061200e565b90925090506000826003811115610db357fe5b14610def5760405162461bcd60e51b81526004018080602001828103825260358152602001806153176035913960400191505060405180910390fd5b9150505b90565b610e0486868686868661141b565b601180546001600160a01b0319166001600160a01b038981169190911791829055604080516318160ddd60e01b8152905192909116916318160ddd91600480820192602092909190829003018186803b158015610e6057600080fd5b505afa158015610e74573d6000803e3d6000fd5b505050506040513d6020811015610e8a57600080fd5b505050505050505050565b6000805460ff16610eda576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff19168155610ef0338686866120bd565b1490506000805460ff191660011790559392505050565b600080610f1484846123cb565b50949350505050565b6004546001600160a01b031681565b60035460ff1681565b6000610f3f614fd8565b6040518060200160405280610f52611b79565b90526001600160a01b0384166000908152600e6020526040812054919250908190610f7e908490612476565b90925090506000826003811115610f9157fe5b14610fe3576040805162461bcd60e51b815260206004820152601f60248201527f62616c616e636520636f756c64206e6f742062652063616c63756c6174656400604482015290519081900360640190fd5b949350505050565b6000610ff56124ca565b905090565b600181565b6000610c5b8261254a565b60035460009061010090046001600160a01b03163314611037576110306001603f6125de565b9050610c72565b60055460408051623f1ee960e11b815290516001600160a01b0392831692851691627e3dd2916004808301926020929190829003018186803b15801561107c57600080fd5b505afa158015611090573d6000803e3d6000fd5b505050506040513d60208110156110a657600080fd5b50516110f9576040805162461bcd60e51b815260206004820152601c60248201527f6d61726b6572206d6574686f642072657475726e65642066616c736500000000604482015290519081900360640190fd5b600580546001600160a01b0319166001600160a01b03858116918217909255604080519284168352602083019190915280517f7ac369dbd14fa5ea3f473ed67cc9d598964a77501540ba6751eb0b3decf5870d9281900390910190a160005b9392505050565b600b5481565b60035461010090046001600160a01b031633146111b35760405162461bcd60e51b815260040180806020018281038252602d8152602001806153cc602d913960400191505060405180910390fd5b50565b6012546001600160a01b031681565b6005546001600160a01b031681565b6000805460ff16611219576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff1916815561122b61160e565b905080156112515761124981601181111561124257fe5b60306125de565b915050610d7b565b61125a83612644565b9150506000805460ff19166001179055919050565b60095481565b6011546001600160a01b031681565b6001600160a01b03166000908152600e602052604090205490565b6000805460ff166112e4576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff191681556112f661160e565b14611341576040805162461bcd60e51b81526020600482015260166024820152751858d8dc9d59481a5b9d195c995cdd0819985a5b195960521b604482015290519081900360640190fd5b50600b546000805460ff1916600117905590565b6000610c5b82612777565b600c5481565b6002805460408051602060018416156101000260001901909316849004601f81018490048402820184019092528181529291830182828015610bec5780601f10610bc157610100808354040283529160200191610bec565b60008060006113cc846127f8565b909250905060008260038111156113df57fe5b146111585760405162461bcd60e51b81526004018080602001828103825260378152602001806152226037913960400191505060405180910390fd5b60035461010090046001600160a01b031633146114695760405162461bcd60e51b81526004018080602001828103825260248152602001806151316024913960400191505060405180910390fd5b6009541580156114795750600a54155b6114b45760405162461bcd60e51b81526004018080602001828103825260238152602001806151556023913960400191505060405180910390fd5b6007849055836114f55760405162461bcd60e51b81526004018080602001828103825260308152602001806151786030913960400191505060405180910390fd5b60006115008761100a565b90508015611555576040805162461bcd60e51b815260206004820152601a60248201527f73657474696e6720636f6d7074726f6c6c6572206661696c6564000000000000604482015290519081900360640190fd5b61155d6128ac565b600955670de0b6b3a7640000600a55611575866128b0565b905080156115b45760405162461bcd60e51b81526004018080602001828103825260228152602001806151a86022913960400191505060405180910390fd5b83516115c7906001906020870190614feb565b5082516115db906002906020860190614feb565b50506003805460ff90921660ff199283161790556000805490911660011790555050505050565b600080610c6d83612a25565b6000806116196128ac565b6009549091508082141561163257600092505050610df3565b600061163c6124ca565b600b54600c54600a54600654604080516315f2405360e01b815260048101879052602481018690526044810185905290519596509394929391926000926001600160a01b03909216916315f24053916064808301926020929190829003018186803b1580156116aa57600080fd5b505afa1580156116be573d6000803e3d6000fd5b505050506040513d60208110156116d457600080fd5b5051905065048c27395000811115611733576040805162461bcd60e51b815260206004820152601c60248201527f626f72726f772072617465206973206162737572646c79206869676800000000604482015290519081900360640190fd5b6000806117408989612aa6565b9092509050600082600381111561175357fe5b146117a5576040805162461bcd60e51b815260206004820152601f60248201527f636f756c64206e6f742063616c63756c61746520626c6f636b2064656c746100604482015290519081900360640190fd5b6117ad614fd8565b6000806000806117cb60405180602001604052808a81525087612ac9565b909750945060008760038111156117de57fe5b14611810576117fb600960068960038111156117f657fe5b612b31565b9e505050505050505050505050505050610df3565b61181a858c612476565b9097509350600087600381111561182d57fe5b14611845576117fb600960018960038111156117f657fe5b61184f848c612b97565b9097509250600087600381111561186257fe5b1461187a576117fb600960048960038111156117f657fe5b6118956040518060200160405280600854815250858c612bbd565b909750915060008760038111156118a857fe5b146118c0576117fb600960058960038111156117f657fe5b6118cb858a8b612bbd565b909750905060008760038111156118de57fe5b146118f6576117fb600960038960038111156117f657fe5b60098e9055600a819055600b839055600c829055604080518d8152602081018690528082018390526060810185905290517f4dec04e750ca11537cabcd8a9eab06494de08da3735bc8871cd41250e190bc049181900360800190a160009e50505050505050505050505050505090565b6000805460ff166119ab576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff191681556119c1333386866120bd565b1490506000805460ff1916600117905592915050565b600a5481565b6006546000906001600160a01b031663b81688166119f96124ca565b600b54600c546008546040518563ffffffff1660e01b81526004018085815260200184815260200183815260200182815260200194505050505060206040518083038186803b158015611a4b57600080fd5b505afa158015611a5f573d6000803e3d6000fd5b505050506040513d6020811015611a7557600080fd5b5051905090565b6000805460ff16611ac1576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff19169055611ad733858585612c19565b90506000805460ff191660011790559392505050565b60035460009061010090046001600160a01b03163314611b1357611030600160456125de565b600480546001600160a01b038481166001600160a01b0319831681179093556040805191909216808252602082019390935281517fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9929181900390910190a16000611158565b6000805460ff16611bbe576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff19168155611bd061160e565b14611c1b576040805162461bcd60e51b81526020600482015260166024820152751858d8dc9d59481a5b9d195c995cdd0819985a5b195960521b604482015290519081900360640190fd5b611c23610d93565b90506000805460ff1916600117905590565b6001600160a01b0381166000908152600e6020526040812054819081908190818080611c60896127f8565b935090506000816003811115611c7257fe5b14611c905760095b975060009650869550859450611cc39350505050565b611c9861200e565b925090506000816003811115611caa57fe5b14611cb6576009611c7a565b5060009650919450925090505b9193509193565b6000610c5b82612e7f565b6000610c5b82612efe565b6001600160a01b039182166000908152600f6020908152604080832093909416825291909152205490565b6004546000906001600160a01b031633141580611d26575033155b15611d3e57611d37600160006125de565b9050610df3565b60038054600480546001600160a01b03818116610100818102610100600160a81b0319871617968790556001600160a01b031990931690935560408051948390048216808652929095041660208401528351909391927ff9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc92908290030190a1600454604080516001600160a01b038085168252909216602083015280517fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a99281900390910190a160009250505090565b600080611e1961160e565b90508015611e3f57611e37816011811115611e3057fe5b60406125de565b915050610c72565b611158836128b0565b6006546001600160a01b031681565b600080611e65858585612f78565b5095945050505050565b60035461010090046001600160a01b031681565b6006546000906001600160a01b03166315f24053611e9f6124ca565b600b54600c546040518463ffffffff1660e01b815260040180848152602001838152602001828152602001935050505060206040518083038186803b158015611a4b57600080fd5b6000805460ff16611f2c576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff19168155611f3e61160e565b90508015611f5c57611249816011811115611f5557fe5b60466125de565b61125a836130aa565b60008054819060ff16611fac576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff19168155611fbe61160e565b90508015611fe957611fdc816011811115611fd557fe5b60366125de565b925060009150611ffa9050565b611ff4333386613152565b92509250505b6000805460ff191660011790559092909150565b600d54600090819080612029575050600754600091506120b9565b60006120336124ca565b9050600061203f614fd8565b600061205084600b54600c54613537565b93509050600081600381111561206257fe5b14612077579550600094506120b99350505050565b6120818386613575565b92509050600081600381111561209357fe5b146120a8579550600094506120b99350505050565b50516000955093506120b992505050565b9091565b600554604080516317b9b84b60e31b81523060048201526001600160a01b03868116602483015285811660448301526064820185905291516000938493169163bdcdc25891608480830192602092919082900301818787803b15801561212257600080fd5b505af1158015612136573d6000803e3d6000fd5b505050506040513d602081101561214c57600080fd5b50519050801561216b576121636003604a83612b31565b915050610fe3565b836001600160a01b0316856001600160a01b03161415612191576121636002604b6125de565b60006001600160a01b0387811690871614156121b057506000196121d8565b506001600160a01b038086166000908152600f60209081526040808320938a16835292905220545b6000806000806121e88589612aa6565b909450925060008460038111156121fb57fe5b146122195761220c6009604b6125de565b9650505050505050610fe3565b6001600160a01b038a166000908152600e602052604090205461223c9089612aa6565b9094509150600084600381111561224f57fe5b146122605761220c6009604c6125de565b6001600160a01b0389166000908152600e60205260409020546122839089612b97565b9094509050600084600381111561229657fe5b146122a75761220c6009604d6125de565b6001600160a01b03808b166000908152600e6020526040808220859055918b1681522081905560001985146122ff576001600160a01b03808b166000908152600f60209081526040808320938f168352929052208390555b886001600160a01b03168a6001600160a01b03166000805160206152938339815191528a6040518082815260200191505060405180910390a36005546040805163352b4a3f60e11b81523060048201526001600160a01b038d811660248301528c81166044830152606482018c905291519190921691636a56947e91608480830192600092919082900301818387803b15801561239b57600080fd5b505af11580156123af573d6000803e3d6000fd5b50600092506123bc915050565b9b9a5050505050505050505050565b60008054819060ff16612412576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff1916815561242461160e565b9050801561244f5761244281601181111561243b57fe5b60356125de565b9250600091506124609050565b61245a338686613152565b92509250505b6000805460ff1916600117905590939092509050565b6000806000612483614fd8565b61248d8686612ac9565b909250905060008260038111156124a057fe5b146124b157509150600090506124c3565b60006124bc82613625565b9350935050505b9250929050565b601154604080516370a0823160e01b815230600482015290516000926001600160a01b03169182916370a0823191602480820192602092909190829003018186803b15801561251857600080fd5b505afa15801561252c573d6000803e3d6000fd5b505050506040513d602081101561254257600080fd5b505191505090565b6000805460ff1661258f576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff191681556125a161160e565b905080156125bf576112498160118111156125b857fe5b604e6125de565b6125c883613634565b509150506000805460ff19166001179055919050565b60007f45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa083601181111561260d57fe5b83605681111561261957fe5b604080519283526020830191909152600082820152519081900360600190a182601181111561115857fe5b600354600090819061010090046001600160a01b0316331461266c57611e37600160316125de565b6126746128ac565b6009541461268857611e37600a60336125de565b826126916124ca565b10156126a357611e37600e60326125de565b600c548311156126b957611e37600260346125de565b50600c54828103908111156126ff5760405162461bcd60e51b81526004018080602001828103825260248152602001806153a86024913960400191505060405180910390fd5b600c81905560035461271f9061010090046001600160a01b03168461371c565b600354604080516101009092046001600160a01b0316825260208201859052818101839052517f3bad0c59cf2f06e7314077049f48a93578cd16f5ef92329f1dab1420a99c177e916060908290030190a16000611158565b6000805460ff166127bc576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff191681556127ce61160e565b905080156127ec576112498160118111156127e557fe5b60276125de565b61125a33600085613813565b6001600160a01b03811660009081526010602052604081208054829182918291829161282f5750600094508493506128a792505050565b61283f8160000154600a54613fc3565b9094509250600084600381111561285257fe5b146128675750919350600092506128a7915050565b612875838260010154614002565b9094509150600084600381111561288857fe5b1461289d5750919350600092506128a7915050565b5060009450925050505b915091565b4390565b600354600090819061010090046001600160a01b031633146128d857611e37600160426125de565b6128e06128ac565b600954146128f457611e37600a60416125de565b600660009054906101000a90046001600160a01b03169050826001600160a01b0316632191f92a6040518163ffffffff1660e01b815260040160206040518083038186803b15801561294557600080fd5b505afa158015612959573d6000803e3d6000fd5b505050506040513d602081101561296f57600080fd5b50516129c2576040805162461bcd60e51b815260206004820152601c60248201527f6d61726b6572206d6574686f642072657475726e65642066616c736500000000604482015290519081900360640190fd5b600680546001600160a01b0319166001600160a01b03858116918217909255604080519284168352602083019190915280517fedffc32e068c7c95dfd4bdfd5c4d939a084d6b11c4199eac8436ed234d72f9269281900390910190a16000611158565b60008054819060ff16612a6c576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff19168155612a7e61160e565b90508015612a9c57611fdc816011811115612a9557fe5b601e6125de565b611ff4338561402d565b600080838311612abd5750600090508183036124c3565b506003905060006124c3565b6000612ad3614fd8565b600080612ae4866000015186613fc3565b90925090506000826003811115612af757fe5b14612b16575060408051602081019091526000815290925090506124c3565b60408051602081019091529081526000969095509350505050565b60007f45b96fe442630264581b197e84bbada861235052c5a1aadfff9ea4e40a969aa0846011811115612b6057fe5b846056811115612b6c57fe5b604080519283526020830191909152818101859052519081900360600190a1836011811115610fe357fe5b600080838301848110612baf576000925090506124c3565b5060029150600090506124c3565b6000806000612bca614fd8565b612bd48787612ac9565b90925090506000826003811115612be757fe5b14612bf85750915060009050612c11565b612c0a612c0482613625565b86612b97565b9350935050505b935093915050565b6005546040805163d02f735160e01b81523060048201526001600160a01b038781166024830152868116604483015285811660648301526084820185905291516000938493169163d02f73519160a480830192602092919082900301818787803b158015612c8657600080fd5b505af1158015612c9a573d6000803e3d6000fd5b505050506040513d6020811015612cb057600080fd5b505190508015612cc7576121636003601b83612b31565b846001600160a01b0316846001600160a01b03161415612ced576121636006601c6125de565b6001600160a01b0384166000908152600e602052604081205481908190612d149087612aa6565b90935091506000836003811115612d2757fe5b14612d4a57612d3f6009601a8560038111156117f657fe5b945050505050610fe3565b6001600160a01b0388166000908152600e6020526040902054612d6d9087612b97565b90935090506000836003811115612d8057fe5b14612d9857612d3f600960198560038111156117f657fe5b6001600160a01b038088166000818152600e60209081526040808320879055938c168083529184902085905583518a815293519193600080516020615293833981519152929081900390910190a360055460408051636d35bf9160e01b81523060048201526001600160a01b038c811660248301528b811660448301528a81166064830152608482018a905291519190921691636d35bf919160a480830192600092919082900301818387803b158015612e5157600080fd5b505af1158015612e65573d6000803e3d6000fd5b5060009250612e72915050565b9998505050505050505050565b6000805460ff16612ec4576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff19168155612ed661160e565b90508015612ef457611249816011811115612eed57fe5b60086125de565b61125a338461448c565b6000805460ff16612f43576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff19168155612f5561160e565b90508015612f6c576112498160118111156127e557fe5b61125a33846000613813565b60008054819060ff16612fbf576040805162461bcd60e51b815260206004820152600a6024820152691c994b595b9d195c995960b21b604482015290519081900360640190fd5b6000805460ff19168155612fd161160e565b90508015612ffc57612fef816011811115612fe857fe5b600f6125de565b9250600091506130939050565b836001600160a01b031663a6afed956040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561303757600080fd5b505af115801561304b573d6000803e3d6000fd5b505050506040513d602081101561306157600080fd5b50519050801561308157612fef81601181111561307a57fe5b60106125de565b61308d3387878761479a565b92509250505b6000805460ff191660011790559094909350915050565b60035460009061010090046001600160a01b031633146130d057611030600160476125de565b6130d86128ac565b600954146130ec57611030600a60486125de565b670de0b6b3a764000082111561310857611030600260496125de565b6008805490839055604080518281526020810185905281517faaa68312e2ea9d50e16af5068410ab56e1a1fd06037b1a35664812c30f821460929181900390910190a16000611158565b60055460408051631200453160e11b81523060048201526001600160a01b0386811660248301528581166044830152606482018590529151600093849384939116916324008a629160848082019260209290919082900301818787803b1580156131bb57600080fd5b505af11580156131cf573d6000803e3d6000fd5b505050506040513d60208110156131e557600080fd5b505190508015613209576131fc6003603883612b31565b925060009150612c119050565b6132116128ac565b60095414613225576131fc600a60396125de565b61322d615069565b6001600160a01b0386166000908152601060205260409020600101546060820152613257866127f8565b608083018190526020830182600381111561326e57fe5b600381111561327957fe5b905250600090508160200151600381111561329057fe5b146132ba576132ac60096037836020015160038111156117f657fe5b935060009250612c11915050565b6000198514156132d357608081015160408201526132db565b604081018590525b6132e9878260400151614d1d565b60e0820181905260808201516132fe91612aa6565b60a083018190526020830182600381111561331557fe5b600381111561332057fe5b905250600090508160200151600381111561333757fe5b146133735760405162461bcd60e51b815260040180806020018281038252603a815260200180615259603a913960400191505060405180910390fd5b613383600b548260e00151612aa6565b60c083018190526020830182600381111561339a57fe5b60038111156133a557fe5b90525060009050816020015160038111156133bc57fe5b146133f85760405162461bcd60e51b81526004018080602001828103825260318152602001806152b36031913960400191505060405180910390fd5b60a080820180516001600160a01b03808a16600081815260106020908152604091829020948555600a5460019095019490945560c0870151600b81905560e088015195518251948f16855294840192909252828101949094526060820192909252608081019190915290517f1a2a22cb034d26d1854bdc6666a5b91fe25efbbb5dcad3b0355478d6f5c362a1929181900390910190a160055460e0820151606083015160408051631ededc9160e01b81523060048201526001600160a01b038c811660248301528b8116604483015260648201949094526084810192909252519190921691631ededc919160a480830192600092919082900301818387803b15801561350357600080fd5b505af1158015613517573d6000803e3d6000fd5b5060009250613524915050565b8160e00151935093505050935093915050565b6000806000806135478787612b97565b9092509050600082600381111561355a57fe5b1461356b5750915060009050612c11565b612c0a8186612aa6565b600061357f614fd8565b60008061359486670de0b6b3a7640000613fc3565b909250905060008260038111156135a757fe5b146135c6575060408051602081019091526000815290925090506124c3565b6000806135d38388614002565b909250905060008260038111156135e657fe5b14613608575060408051602081019091526000815290945092506124c3915050565b604080516020810190915290815260009890975095505050505050565b51670de0b6b3a7640000900490565b6000806000806136426128ac565b6009541461366157613656600a604f6125de565b935091506128a79050565b61366b3386614d1d565b905080600c54019150600c548210156136cb576040805162461bcd60e51b815260206004820181905260248201527f61646420726573657276657320756e6578706563746564206f766572666c6f77604482015290519081900360640190fd5b600c829055604080513381526020810183905280820184905290517fa91e67c5ea634cd43a12c5a482724b03de01e85ca68702a53d0c2f45cb7c1dc59181900360600190a160009350915050915091565b6011546040805163a9059cbb60e01b81526001600160a01b0385811660048301526024820185905291519190921691829163a9059cbb9160448082019260009290919082900301818387803b15801561377457600080fd5b505af1158015613788573d6000803e3d6000fd5b5050505060003d600081146137a457602081146137ae57600080fd5b60001991506137ba565b60206000803e60005191505b508061380d576040805162461bcd60e51b815260206004820152601960248201527f544f4b454e5f5452414e534645525f4f55545f4641494c454400000000000000604482015290519081900360640190fd5b50505050565b6000821580613820575081155b61385b5760405162461bcd60e51b81526004018080602001828103825260348152602001806153746034913960400191505060405180910390fd5b6138636150af565b61386b61200e565b604083018190526020830182600381111561388257fe5b600381111561388d57fe5b90525060009050816020015160038111156138a457fe5b146138c8576138c06009602b836020015160038111156117f657fe5b915050611158565b83156139495760608101849052604080516020810182529082015181526138ef9085612476565b608083018190526020830182600381111561390657fe5b600381111561391157fe5b905250600090508160200151600381111561392857fe5b14613944576138c060096029836020015160038111156117f657fe5b6139c2565b6139658360405180602001604052808460400151815250614f67565b606083018190526020830182600381111561397c57fe5b600381111561398757fe5b905250600090508160200151600381111561399e57fe5b146139ba576138c06009602a836020015160038111156117f657fe5b608081018390525b60055460608201516040805163eabe7d9160e01b81523060048201526001600160a01b03898116602483015260448201939093529051600093929092169163eabe7d919160648082019260209290919082900301818787803b158015613a2757600080fd5b505af1158015613a3b573d6000803e3d6000fd5b505050506040513d6020811015613a5157600080fd5b505190508015613a7157613a686003602883612b31565b92505050611158565b613a796128ac565b60095414613a8d57613a68600a602c6125de565b613a9d600d548360600151612aa6565b60a0840181905260208401826003811115613ab457fe5b6003811115613abf57fe5b9052506000905082602001516003811115613ad657fe5b14613af257613a686009602e846020015160038111156117f657fe5b6001600160a01b0386166000908152600e60205260409020546060830151613b1a9190612aa6565b60c0840181905260208401826003811115613b3157fe5b6003811115613b3c57fe5b9052506000905082602001516003811115613b5357fe5b14613b6f57613a686009602d846020015160038111156117f657fe5b8160800151613b7c6124ca565b1015613b8e57613a68600e602f6125de565b600080600560009054906101000a90046001600160a01b03166001600160a01b03166304ef9d586040518163ffffffff1660e01b815260040160206040518083038186803b158015613bdf57600080fd5b505afa158015613bf3573d6000803e3d6000fd5b505050506040513d6020811015613c0957600080fd5b505115613e7757608084015160055460408051629df3ab60e31b81529051613c8c93926001600160a01b0316916304ef9d58916004808301926020929190829003018186803b158015613c5b57600080fd5b505afa158015613c6f573d6000803e3d6000fd5b505050506040513d6020811015613c8557600080fd5b5051613fc3565b85602001819450826003811115613c9f57fe5b6003811115613caa57fe5b9052506000905084602001516003811115613cc157fe5b14613ce857613cdd60096056866020015160038111156117f657fe5b945050505050611158565b613cfa82670de0b6b3a7640000614002565b85602001819450826003811115613d0d57fe5b6003811115613d1857fe5b9052506000905084602001516003811115613d2f57fe5b14613d4b57613cdd60096056866020015160038111156117f657fe5b613d59846080015183612aa6565b85602001819350826003811115613d6c57fe5b6003811115613d7757fe5b9052506000905084602001516003811115613d8e57fe5b14613daa57613cdd60096056866020015160038111156117f657fe5b6005546040805163c5f956af60e01b81529051613e22926001600160a01b03169163c5f956af916004808301926020929190829003018186803b158015613df057600080fd5b505afa158015613e04573d6000803e3d6000fd5b505050506040513d6020811015613e1a57600080fd5b50518361371c565b606080850151604080516001600160a01b038c1681526020810186905280820192909252517fccf8e53b86a99b7e9ecf796342c165764d66154780f638c08e6241d711fba6d4929181900390910190a1613e7e565b5060808301515b613e88888261371c565b60a0840151600d5560c08401516001600160a01b0389166000818152600e6020908152604091829020939093556060870151815190815290513093600080516020615293833981519152928290030190a3606080850151604080516001600160a01b038c1681526020810185905280820192909252517fe5b754fb1abb7f01b499791d0b820ae3b6af3424ac1c59768edb53f4ec31a929929181900390910190a160055460808501516060860151604080516351dff98960e01b81523060048201526001600160a01b038d81166024830152604482019490945260648101929092525191909216916351dff98991608480830192600092919082900301818387803b158015613f9657600080fd5b505af1158015613faa573d6000803e3d6000fd5b5060009250613fb7915050565b98975050505050505050565b60008083613fd6575060009050806124c3565b83830283858281613fe357fe5b0414613ff7575060029150600090506124c3565b6000925090506124c3565b6000808261401657506001905060006124c3565b600083858161402157fe5b04915091509250929050565b60055460408051634ef4c3e160e01b81523060048201526001600160a01b03858116602483015260448201859052915160009384938493911691634ef4c3e19160648082019260209290919082900301818787803b15801561408e57600080fd5b505af11580156140a2573d6000803e3d6000fd5b505050506040513d60208110156140b857600080fd5b5051905080156140dc576140cf6003601f83612b31565b9250600091506124c39050565b6140e46128ac565b600954146140f8576140cf600a60226125de565b6141006150af565b61410861200e565b604083018190526020830182600381111561411f57fe5b600381111561412a57fe5b905250600090508160200151600381111561414157fe5b1461416b5761415d60096021836020015160038111156117f657fe5b9350600092506124c3915050565b6141758686614d1d565b60c08201819052604080516020810182529083015181526141969190614f67565b60608301819052602083018260038111156141ad57fe5b60038111156141b857fe5b90525060009050816020015160038111156141cf57fe5b14614221576040805162461bcd60e51b815260206004820181905260248201527f4d494e545f45584348414e47455f43414c43554c4154494f4e5f4641494c4544604482015290519081900360640190fd5b614231600d548260600151612b97565b608083018190526020830182600381111561424857fe5b600381111561425357fe5b905250600090508160200151600381111561426a57fe5b146142a65760405162461bcd60e51b815260040180806020018281038252602881526020018061534c6028913960400191505060405180910390fd5b6001600160a01b0386166000908152600e602052604090205460608201516142ce9190612b97565b60a08301819052602083018260038111156142e557fe5b60038111156142f057fe5b905250600090508160200151600381111561430757fe5b146143435760405162461bcd60e51b815260040180806020018281038252602b8152602001806151f7602b913960400191505060405180910390fd5b6080810151600d5560a08101516001600160a01b0387166000818152600e60209081526040918290209390935560c084015160608086015183519485529484019190915282820193909352517f4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f929181900390910190a1606081015160408051918252516001600160a01b0388169130916000805160206152938339815191529181900360200190a360055460c08201516060830151604080516341c728b960e01b81523060048201526001600160a01b038b81166024830152604482019490945260648101929092525191909216916341c728b991608480830192600092919082900301818387803b15801561445957600080fd5b505af115801561446d573d6000803e3d6000fd5b506000925061447a915050565b8160c001519350935050509250929050565b6005546040805163368f515360e21b81523060048201526001600160a01b0385811660248301526044820185905291516000938493169163da3d454c91606480830192602092919082900301818787803b1580156144e957600080fd5b505af11580156144fd573d6000803e3d6000fd5b505050506040513d602081101561451357600080fd5b5051905080156145325761452a6003600e83612b31565b915050610c5b565b61453a6128ac565b6009541461454d5761452a600a806125de565b826145566124ca565b10156145685761452a600e60096125de565b6145706150ed565b614579856127f8565b602083018190528282600381111561458d57fe5b600381111561459857fe5b90525060009050815160038111156145ac57fe5b146145d1576145c860096007836000015160038111156117f657fe5b92505050610c5b565b6145df816020015185612b97565b60408301819052828260038111156145f357fe5b60038111156145fe57fe5b905250600090508151600381111561461257fe5b1461462e576145c86009600c836000015160038111156117f657fe5b61463a600b5485612b97565b606083018190528282600381111561464e57fe5b600381111561465957fe5b905250600090508151600381111561466d57fe5b14614689576145c86009600b836000015160038111156117f657fe5b614693858561371c565b604080820180516001600160a01b03881660008181526010602090815290859020928355600a54600190930192909255606080860151600b81905593518551928352928201899052818501929092529081019190915290517f13ed6866d4e1ee6da46f845c46d7e54120883d75c5ea9a2dacc1c4ca8984ab809181900360800190a160055460408051635c77860560e01b81523060048201526001600160a01b0388811660248301526044820188905291519190921691635c77860591606480830192600092919082900301818387803b15801561477057600080fd5b505af1158015614784573d6000803e3d6000fd5b5060009250614791915050565b95945050505050565b60055460408051632fe3f38f60e11b81523060048201526001600160a01b0384811660248301528781166044830152868116606483015260848201869052915160009384938493911691635fc7e71e9160a48082019260209290919082900301818787803b15801561480b57600080fd5b505af115801561481f573d6000803e3d6000fd5b505050506040513d602081101561483557600080fd5b5051905080156148595761484c6003601283612b31565b925060009150614d149050565b6148616128ac565b600954146148755761484c600a60166125de565b61487d6128ac565b846001600160a01b0316636c540baf6040518163ffffffff1660e01b815260040160206040518083038186803b1580156148b657600080fd5b505afa1580156148ca573d6000803e3d6000fd5b505050506040513d60208110156148e057600080fd5b5051146148f35761484c600a60116125de565b866001600160a01b0316866001600160a01b031614156149195761484c600660176125de565b8461492a5761484c600760156125de565b6000198514156149405761484c600760146125de565b60008061494e898989613152565b9092509050811561497e5761496f82601181111561496857fe5b60186125de565b945060009350614d1492505050565b6005546040805163c488847b60e01b81523060048201526001600160a01b038981166024830152604482018590528251600094859492169263c488847b926064808301939192829003018186803b1580156149d857600080fd5b505afa1580156149ec573d6000803e3d6000fd5b505050506040513d6040811015614a0257600080fd5b50805160209091015190925090508115614a4d5760405162461bcd60e51b81526004018080602001828103825260338152602001806152e46033913960400191505060405180910390fd5b80886001600160a01b03166370a082318c6040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b158015614aa457600080fd5b505afa158015614ab8573d6000803e3d6000fd5b505050506040513d6020811015614ace57600080fd5b50511015614b23576040805162461bcd60e51b815260206004820152601860248201527f4c49515549444154455f5345495a455f544f4f5f4d5543480000000000000000604482015290519081900360640190fd5b60006001600160a01b038916301415614b4957614b42308d8d85612c19565b9050614bd3565b6040805163b2a02ff160e01b81526001600160a01b038e811660048301528d81166024830152604482018590529151918b169163b2a02ff1916064808201926020929091908290030181600087803b158015614ba457600080fd5b505af1158015614bb8573d6000803e3d6000fd5b505050506040513d6020811015614bce57600080fd5b505190505b8015614c1d576040805162461bcd60e51b81526020600482015260146024820152731d1bdad95b881cd95a5e9d5c994819985a5b195960621b604482015290519081900360640190fd5b604080516001600160a01b03808f168252808e1660208301528183018790528b1660608201526080810184905290517f298637f684da70674f26509b10f07ec2fbc77a335ab1e7d6215a4b2484d8bb529181900360a00190a1600554604080516347ef3b3b60e01b81523060048201526001600160a01b038c811660248301528f811660448301528e811660648301526084820188905260a48201869052915191909216916347ef3b3b9160c480830192600092919082900301818387803b158015614ce857600080fd5b505af1158015614cfc573d6000803e3d6000fd5b5060009250614d09915050565b975092955050505050505b94509492505050565b601154604080516370a0823160e01b815230600482015290516000926001600160a01b031691839183916370a08231916024808301926020929190829003018186803b158015614d6c57600080fd5b505afa158015614d80573d6000803e3d6000fd5b505050506040513d6020811015614d9657600080fd5b5051604080516323b872dd60e01b81526001600160a01b038881166004830152306024830152604482018890529151929350908416916323b872dd9160648082019260009290919082900301818387803b158015614df357600080fd5b505af1158015614e07573d6000803e3d6000fd5b5050505060003d60008114614e235760208114614e2d57600080fd5b6000199150614e39565b60206000803e60005191505b5080614e8c576040805162461bcd60e51b815260206004820152601860248201527f544f4b454e5f5452414e534645525f494e5f4641494c45440000000000000000604482015290519081900360640190fd5b601154604080516370a0823160e01b815230600482015290516000926001600160a01b0316916370a08231916024808301926020929190829003018186803b158015614ed757600080fd5b505afa158015614eeb573d6000803e3d6000fd5b505050506040513d6020811015614f0157600080fd5b5051905082811015614f5a576040805162461bcd60e51b815260206004820152601a60248201527f544f4b454e5f5452414e534645525f494e5f4f564552464c4f57000000000000604482015290519081900360640190fd5b9190910395945050505050565b6000806000614f74614fd8565b61248d86866000614f83614fd8565b600080614f98670de0b6b3a764000087613fc3565b90925090506000826003811115614fab57fe5b14614fca575060408051602081019091526000815290925090506124c3565b6124bc818660000151613575565b6040518060200160405280600081525090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061502c57805160ff1916838001178555615059565b82800160010185558215615059579182015b8281111561505957825182559160200191906001019061503e565b50615065929150615116565b5090565b6040805161010081019091528060008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6040805160e0810190915280600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b604080516080810190915280600081526020016000815260200160008152602001600081525090565b610df391905b80821115615065576000815560010161511c56fe6f6e6c792061646d696e206d617920696e697469616c697a6520746865206d61726b65746d61726b6574206d6179206f6e6c7920626520696e697469616c697a6564206f6e6365696e697469616c2065786368616e67652072617465206d7573742062652067726561746572207468616e207a65726f2e73657474696e6720696e7465726573742072617465206d6f64656c206661696c65646f6e6c79207468652061646d696e206d61792063616c6c205f72657369676e496d706c656d656e746174696f6e4d494e545f4e45575f4143434f554e545f42414c414e43455f43414c43554c4154494f4e5f4641494c4544626f72726f7742616c616e636553746f7265643a20626f72726f7742616c616e636553746f726564496e7465726e616c206661696c656452455041595f424f52524f575f4e45575f4143434f554e545f424f52524f575f42414c414e43455f43414c43554c4154494f4e5f4641494c4544ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef52455041595f424f52524f575f4e45575f544f54414c5f42414c414e43455f43414c43554c4154494f4e5f4641494c45444c49515549444154455f434f4d5054524f4c4c45525f43414c43554c4154455f414d4f554e545f5345495a455f4641494c454465786368616e67655261746553746f7265643a2065786368616e67655261746553746f726564496e7465726e616c206661696c65644d494e545f4e45575f544f54414c5f535550504c595f43414c43554c4154494f4e5f4641494c45446f6e65206f662072656465656d546f6b656e73496e206f722072656465656d416d6f756e74496e206d757374206265207a65726f72656475636520726573657276657320756e657870656374656420756e646572666c6f776f6e6c79207468652061646d696e206d61792063616c6c205f6265636f6d65496d706c656d656e746174696f6ea265627a7a723158200208404f0b95e399b4d974b19a2bccd13ca417c5515cdd6db8c7d89df404626564736f6c63430005110032", + "abi": [ + { "inputs": [], "payable": false, "stateMutability": "nonpayable", "type": "constructor" }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "uint256", "name": "cashPrior", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "interestAccumulated", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "borrowIndex", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "totalBorrows", "type": "uint256" } + ], + "name": "AccrueInterest", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "owner", "type": "address" }, + { "indexed": true, "internalType": "address", "name": "spender", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "address", "name": "borrower", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "borrowAmount", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "accountBorrows", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "totalBorrows", "type": "uint256" } + ], + "name": "Borrow", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "uint256", "name": "error", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "info", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "detail", "type": "uint256" } + ], + "name": "Failure", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "address", "name": "liquidator", "type": "address" }, + { "indexed": false, "internalType": "address", "name": "borrower", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "repayAmount", "type": "uint256" }, + { "indexed": false, "internalType": "address", "name": "vTokenCollateral", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "seizeTokens", "type": "uint256" } + ], + "name": "LiquidateBorrow", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "address", "name": "minter", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "mintAmount", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "mintTokens", "type": "uint256" } + ], + "name": "Mint", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "address", "name": "oldAdmin", "type": "address" }, + { "indexed": false, "internalType": "address", "name": "newAdmin", "type": "address" } + ], + "name": "NewAdmin", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "contract ComptrollerInterface", + "name": "oldComptroller", + "type": "address" + }, + { + "indexed": false, + "internalType": "contract ComptrollerInterface", + "name": "newComptroller", + "type": "address" + } + ], + "name": "NewComptroller", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "contract InterestRateModel", + "name": "oldInterestRateModel", + "type": "address" + }, + { + "indexed": false, + "internalType": "contract InterestRateModel", + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "NewMarketInterestRateModel", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "address", "name": "oldPendingAdmin", "type": "address" }, + { "indexed": false, "internalType": "address", "name": "newPendingAdmin", "type": "address" } + ], + "name": "NewPendingAdmin", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "uint256", "name": "oldReserveFactorMantissa", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "newReserveFactorMantissa", "type": "uint256" } + ], + "name": "NewReserveFactor", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "address", "name": "redeemer", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "redeemAmount", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "redeemTokens", "type": "uint256" } + ], + "name": "Redeem", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "address", "name": "redeemer", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "feeAmount", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "redeemTokens", "type": "uint256" } + ], + "name": "RedeemFee", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "address", "name": "payer", "type": "address" }, + { "indexed": false, "internalType": "address", "name": "borrower", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "repayAmount", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "accountBorrows", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "totalBorrows", "type": "uint256" } + ], + "name": "RepayBorrow", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "address", "name": "benefactor", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "addAmount", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "newTotalReserves", "type": "uint256" } + ], + "name": "ReservesAdded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "address", "name": "admin", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "reduceAmount", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "newTotalReserves", "type": "uint256" } + ], + "name": "ReservesReduced", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "from", "type": "address" }, + { "indexed": true, "internalType": "address", "name": "to", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "Transfer", + "type": "event" + }, + { + "constant": false, + "inputs": [], + "name": "_acceptAdmin", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "internalType": "uint256", "name": "addAmount", "type": "uint256" }], + "name": "_addReserves", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "internalType": "bytes", "name": "data", "type": "bytes" }], + "name": "_becomeImplementation", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "internalType": "uint256", "name": "reduceAmount", "type": "uint256" }], + "name": "_reduceReserves", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [], + "name": "_resignImplementation", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "internalType": "contract ComptrollerInterface", "name": "newComptroller", "type": "address" }], + "name": "_setComptroller", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "internalType": "contract InterestRateModel", "name": "newInterestRateModel", "type": "address" }], + "name": "_setInterestRateModel", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "internalType": "address payable", "name": "newPendingAdmin", "type": "address" }], + "name": "_setPendingAdmin", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "internalType": "uint256", "name": "newReserveFactorMantissa", "type": "uint256" }], + "name": "_setReserveFactor", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "accrualBlockNumber", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [], + "name": "accrueInterest", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "admin", + "outputs": [{ "internalType": "address payable", "name": "", "type": "address" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { "internalType": "address", "name": "owner", "type": "address" }, + { "internalType": "address", "name": "spender", "type": "address" } + ], + "name": "allowance", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { "internalType": "address", "name": "spender", "type": "address" }, + { "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "approve", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [{ "internalType": "address", "name": "owner", "type": "address" }], + "name": "balanceOf", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "internalType": "address", "name": "owner", "type": "address" }], + "name": "balanceOfUnderlying", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "internalType": "uint256", "name": "borrowAmount", "type": "uint256" }], + "name": "borrow", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "internalType": "address", "name": "account", "type": "address" }], + "name": "borrowBalanceCurrent", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [{ "internalType": "address", "name": "account", "type": "address" }], + "name": "borrowBalanceStored", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "borrowIndex", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "borrowRatePerBlock", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "comptroller", + "outputs": [{ "internalType": "contract ComptrollerInterface", "name": "", "type": "address" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [{ "internalType": "uint8", "name": "", "type": "uint8" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [], + "name": "exchangeRateCurrent", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "exchangeRateStored", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [{ "internalType": "address", "name": "account", "type": "address" }], + "name": "getAccountSnapshot", + "outputs": [ + { "internalType": "uint256", "name": "", "type": "uint256" }, + { "internalType": "uint256", "name": "", "type": "uint256" }, + { "internalType": "uint256", "name": "", "type": "uint256" }, + { "internalType": "uint256", "name": "", "type": "uint256" } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "getCash", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "implementation", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { "internalType": "address", "name": "underlying_", "type": "address" }, + { "internalType": "contract ComptrollerInterface", "name": "comptroller_", "type": "address" }, + { "internalType": "contract InterestRateModel", "name": "interestRateModel_", "type": "address" }, + { "internalType": "uint256", "name": "initialExchangeRateMantissa_", "type": "uint256" }, + { "internalType": "string", "name": "name_", "type": "string" }, + { "internalType": "string", "name": "symbol_", "type": "string" }, + { "internalType": "uint8", "name": "decimals_", "type": "uint8" } + ], + "name": "initialize", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { "internalType": "contract ComptrollerInterface", "name": "comptroller_", "type": "address" }, + { "internalType": "contract InterestRateModel", "name": "interestRateModel_", "type": "address" }, + { "internalType": "uint256", "name": "initialExchangeRateMantissa_", "type": "uint256" }, + { "internalType": "string", "name": "name_", "type": "string" }, + { "internalType": "string", "name": "symbol_", "type": "string" }, + { "internalType": "uint8", "name": "decimals_", "type": "uint8" } + ], + "name": "initialize", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "interestRateModel", + "outputs": [{ "internalType": "contract InterestRateModel", "name": "", "type": "address" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "isVToken", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { "internalType": "address", "name": "borrower", "type": "address" }, + { "internalType": "uint256", "name": "repayAmount", "type": "uint256" }, + { "internalType": "contract VTokenInterface", "name": "vTokenCollateral", "type": "address" } + ], + "name": "liquidateBorrow", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "internalType": "uint256", "name": "mintAmount", "type": "uint256" }], + "name": "mint", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [{ "internalType": "string", "name": "", "type": "string" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "pendingAdmin", + "outputs": [{ "internalType": "address payable", "name": "", "type": "address" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "internalType": "uint256", "name": "redeemTokens", "type": "uint256" }], + "name": "redeem", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "internalType": "uint256", "name": "redeemAmount", "type": "uint256" }], + "name": "redeemUnderlying", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "internalType": "uint256", "name": "repayAmount", "type": "uint256" }], + "name": "repayBorrow", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { "internalType": "address", "name": "borrower", "type": "address" }, + { "internalType": "uint256", "name": "repayAmount", "type": "uint256" } + ], + "name": "repayBorrowBehalf", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "reserveFactorMantissa", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { "internalType": "address", "name": "liquidator", "type": "address" }, + { "internalType": "address", "name": "borrower", "type": "address" }, + { "internalType": "uint256", "name": "seizeTokens", "type": "uint256" } + ], + "name": "seize", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "supplyRatePerBlock", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [{ "internalType": "string", "name": "", "type": "string" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalBorrows", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [], + "name": "totalBorrowsCurrent", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalReserves", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { "internalType": "address", "name": "dst", "type": "address" }, + { "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "transfer", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { "internalType": "address", "name": "src", "type": "address" }, + { "internalType": "address", "name": "dst", "type": "address" }, + { "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "transferFrom", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "underlying", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "payable": false, + "stateMutability": "view", + "type": "function" + } + ] +} diff --git a/assets/bsc/VBep20Delegator.json b/assets/bsc/VBep20Delegator.json new file mode 100644 index 00000000..51c767ef --- /dev/null +++ b/assets/bsc/VBep20Delegator.json @@ -0,0 +1,696 @@ +{ + "bytecode": "60806040523480156200001157600080fd5b50604051620019eb380380620019eb83398181016040526101408110156200003857600080fd5b81516020830151604080850151606086015160808701805193519597949692959194919392820192846401000000008211156200007457600080fd5b9083019060208201858111156200008a57600080fd5b8251640100000000811182820188101715620000a557600080fd5b82525081516020918201929091019080838360005b83811015620000d4578181015183820152602001620000ba565b50505050905090810190601f168015620001025780820380516001836020036101000a031916815260200191505b50604052602001805160405193929190846401000000008211156200012657600080fd5b9083019060208201858111156200013c57600080fd5b82516401000000008111828201881017156200015757600080fd5b82525081516020918201929091019080838360005b83811015620001865781810151838201526020016200016c565b50505050905090810190601f168015620001b45780820380516001836020036101000a031916815260200191505b50604081815260208301519083015160608401516080909401805192969195919284640100000000821115620001e957600080fd5b908301906020820185811115620001ff57600080fd5b82516401000000008111828201881017156200021a57600080fd5b82525081516020918201929091019080838360005b83811015620002495781810151838201526020016200022f565b50505050905090810190601f168015620002775780820380516001836020036101000a031916815260200191505b5060405250505033600360016101000a8154816001600160a01b0302191690836001600160a01b0316021790555062000424828b8b8b8b8b8b8b60405160240180886001600160a01b03166001600160a01b03168152602001876001600160a01b03166001600160a01b03168152602001866001600160a01b03166001600160a01b0316815260200185815260200180602001806020018460ff1660ff168152602001838103835286818151815260200191508051906020019080838360005b838110156200035157818101518382015260200162000337565b50505050905090810190601f1680156200037f5780820380516001836020036101000a031916815260200191505b50838103825285518152855160209182019187019080838360005b83811015620003b45781810151838201526020016200039a565b50505050905090810190601f168015620003e25780820380516001836020036101000a031916815260200191505b5060408051601f198184030181529190526020810180516001600160e01b03908116631a31d46560e01b17909152909a50620004721698505050505050505050565b506200043c826000836001600160e01b036200053916565b5050600380546001600160a01b0390921661010002610100600160a81b0319909216919091179055506200071a95505050505050565b606060006060846001600160a01b0316846040518082805190602001908083835b60208310620004b45780518252601f19909201916020918201910162000493565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855af49150503d806000811462000516576040519150601f19603f3d011682016040523d82523d6000602084013e6200051b565b606091505b5091509150600082141562000531573d60208201fd5b949350505050565b60035461010090046001600160a01b03163314620005895760405162461bcd60e51b8152600401808060200182810382526039815260200180620019b26039913960400191505060405180910390fd5b8115620005cb576040805160048152602481019091526020810180516001600160e01b0390811663153ab50560e01b17909152620005c99190620006f016565b505b601280546001600160a01b038581166001600160a01b03198316179092556040516020602482018181528551604484015285519490931693620006a1938693909283926064909201919085019080838360005b83811015620006385781810151838201526020016200061e565b50505050905090810190601f168015620006665780820380516001836020036101000a031916815260200191505b5060408051601f198184030181529190526020810180516001600160e01b03908116630adccee560e31b17909152909350620006f016915050565b50601254604080516001600160a01b038085168252909216602083015280517fd604de94d45953f9138079ec1b82d533cb2160c906d1076d1f7ed54befbca97a9281900390910190a150505050565b60125460609062000714906001600160a01b0316836001600160e01b036200047216565b92915050565b611288806200072a6000396000f3fe6080604052600436106102c95760003560e01c806370a0823111610175578063b71d1a0c116100dc578063e9c714f211610095578063f5e3c4621161006f578063f5e3c46214610955578063f851a44014610998578063f8f9da2814610532578063fca7820b14610499576102c9565b8063e9c714f214610835578063f2b3abbd146104ea578063f3fdb15a14610940576102c9565b8063b71d1a0c146104ea578063bd6d894d14610835578063c37f68e2146108ac578063c5ebeaec14610499578063db006a7514610499578063dd62ed3e14610905576102c9565b8063a0712d681161012e578063a0712d6814610499578063a6afed9514610835578063a9059cbb1461044c578063aa5af0fd14610874578063ae9d70b014610532578063b2a02ff114610889576102c9565b806370a082311461080257806373acee9814610835578063852a12e3146104995780638f840ddd1461084a57806395d89b411461085f57806395dd919314610802576102c9565b80633af9e6691161023457806347bd3718116101ed5780635fe3b567116101c75780635fe3b567146107c3578063601a0bf1146104995780636c540baf146107d85780636f307dc3146107ed576102c9565b806347bd3718146106cf578063555bcc40146106e45780635c60da1b146107ae576102c9565b80633af9e669146104ea5780633b1d21a2146105325780633d9ea3a1146106095780633e941010146104995780634487152f1461061e5780634576b5db146104ea576102c9565b806318160ddd1161028657806318160ddd1461051d578063182df0f51461053257806323b872dd146105475780632608f8181461058a57806326782247146105ad578063313ce567146105de576102c9565b806306fdde03146103115780630933c1ed1461039b578063095ea7b31461044c5780630e75270214610499578063173b9904146104d557806317bfdfbc146104ea575b34156103065760405162461bcd60e51b815260040180806020018281038252603781526020018061121d6037913960400191505060405180910390fd5b61030e6109ad565b50005b34801561031d57600080fd5b50610326610a35565b6040805160208082528351818301528351919283929083019185019080838360005b83811015610360578181015183820152602001610348565b50505050905090810190601f16801561038d5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3480156103a757600080fd5b50610326600480360360208110156103be57600080fd5b810190602081018135600160201b8111156103d857600080fd5b8201836020820111156103ea57600080fd5b803590602001918460018302840111600160201b8311171561040b57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550610ac2945050505050565b34801561045857600080fd5b506104856004803603604081101561046f57600080fd5b506001600160a01b038135169060200135610ae1565b604080519115158252519081900360200190f35b3480156104a557600080fd5b506104c3600480360360208110156104bc57600080fd5b5035610af2565b60408051918252519081900360200190f35b3480156104e157600080fd5b506104c3610b02565b3480156104f657600080fd5b506104c36004803603602081101561050d57600080fd5b50356001600160a01b0316610af2565b34801561052957600080fd5b506104c3610b08565b34801561053e57600080fd5b506104c3610b0e565b34801561055357600080fd5b506104856004803603606081101561056a57600080fd5b506001600160a01b03813581169160208101359091169060400135610b1c565b34801561059657600080fd5b506104c36004803603604081101561046f57600080fd5b3480156105b957600080fd5b506105c2610b2e565b604080516001600160a01b039092168252519081900360200190f35b3480156105ea57600080fd5b506105f3610b3d565b6040805160ff9092168252519081900360200190f35b34801561061557600080fd5b50610485610b46565b34801561062a57600080fd5b506103266004803603602081101561064157600080fd5b810190602081018135600160201b81111561065b57600080fd5b82018360208201111561066d57600080fd5b803590602001918460018302840111600160201b8311171561068e57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550610b4b945050505050565b3480156106db57600080fd5b506104c3610d6a565b3480156106f057600080fd5b506107ac6004803603606081101561070757600080fd5b6001600160a01b03823516916020810135151591810190606081016040820135600160201b81111561073857600080fd5b82018360208201111561074a57600080fd5b803590602001918460018302840111600160201b8311171561076b57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550610d70945050505050565b005b3480156107ba57600080fd5b506105c2610f13565b3480156107cf57600080fd5b506105c2610f22565b3480156107e457600080fd5b506104c3610f31565b3480156107f957600080fd5b506105c2610f37565b34801561080e57600080fd5b506104c36004803603602081101561082557600080fd5b50356001600160a01b0316610f46565b34801561084157600080fd5b506104c3610f50565b34801561085657600080fd5b506104c3610f5a565b34801561086b57600080fd5b50610326610f60565b34801561088057600080fd5b506104c3610fb8565b34801561089557600080fd5b506104c36004803603606081101561056a57600080fd5b3480156108b857600080fd5b506108df600480360360208110156108cf57600080fd5b50356001600160a01b0316610fbe565b604080519485526020850193909352838301919091526060830152519081900360800190f35b34801561091157600080fd5b506104c36004803603604081101561092857600080fd5b506001600160a01b0381358116916020013516610fd4565b34801561094c57600080fd5b506105c2610fde565b34801561096157600080fd5b506104c36004803603606081101561097857600080fd5b506001600160a01b03813581169160208101359160409091013516610b1c565b3480156109a457600080fd5b506105c2610fed565b6012546040516060916000916001600160a01b0390911690829036908083838082843760405192019450600093509091505080830381855af49150503d8060008114610a15576040519150601f19603f3d011682016040523d82523d6000602084013e610a1a565b606091505b505090506040513d6000823e818015610a31573d82f35b3d82fd5b60018054604080516020600284861615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015610aba5780601f10610a8f57610100808354040283529160200191610aba565b820191906000526020600020905b815481529060010190602001808311610a9d57829003601f168201915b505050505081565b601254606090610adb906001600160a01b031683611001565b92915050565b6000610aeb6109ad565b5092915050565b6000610afc6109ad565b50919050565b60085481565b600d5481565b6000610b186110c3565b5090565b6000610b266109ad565b509392505050565b6004546001600160a01b031681565b60035460ff1681565b600181565b606060006060306001600160a01b0316846040516024018080602001828103825283818151815260200191508051906020019080838360005b83811015610b9c578181015183820152602001610b84565b50505050905090810190601f168015610bc95780820380516001836020036101000a031916815260200191505b5060408051601f198184030181529181526020820180516001600160e01b0316630933c1ed60e01b178152905182519295509350839250908083835b60208310610c245780518252601f199092019160209182019101610c05565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d8060008114610c84576040519150601f19603f3d011682016040523d82523d6000602084013e610c89565b606091505b50915091506000821415610c9e573d60208201fd5b808060200190516020811015610cb357600080fd5b8101908080516040519392919084600160201b821115610cd257600080fd5b908301906020820185811115610ce757600080fd5b8251600160201b811182820188101715610d0057600080fd5b82525081516020918201929091019080838360005b83811015610d2d578181015183820152602001610d15565b50505050905090810190601f168015610d5a5780820380516001836020036101000a031916815260200191505b5060405250505092505050919050565b600b5481565b60035461010090046001600160a01b03163314610dbe5760405162461bcd60e51b81526004018080602001828103825260398152602001806111e46039913960400191505060405180910390fd5b8115610df8576040805160048152602481019091526020810180516001600160e01b031663153ab50560e01b179052610df690610ac2565b505b601280546001600160a01b038581166001600160a01b03198316179092556040516020602482018181528551604484015285519490931693610ec4938693909283926064909201919085019080838360005b83811015610e62578181015183820152602001610e4a565b50505050905090810190601f168015610e8f5780820380516001836020036101000a031916815260200191505b5060408051601f198184030181529190526020810180516001600160e01b0316630adccee560e31b1790529250610ac2915050565b50601254604080516001600160a01b038085168252909216602083015280517fd604de94d45953f9138079ec1b82d533cb2160c906d1076d1f7ed54befbca97a9281900390910190a150505050565b6012546001600160a01b031681565b6005546001600160a01b031681565b60095481565b6011546001600160a01b031681565b6000610afc6110c3565b6000610b186109ad565b600c5481565b6002805460408051602060018416156101000260001901909316849004601f81018490048402820184019092528181529291830182828015610aba5780601f10610a8f57610100808354040283529160200191610aba565b600a5481565b600080600080610fcc6110c3565b509193509193565b6000610aeb6110c3565b6006546001600160a01b031681565b60035461010090046001600160a01b031681565b606060006060846001600160a01b0316846040518082805190602001908083835b602083106110415780518252601f199092019160209182019101611022565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855af49150503d80600081146110a1576040519150601f19603f3d011682016040523d82523d6000602084013e6110a6565b606091505b509150915060008214156110bb573d60208201fd5b949350505050565b60606000306001600160a01b03166000366040516024018080602001828103825284848281815260200192508082843760008382015260408051601f909201601f1990811690940182810390940182529283526020810180516001600160e01b0316630933c1ed60e01b17815292518151919750955085945091925081905083835b602083106111645780518252601f199092019160209182019101611145565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855afa9150503d80600081146111c4576040519150601f19603f3d011682016040523d82523d6000602084013e6111c9565b606091505b505090506040513d6000823e818015610a31573d60408301f3fe56426570323044656c656761746f723a3a5f736574496d706c656d656e746174696f6e3a2043616c6c6572206d7573742062652061646d696e56426570323044656c656761746f723a66616c6c6261636b3a2063616e6e6f742073656e642076616c756520746f2066616c6c6261636ba265627a7a72315820f76198fce4f6ce47315ef097a3e79ac8147a52771429049461549f9b5f73fd0664736f6c6343000511003256426570323044656c656761746f723a3a5f736574496d706c656d656e746174696f6e3a2043616c6c6572206d7573742062652061646d696e", + "abi": [ + { + "inputs": [ + { "internalType": "address", "name": "underlying_", "type": "address" }, + { "internalType": "contract ComptrollerInterface", "name": "comptroller_", "type": "address" }, + { "internalType": "contract InterestRateModel", "name": "interestRateModel_", "type": "address" }, + { "internalType": "uint256", "name": "initialExchangeRateMantissa_", "type": "uint256" }, + { "internalType": "string", "name": "name_", "type": "string" }, + { "internalType": "string", "name": "symbol_", "type": "string" }, + { "internalType": "uint8", "name": "decimals_", "type": "uint8" }, + { "internalType": "address payable", "name": "admin_", "type": "address" }, + { "internalType": "address", "name": "implementation_", "type": "address" }, + { "internalType": "bytes", "name": "becomeImplementationData", "type": "bytes" } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "uint256", "name": "cashPrior", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "interestAccumulated", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "borrowIndex", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "totalBorrows", "type": "uint256" } + ], + "name": "AccrueInterest", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "owner", "type": "address" }, + { "indexed": true, "internalType": "address", "name": "spender", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "address", "name": "borrower", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "borrowAmount", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "accountBorrows", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "totalBorrows", "type": "uint256" } + ], + "name": "Borrow", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "uint256", "name": "error", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "info", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "detail", "type": "uint256" } + ], + "name": "Failure", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "address", "name": "liquidator", "type": "address" }, + { "indexed": false, "internalType": "address", "name": "borrower", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "repayAmount", "type": "uint256" }, + { "indexed": false, "internalType": "address", "name": "vTokenCollateral", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "seizeTokens", "type": "uint256" } + ], + "name": "LiquidateBorrow", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "address", "name": "minter", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "mintAmount", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "mintTokens", "type": "uint256" } + ], + "name": "Mint", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "address", "name": "oldAdmin", "type": "address" }, + { "indexed": false, "internalType": "address", "name": "newAdmin", "type": "address" } + ], + "name": "NewAdmin", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "contract ComptrollerInterface", + "name": "oldComptroller", + "type": "address" + }, + { + "indexed": false, + "internalType": "contract ComptrollerInterface", + "name": "newComptroller", + "type": "address" + } + ], + "name": "NewComptroller", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "address", "name": "oldImplementation", "type": "address" }, + { "indexed": false, "internalType": "address", "name": "newImplementation", "type": "address" } + ], + "name": "NewImplementation", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "contract InterestRateModel", + "name": "oldInterestRateModel", + "type": "address" + }, + { + "indexed": false, + "internalType": "contract InterestRateModel", + "name": "newInterestRateModel", + "type": "address" + } + ], + "name": "NewMarketInterestRateModel", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "address", "name": "oldPendingAdmin", "type": "address" }, + { "indexed": false, "internalType": "address", "name": "newPendingAdmin", "type": "address" } + ], + "name": "NewPendingAdmin", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "uint256", "name": "oldReserveFactorMantissa", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "newReserveFactorMantissa", "type": "uint256" } + ], + "name": "NewReserveFactor", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "address", "name": "redeemer", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "redeemAmount", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "redeemTokens", "type": "uint256" } + ], + "name": "Redeem", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "address", "name": "payer", "type": "address" }, + { "indexed": false, "internalType": "address", "name": "borrower", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "repayAmount", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "accountBorrows", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "totalBorrows", "type": "uint256" } + ], + "name": "RepayBorrow", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "address", "name": "benefactor", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "addAmount", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "newTotalReserves", "type": "uint256" } + ], + "name": "ReservesAdded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "address", "name": "admin", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "reduceAmount", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "newTotalReserves", "type": "uint256" } + ], + "name": "ReservesReduced", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "from", "type": "address" }, + { "indexed": true, "internalType": "address", "name": "to", "type": "address" }, + { "indexed": false, "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "Transfer", + "type": "event" + }, + { "payable": true, "stateMutability": "payable", "type": "fallback" }, + { + "constant": false, + "inputs": [], + "name": "_acceptAdmin", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "internalType": "uint256", "name": "addAmount", "type": "uint256" }], + "name": "_addReserves", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "internalType": "uint256", "name": "reduceAmount", "type": "uint256" }], + "name": "_reduceReserves", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "internalType": "contract ComptrollerInterface", "name": "newComptroller", "type": "address" }], + "name": "_setComptroller", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { "internalType": "address", "name": "implementation_", "type": "address" }, + { "internalType": "bool", "name": "allowResign", "type": "bool" }, + { "internalType": "bytes", "name": "becomeImplementationData", "type": "bytes" } + ], + "name": "_setImplementation", + "outputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "internalType": "contract InterestRateModel", "name": "newInterestRateModel", "type": "address" }], + "name": "_setInterestRateModel", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "internalType": "address payable", "name": "newPendingAdmin", "type": "address" }], + "name": "_setPendingAdmin", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "internalType": "uint256", "name": "newReserveFactorMantissa", "type": "uint256" }], + "name": "_setReserveFactor", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "accrualBlockNumber", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [], + "name": "accrueInterest", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "admin", + "outputs": [{ "internalType": "address payable", "name": "", "type": "address" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { "internalType": "address", "name": "owner", "type": "address" }, + { "internalType": "address", "name": "spender", "type": "address" } + ], + "name": "allowance", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { "internalType": "address", "name": "spender", "type": "address" }, + { "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "approve", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [{ "internalType": "address", "name": "owner", "type": "address" }], + "name": "balanceOf", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "internalType": "address", "name": "owner", "type": "address" }], + "name": "balanceOfUnderlying", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "internalType": "uint256", "name": "borrowAmount", "type": "uint256" }], + "name": "borrow", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "internalType": "address", "name": "account", "type": "address" }], + "name": "borrowBalanceCurrent", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [{ "internalType": "address", "name": "account", "type": "address" }], + "name": "borrowBalanceStored", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "borrowIndex", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "borrowRatePerBlock", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "comptroller", + "outputs": [{ "internalType": "contract ComptrollerInterface", "name": "", "type": "address" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "decimals", + "outputs": [{ "internalType": "uint8", "name": "", "type": "uint8" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "internalType": "bytes", "name": "data", "type": "bytes" }], + "name": "delegateToImplementation", + "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [{ "internalType": "bytes", "name": "data", "type": "bytes" }], + "name": "delegateToViewImplementation", + "outputs": [{ "internalType": "bytes", "name": "", "type": "bytes" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [], + "name": "exchangeRateCurrent", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "exchangeRateStored", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [{ "internalType": "address", "name": "account", "type": "address" }], + "name": "getAccountSnapshot", + "outputs": [ + { "internalType": "uint256", "name": "", "type": "uint256" }, + { "internalType": "uint256", "name": "", "type": "uint256" }, + { "internalType": "uint256", "name": "", "type": "uint256" }, + { "internalType": "uint256", "name": "", "type": "uint256" } + ], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "getCash", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "implementation", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "interestRateModel", + "outputs": [{ "internalType": "contract InterestRateModel", "name": "", "type": "address" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "isVToken", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { "internalType": "address", "name": "borrower", "type": "address" }, + { "internalType": "uint256", "name": "repayAmount", "type": "uint256" }, + { "internalType": "contract VTokenInterface", "name": "vTokenCollateral", "type": "address" } + ], + "name": "liquidateBorrow", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "internalType": "uint256", "name": "mintAmount", "type": "uint256" }], + "name": "mint", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "name", + "outputs": [{ "internalType": "string", "name": "", "type": "string" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "pendingAdmin", + "outputs": [{ "internalType": "address payable", "name": "", "type": "address" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "internalType": "uint256", "name": "redeemTokens", "type": "uint256" }], + "name": "redeem", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "internalType": "uint256", "name": "redeemAmount", "type": "uint256" }], + "name": "redeemUnderlying", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [{ "internalType": "uint256", "name": "repayAmount", "type": "uint256" }], + "name": "repayBorrow", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { "internalType": "address", "name": "borrower", "type": "address" }, + { "internalType": "uint256", "name": "repayAmount", "type": "uint256" } + ], + "name": "repayBorrowBehalf", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "reserveFactorMantissa", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { "internalType": "address", "name": "liquidator", "type": "address" }, + { "internalType": "address", "name": "borrower", "type": "address" }, + { "internalType": "uint256", "name": "seizeTokens", "type": "uint256" } + ], + "name": "seize", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "supplyRatePerBlock", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "symbol", + "outputs": [{ "internalType": "string", "name": "", "type": "string" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalBorrows", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [], + "name": "totalBorrowsCurrent", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalReserves", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "totalSupply", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { "internalType": "address", "name": "dst", "type": "address" }, + { "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "transfer", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { "internalType": "address", "name": "src", "type": "address" }, + { "internalType": "address", "name": "dst", "type": "address" }, + { "internalType": "uint256", "name": "amount", "type": "uint256" } + ], + "name": "transferFrom", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "underlying", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "payable": false, + "stateMutability": "view", + "type": "function" + } + ] +} diff --git a/assets/bsc/WhitePaperInterestRateModel.json b/assets/bsc/WhitePaperInterestRateModel.json new file mode 100644 index 00000000..29bf7242 --- /dev/null +++ b/assets/bsc/WhitePaperInterestRateModel.json @@ -0,0 +1,99 @@ +{ + "bytecode": "608060405234801561001057600080fd5b506040516107203803806107208339818101604052604081101561003357600080fd5b508051602091820151909161005690839062a06680906102ee6100bc821b17901c565b6001556100718162a066806100bc602090811b6102ee17901c565b600081905560015460408051918252602082019290925281517ff35fa19c15e9ba782633a5df62a98b20217151addc68e3ff2cd623a48d37ec27929181900390910190a150506101ad565b600061010483836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f00000000000081525061010b60201b60201c565b9392505050565b600081836101975760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561015c578181015183820152602001610144565b50505050905090810190601f1680156101895780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5060008385816101a357fe5b0495945050505050565b610564806101bc6000396000f3fe608060405234801561001057600080fd5b506004361061007d5760003560e01c80638726bb891161005b5780638726bb8914610102578063a385fb961461010a578063b816881614610112578063f14039de146101415761007d565b806315f24053146100825780632191f92a146100bd5780636e71e2d8146100d9575b600080fd5b6100ab6004803603606081101561009857600080fd5b5080359060208101359060400135610149565b60408051918252519081900360200190f35b6100c56101a3565b604080519115158252519081900360200190f35b6100ab600480360360608110156100ef57600080fd5b50803590602081013590604001356101a8565b6100ab6101fa565b6100ab610200565b6100ab6004803603608081101561012857600080fd5b5080359060208101359060408101359060600135610207565b6100ab610286565b6000806101578585856101a8565b905061019860015461018c670de0b6b3a76400006101806000548661028c90919063ffffffff16565b9063ffffffff6102ee16565b9063ffffffff61033016565b9150505b9392505050565b600181565b6000826101b75750600061019c565b6101f26101da836101ce878763ffffffff61033016565b9063ffffffff61037216565b61018085670de0b6b3a764000063ffffffff61028c16565b949350505050565b60005481565b62a0668081565b600080610222670de0b6b3a76400008463ffffffff61037216565b90506000610231878787610149565b90506000610251670de0b6b3a7640000610180848663ffffffff61028c16565b905061027a670de0b6b3a76400006101808361026e8c8c8c6101a8565b9063ffffffff61028c16565b98975050505050505050565b60015481565b60008261029b575060006102e8565b828202828482816102a857fe5b04146102e55760405162461bcd60e51b815260040180806020018281038252602181526020018061050f6021913960400191505060405180910390fd5b90505b92915050565b60006102e583836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f0000000000008152506103b4565b60006102e583836040518060400160405280601b81526020017f536166654d6174683a206164646974696f6e206f766572666c6f770000000000815250610456565b60006102e583836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506104b4565b600081836104405760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156104055781810151838201526020016103ed565b50505050905090810190601f1680156104325780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b50600083858161044c57fe5b0495945050505050565b600083830182858210156104ab5760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156104055781810151838201526020016103ed565b50949350505050565b600081848411156105065760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156104055781810151838201526020016103ed565b50505090039056fe536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77a265627a7a723158208907006cfa0ce458f7c18512eee61d98e1d9fad802f1a998331772e4fedd274264736f6c63430005110032", + "abi": [ + { + "inputs": [ + { "internalType": "uint256", "name": "baseRatePerYear", "type": "uint256" }, + { "internalType": "uint256", "name": "multiplierPerYear", "type": "uint256" } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": false, "internalType": "uint256", "name": "baseRatePerBlock", "type": "uint256" }, + { "indexed": false, "internalType": "uint256", "name": "multiplierPerBlock", "type": "uint256" } + ], + "name": "NewInterestParams", + "type": "event" + }, + { + "constant": true, + "inputs": [], + "name": "baseRatePerBlock", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "blocksPerYear", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { "internalType": "uint256", "name": "cash", "type": "uint256" }, + { "internalType": "uint256", "name": "borrows", "type": "uint256" }, + { "internalType": "uint256", "name": "reserves", "type": "uint256" } + ], + "name": "getBorrowRate", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { "internalType": "uint256", "name": "cash", "type": "uint256" }, + { "internalType": "uint256", "name": "borrows", "type": "uint256" }, + { "internalType": "uint256", "name": "reserves", "type": "uint256" }, + { "internalType": "uint256", "name": "reserveFactorMantissa", "type": "uint256" } + ], + "name": "getSupplyRate", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "isInterestRateModel", + "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [], + "name": "multiplierPerBlock", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "view", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { "internalType": "uint256", "name": "cash", "type": "uint256" }, + { "internalType": "uint256", "name": "borrows", "type": "uint256" }, + { "internalType": "uint256", "name": "reserves", "type": "uint256" } + ], + "name": "utilizationRate", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "payable": false, + "stateMutability": "pure", + "type": "function" + } + ] +} diff --git a/contracts/interfaces/WrappedPiErc20Interface.sol b/contracts/interfaces/WrappedPiErc20Interface.sol index ac640565..3545506e 100644 --- a/contracts/interfaces/WrappedPiErc20Interface.sol +++ b/contracts/interfaces/WrappedPiErc20Interface.sol @@ -23,7 +23,7 @@ interface WrappedPiErc20Interface is IERC20 { bytes4 signature, bytes calldata args, uint256 value - ) external; + ) external returns (bytes memory); struct ExternalCallData { address destination; @@ -32,7 +32,7 @@ interface WrappedPiErc20Interface is IERC20 { uint256 value; } - function callExternalMultiple(ExternalCallData[] calldata calls) external; + function callExternalMultiple(ExternalCallData[] calldata calls) external returns (bytes[] memory); function getUnderlyingBalance() external view returns (uint256); } diff --git a/contracts/interfaces/venus/VBep20Interface.sol b/contracts/interfaces/venus/VBep20Interface.sol new file mode 100644 index 00000000..cc52ef66 --- /dev/null +++ b/contracts/interfaces/venus/VBep20Interface.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.6.12; + +interface VBep20Interface { + function mint(uint256 mintAmount) external returns (uint256); + + function redeem(uint256 redeemTokens) external returns (uint256); + + function redeemUnderlying(uint256 redeemAmount) external returns (uint256); + + function borrow(uint256 borrowAmount) external returns (uint256); + + function repayBorrow(uint256 repayAmount) external returns (uint256); + + function repayBorrowBehalf(address borrower, uint256 repayAmount) external returns (uint256); + + function comptroller() external view returns (address); + + function underlying() external view returns (address); + + function accrueInterest() external returns (uint256); + + function exchangeRateStored() external view returns (uint256); +} diff --git a/contracts/interfaces/venus/VenusComptrollerInterface.sol b/contracts/interfaces/venus/VenusComptrollerInterface.sol new file mode 100644 index 00000000..1e427ad1 --- /dev/null +++ b/contracts/interfaces/venus/VenusComptrollerInterface.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.6.12; + +interface VenusComptrollerInterface { + function enterMarkets(address[] calldata cTokens) external returns (uint256[] memory); + + function exitMarket(address cToken) external returns (uint256); + + function claimVenus( + address[] memory holders, + address[] memory cTokens, + bool borrowers, + bool suppliers + ) external; + + function markets(address cToken) + external + view + returns ( + bool, + uint256, + bool + ); + + function compSpeeds(address cToken) external view returns (uint256); +} diff --git a/contracts/powerindex-router/PowerIndexBasicRouter.sol b/contracts/powerindex-router/PowerIndexBasicRouter.sol index 642c1df0..8a2ce904 100644 --- a/contracts/powerindex-router/PowerIndexBasicRouter.sol +++ b/contracts/powerindex-router/PowerIndexBasicRouter.sol @@ -165,12 +165,13 @@ contract PowerIndexBasicRouter is PowerIndexBasicRouterInterface, PowerIndexNaiv bool _claimAndDistributeRewards, bytes calldata _rewardOpts ) external onlyReporter(_reporterId, _rewardOpts) onlyEOA { + _beforePoke(); (uint256 minInterval, ) = _getMinMaxReportInterval(); (ReserveStatus status, uint256 diff, bool forceRebalance) = getReserveStatus(_getUnderlyingStaked(), 0); require(forceRebalance || lastRebalancedAt + minInterval < block.timestamp, "MIN_INTERVAL_NOT_REACHED"); require(status != ReserveStatus.EQUILIBRIUM, "RESERVE_STATUS_EQUILIBRIUM"); _rebalancePoke(status, diff); - _postPoke(status, _claimAndDistributeRewards); + _afterPoke(status, _claimAndDistributeRewards); } function pokeFromSlasher( @@ -178,21 +179,27 @@ contract PowerIndexBasicRouter is PowerIndexBasicRouterInterface, PowerIndexNaiv bool _claimAndDistributeRewards, bytes calldata _rewardOpts ) external onlyNonReporter(_reporterId, _rewardOpts) onlyEOA { + _beforePoke(); (, uint256 maxInterval) = _getMinMaxReportInterval(); (ReserveStatus status, uint256 diff, bool forceRebalance) = getReserveStatus(_getUnderlyingStaked(), 0); require(forceRebalance || lastRebalancedAt + maxInterval < block.timestamp, "MAX_INTERVAL_NOT_REACHED"); require(status != ReserveStatus.EQUILIBRIUM, "RESERVE_STATUS_EQUILIBRIUM"); _rebalancePoke(status, diff); - _postPoke(status, _claimAndDistributeRewards); + _afterPoke(status, _claimAndDistributeRewards); } function poke(bool _claimAndDistributeRewards) external onlyEOA { + _beforePoke(); (ReserveStatus status, uint256 diff, ) = getReserveStatus(_getUnderlyingStaked(), 0); _rebalancePoke(status, diff); - _postPoke(status, _claimAndDistributeRewards); + _afterPoke(status, _claimAndDistributeRewards); } - function _postPoke(ReserveStatus reserveStatus, bool _claimAndDistributeRewards) internal { + function _beforePoke() internal virtual { + require(staking != address(0), "STAKING_IS_NULL"); + } + + function _afterPoke(ReserveStatus reserveStatus, bool _claimAndDistributeRewards) internal { lastRebalancedAt = block.timestamp; if (_claimAndDistributeRewards && lastClaimRewardsAt + claimRewardsInterval < block.timestamp) { @@ -214,12 +221,12 @@ contract PowerIndexBasicRouter is PowerIndexBasicRouterInterface, PowerIndexNaiv // need to redefine in implementation } - function _callVoting(bytes4 _sig, bytes memory _data) internal { - piToken.callExternal(voting, _sig, _data, 0); + function _callVoting(bytes4 _sig, bytes memory _data) internal returns (bytes memory) { + return piToken.callExternal(voting, _sig, _data, 0); } - function _callStaking(bytes4 _sig, bytes memory _data) internal { - piToken.callExternal(staking, _sig, _data, 0); + function _callStaking(bytes4 _sig, bytes memory _data) internal returns (bytes memory) { + return piToken.callExternal(staking, _sig, _data, 0); } function _checkVotingSenderAllowed() internal view { diff --git a/contracts/powerindex-router/WrappedPiErc20.sol b/contracts/powerindex-router/WrappedPiErc20.sol index db817418..22c82924 100644 --- a/contracts/powerindex-router/WrappedPiErc20.sol +++ b/contracts/powerindex-router/WrappedPiErc20.sol @@ -126,14 +126,20 @@ contract WrappedPiErc20 is ERC20, ReentrancyGuard, WrappedPiErc20Interface { bytes4 _signature, bytes calldata _args, uint256 _value - ) external override onlyRouter { - _callExternal(_destination, _signature, _args, _value); + ) external override onlyRouter returns (bytes memory) { + return _callExternal(_destination, _signature, _args, _value); } - function callExternalMultiple(ExternalCallData[] calldata _calls) external override onlyRouter { + function callExternalMultiple(ExternalCallData[] calldata _calls) + external + override + onlyRouter + returns (bytes[] memory results) + { uint256 len = _calls.length; + results = new bytes[](len); for (uint256 i = 0; i < len; i++) { - _callExternal(_calls[i].destination, _calls[i].signature, _calls[i].args, _calls[i].value); + results[i] = _callExternal(_calls[i].destination, _calls[i].signature, _calls[i].args, _calls[i].value); } } @@ -146,7 +152,7 @@ contract WrappedPiErc20 is ERC20, ReentrancyGuard, WrappedPiErc20Interface { bytes4 _signature, bytes calldata _args, uint256 _value - ) internal { + ) internal returns (bytes memory) { (bool success, bytes memory data) = _destination.call{ value: _value }(abi.encodePacked(_signature, _args)); if (!success) { @@ -170,5 +176,7 @@ contract WrappedPiErc20 is ERC20, ReentrancyGuard, WrappedPiErc20Interface { } emit CallExternal(_destination, _signature, _args, data); + + return data; } } diff --git a/contracts/powerindex-router/implementations/VenusVBep20SupplyRouter.sol b/contracts/powerindex-router/implementations/VenusVBep20SupplyRouter.sol new file mode 100644 index 00000000..7ac7bcb1 --- /dev/null +++ b/contracts/powerindex-router/implementations/VenusVBep20SupplyRouter.sol @@ -0,0 +1,286 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.6.12; +pragma experimental ABIEncoderV2; + +import "../PowerIndexBasicRouter.sol"; +import "../../interfaces/venus/VenusComptrollerInterface.sol"; +import "../../interfaces/venus/VBep20Interface.sol"; + +contract VenusVBep20SupplyRouter is PowerIndexBasicRouter { + event Stake(address indexed sender, uint256 amount, uint256 rewardReceived); + event Redeem(address indexed sender, uint256 amount, uint256 rewardReceived); + event IgnoreDueMissingStaking(); + event ClaimRewards(address indexed sender, uint256 xvsEarned, uint256 underlyingEarned); + event DistributeUnderlyingReward( + address indexed sender, + uint256 underlyingReward, + uint256 pvpReward, + uint256 poolRewardsUnderlying, + uint256 poolRewardsPi, + address[] pools + ); + + struct VenusConfig { + address troller; + address xvs; + } + + uint256 internal constant NO_ERROR_CODE = 0; + + address internal immutable TROLLER; + IERC20 internal immutable UNDERLYING; + IERC20 internal immutable XVS; + + constructor( + address _piToken, + BasicConfig memory _basicConfig, + VenusConfig memory _compConfig + ) public PowerIndexBasicRouter(_piToken, _basicConfig) { + TROLLER = _compConfig.troller; + UNDERLYING = IERC20(VBep20Interface(_basicConfig.staking).underlying()); + XVS = IERC20(_compConfig.xvs); + } + + /*** THE PROXIED METHOD EXECUTORS FOR VOTING ***/ + + function _claimRewards(ReserveStatus) internal override { + // #1. Claim XVS + address[] memory holders = new address[](1); + holders[0] = address(piToken); + address[] memory tokens = new address[](1); + tokens[0] = staking; + + uint256 xvsBefore = XVS.balanceOf(address(piToken)); + piToken.callExternal( + TROLLER, + VenusComptrollerInterface.claimVenus.selector, + abi.encode(holders, tokens, false, true), + 0 + ); + uint256 xvsEarned = XVS.balanceOf(address(piToken)).sub(xvsBefore); + if (xvsEarned > 0) { + piToken.callExternal(address(XVS), IERC20.transfer.selector, abi.encode(address(this), xvsEarned), 0); + } + + // #2. Redeem underlying interest + uint256 pendingInterestReward = getPendingInterestReward(); + + uint256 underlyingEarned = 0; + if (pendingInterestReward > 0) { + uint256 underlyingBefore = UNDERLYING.balanceOf(address(piToken)); + _callCompStaking(VBep20Interface(0).redeemUnderlying.selector, abi.encode(pendingInterestReward)); + underlyingEarned = UNDERLYING.balanceOf(address(piToken)).sub(underlyingBefore); + } + + if (underlyingEarned > 0) { + piToken.callExternal( + address(UNDERLYING), + IERC20.transfer.selector, + abi.encode(address(this), underlyingEarned), + 0 + ); + } + + // #3. Emit claim results + emit ClaimRewards(msg.sender, xvsEarned, underlyingEarned); + } + + function _distributeRewards() internal override { + uint256 xvsToDistribute = IERC20(XVS).balanceOf(address(this)); + uint256 underlyingToDistribute = UNDERLYING.balanceOf(address(this)); + require(xvsToDistribute > 0 || underlyingToDistribute > 0, "NOTHING_TO_DISTRIBUTE"); + + if (XVS == UNDERLYING) { + _distributeUnderlyingReward(underlyingToDistribute); + } else { + // WARNING: XVS distribution for the cases with XVS != UNDERLYING is not supported yet + // The accrued XVS will remain on this contract + _distributeUnderlyingReward(underlyingToDistribute); + } + } + + function _distributeUnderlyingReward(uint256 _underlyingToDistribute) internal { + // Step #1. Distribute pvpReward + (uint256 pvpReward, uint256 poolRewardsUnderlying) = _distributeRewardToPvp(_underlyingToDistribute, UNDERLYING); + require(poolRewardsUnderlying > 0, "NO_POOL_REWARDS_UNDERLYING"); + + // Step #2. Wrap underlying into piToken + UNDERLYING.approve(address(piToken), poolRewardsUnderlying); + piToken.deposit(poolRewardsUnderlying); + + // Step #3. Distribute piToken over the pools + (uint256 poolRewardsPi, address[] memory pools) = _distributePiRemainderToPools(piToken); + + emit DistributeUnderlyingReward( + msg.sender, + _underlyingToDistribute, + pvpReward, + poolRewardsUnderlying, + poolRewardsPi, + pools + ); + } + + /*** OWNER METHODS ***/ + + function initRouter() external onlyOwner { + address[] memory tokens = new address[](1); + tokens[0] = staking; + bytes memory result = + piToken.callExternal(TROLLER, VenusComptrollerInterface.enterMarkets.selector, abi.encode(tokens), 0); + uint256[] memory err = abi.decode(result, (uint256[])); + require(err[0] == NO_ERROR_CODE, "V_ERROR"); + _callStaking(IERC20.approve.selector, abi.encode(staking, uint256(-1))); + } + + function stake(uint256 _amount) external onlyOwner { + _stake(_amount); + } + + function redeem(uint256 _amount) external onlyOwner { + _redeem(_amount); + } + + /*** POKE FUNCTION ***/ + + function _beforePoke() internal override { + super._beforePoke(); + require(VBep20Interface(staking).accrueInterest() == NO_ERROR_CODE, "V_ERROR"); + } + + function _rebalancePoke(ReserveStatus reserveStatus, uint256 diff) internal override { + if (reserveStatus == ReserveStatus.SHORTAGE) { + _redeem(diff); + } else if (reserveStatus == ReserveStatus.EXCESS) { + _stake(diff); + } + } + + /*** VIEWERS ***/ + + /** + * @notice Get the amount of vToken will be minted in exchange of the given underlying tokens + * @param _tokenAmount The input amount of underlying tokens + * @return The corresponding amount of vTokens tokens + */ + function getVTokenForToken(uint256 _tokenAmount) public view returns (uint256) { + // token / exchangeRate + return _tokenAmount.mul(1e18) / VBep20Interface(staking).exchangeRateStored(); + } + + /** + * @notice Get the amount of underlying tokens will released in exchange of the given vTokens + * @param _vTokenAmount The input amount of vTokens tokens + * @return The corresponding amount of underlying tokens + */ + function getTokenForVToken(uint256 _vTokenAmount) public view returns (uint256) { + // vToken * exchangeRate + return _vTokenAmount.mul(VBep20Interface(staking).exchangeRateStored()) / 1e18; + } + + /** + * @notice Get the total amount of UNDERLYING tokens could be released in exchange of the piToken's vToken balance. + * Is comprised of the underlyingStaked and the pendingRewards. + * @return The UNDERLYING amount + */ + function getUnderlyingBackedByVToken() public view returns (uint256) { + if (staking == address(0)) { + return 0; + } + + uint256 vTokenAtPiToken = IERC20(staking).balanceOf(address(piToken)); + if (vTokenAtPiToken == 0) { + return 0; + } + + return getTokenForVToken(vTokenAtPiToken); + } + + /** + * @notice Get the amount of current pending rewards available at VToken + * @dev Does not includes the accrued XVS amount + * @dev Uses the last cached value, not the current one + * @dev Use with front-end only + * @return amount of pending rewards + */ + function getPendingInterestReward() public view returns (uint256 amount) { + // return underlyingAtPiToken + underlyingBackedByVToken - piToken.totalSupply() + amount = UNDERLYING.balanceOf(address(piToken)).add(getUnderlyingBackedByVToken()).add(1).sub( + piToken.totalSupply() + ); + return amount == 1 ? 0 : amount; + } + + /*** EQUIVALENT METHODS OVERRIDES ***/ + + function getPiEquivalentForUnderlying( + uint256 _underlyingAmount, + IERC20, /* _underlyingToken */ + uint256 /* _piTotalSupply */ + ) public view override returns (uint256) { + return _underlyingAmount; + } + + function getPiEquivalentForUnderlyingPure( + uint256 _underlyingAmount, + uint256, /* _totalUnderlyingWrapped */ + uint256 /* _piTotalSupply */ + ) public pure override returns (uint256) { + return _underlyingAmount; + } + + function getUnderlyingEquivalentForPi( + uint256 _piAmount, + IERC20, /* _underlyingToken */ + uint256 /* _piTotalSupply */ + ) public view override returns (uint256) { + return _piAmount; + } + + function getUnderlyingEquivalentForPiPure( + uint256 _piAmount, + uint256, /* _totalUnderlyingWrapped */ + uint256 /* _piTotalSupply */ + ) public pure override returns (uint256) { + return _piAmount; + } + + /*** INTERNALS ***/ + + function _getUnderlyingStaked() internal view override returns (uint256) { + // return piTokenTotalSupply - underlyingAtPiToken + return piToken.totalSupply().sub(UNDERLYING.balanceOf(address(piToken))); + } + + function _stake(uint256 _amount) internal { + require(_amount > 0, "CANT_STAKE_0"); + + uint256 underlyingBefore = UNDERLYING.balanceOf(address(piToken)); + + piToken.approveUnderlying(staking, _amount); + + _callCompStaking(VBep20Interface(0).mint.selector, abi.encode(_amount)); + uint256 receivedReward = UNDERLYING.balanceOf(address(piToken)).sub(underlyingBefore.sub(_amount)); + piToken.callExternal(address(UNDERLYING), IERC20.transfer.selector, abi.encode(address(this), receivedReward), 0); + + emit Stake(msg.sender, _amount, receivedReward); + } + + function _redeem(uint256 _amount) internal { + require(_amount > 0, "CANT_REDEEM_0"); + + uint256 underlyingBefore = UNDERLYING.balanceOf(address(piToken)); + _callCompStaking(VBep20Interface(0).redeemUnderlying.selector, abi.encode(_amount)); + uint256 receivedReward = UNDERLYING.balanceOf(address(piToken)).sub(underlyingBefore).sub(_amount); + piToken.callExternal(address(UNDERLYING), IERC20.transfer.selector, abi.encode(address(this), receivedReward), 0); + + emit Redeem(msg.sender, _amount, receivedReward); + } + + function _callCompStaking(bytes4 _sig, bytes memory _data) internal { + bytes memory result = _callStaking(_sig, _data); + uint256 err = abi.decode(result, (uint256)); + require(err == NO_ERROR_CODE, "V_ERROR"); + } +} diff --git a/contracts/test/MockOracle.sol b/contracts/test/MockOracle.sol index 1a18cdd7..c70e8a64 100644 --- a/contracts/test/MockOracle.sol +++ b/contracts/test/MockOracle.sol @@ -4,6 +4,7 @@ pragma solidity 0.6.12; contract MockOracle { mapping(address => uint256) public prices; + mapping(address => address) public wrappers; constructor() public {} @@ -11,6 +12,10 @@ contract MockOracle { prices[token] = price; } + function setWrapper(address wrapper, address underlying) public { + wrappers[wrapper] = underlying; + } + function assetPrices(address token) public view returns (uint256) { return prices[token]; } @@ -18,4 +23,8 @@ contract MockOracle { function getPriceByAsset(address token) public view returns (uint256) { return prices[token]; } + + function getUnderlyingPrice(address wrapper) public view returns (uint256) { + return prices[wrappers[wrapper]]; + } } diff --git a/test/helpers/builders.js b/test/helpers/builders.js index e47a8703..89f2e35b 100644 --- a/test/helpers/builders.js +++ b/test/helpers/builders.js @@ -59,6 +59,11 @@ function buildAutoRouterConfig(AUTO) { return { AUTO }; } +// VENUS +function buildVenusRouterConfig(troller, xvs) { + return { troller, xvs }; +} + const BasicConfig = { poolRestrictions: 'address', powerPoke: 'address', @@ -143,6 +148,7 @@ module.exports = { buildBakeryChefRouterConfig, buildMasterChefRouterConfig, buildAutoRouterConfig, + buildVenusRouterConfig, buildAaveAssetConfigInput, buildBasicRouterArgs, buildYearnRouterArgs, diff --git a/test/helpers/index.js b/test/helpers/index.js index 77c20785..3aa343cb 100644 --- a/test/helpers/index.js +++ b/test/helpers/index.js @@ -139,11 +139,15 @@ async function expectExactRevert(promise, expectedMsg) { /** * Creates a truffle contract from bytecode and abi - * @param name of the contract along with path - * @returns TruffleContract + * @param {string} name of the contract along with path + * @param {[{substr: regex, newSubstr: string}]} bytecodeReplacements the list of bytecode replacements + * @returns {TruffleContract} */ -function artifactFromBytecode(name) { +function artifactFromBytecode(name, bytecodeReplacements = []) { const data = require(`../../assets/${name}.json`); + for (let i = 0; i < bytecodeReplacements.length; i++) { + data.bytecode = data.bytecode.replace(bytecodeReplacements[i].substr, bytecodeReplacements[i].newSubstr); + } const contract = TruffleContract(data); contract.setProvider(web3.currentProvider); contract.defaults(template.class_defaults); @@ -407,6 +411,39 @@ function assertEqualWithAccuracy(bn1, bn2, accuracyPercentWei = '100000000') { assert.equal(lowerThenAccurancy, true, 'diffPercent is ' + web3.utils.fromWei(diffPercent, 'ether')); } +async function newCompContract(contract, ...args) { + const instance = await contract.new(...args); + attachToInstance(instance) + return instance; +} + +async function attachCompContract(contract, address) { + const instance = await contract.at(address); + attachToInstance(instance) + return instance; +} + +function attachToInstance(instance) { + for (let methodName of Object.keys(instance)) { + if (!instance.contract.methods[methodName]) { + continue; + } + const method = instance[methodName]; + instance[methodName] = async function(...args) { + const res = await method(...args); + if (typeof res === 'object' && 'logs' in res) { + for (let log of res.logs) { + if (log.event === 'Failure') { + throw new Error(`Comp error: ${log.args.error} info: ${log.args.info}`); + } + } + } + return res; + } + } +} + + module.exports = { deployProxied, @@ -443,5 +480,7 @@ module.exports = { divBN, subBN, addBN, - assertEqualWithAccuracy + assertEqualWithAccuracy, + newCompContract, + attachCompContract, } diff --git a/test/router/implementations/VenusRouter.unit.js b/test/router/implementations/VenusRouter.unit.js new file mode 100644 index 00000000..7cea2464 --- /dev/null +++ b/test/router/implementations/VenusRouter.unit.js @@ -0,0 +1,687 @@ +const { time, constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { ether, addBN, artifactFromBytecode, newCompContract, attachCompContract } = require('../../helpers'); +const { buildBasicRouterConfig, buildVenusRouterConfig } = require('../../helpers/builders'); +const assert = require('chai').assert; +const MockERC20 = artifacts.require('MockERC20'); +const VenusVBep20SupplyRouter = artifacts.require('VenusVBep20SupplyRouter'); +const WrappedPiErc20 = artifacts.require('WrappedPiErc20'); +const PoolRestrictions = artifacts.require('PoolRestrictions'); +const SushiBar = artifacts.require('SushiBar'); +const MockGulpingBPool = artifacts.require('MockGulpingBPool'); +const MockPoke = artifacts.require('MockPoke'); +const MockOracle = artifacts.require('MockOracle'); + +MockERC20.numberFormat = 'String'; +VenusVBep20SupplyRouter.numberFormat = 'String'; +WrappedPiErc20.numberFormat = 'String'; +SushiBar.numberFormat = 'String'; + +const Unitroller = artifactFromBytecode('bsc/Unitroller'); +const ComptrollerV1 = artifactFromBytecode('bsc/ComptrollerV1'); +const VBep20Delegate = artifactFromBytecode('bsc/VBep20Delegate'); +const VBep20Delegator = artifactFromBytecode('bsc/VBep20Delegator'); +const WhitePaperInterestRateModel = artifactFromBytecode('bsc/WhitePaperInterestRateModel'); + +const { web3 } = MockERC20; + +describe('VenusRouter Tests', () => { + let bob, alice, charlie, venusOwner, piGov, stub, pvp, pool1, pool2; + + before(async function() { + [, bob, alice, charlie, venusOwner, piGov, stub, pvp, pool1, pool2] = await web3.eth.getAccounts(); + }); + + let trollerV4, oracle, usdc, xvs, vUsdc, interestRateModel, poolRestrictions, piUsdc, venusRouter, poke, cake, vCake; + + beforeEach(async function() { + // bsc: 0xcF6BB5389c92Bdda8a3747Ddb454cB7a64626C63 + xvs = await MockERC20.new('Venus', 'XVS', '18', ether(1e14)); + + // bsc: 0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d + usdc = await MockERC20.new('USD Coin', 'USDC', 18, ether('10000000')); + cake = await MockERC20.new('Pancake', 'CAKE', 18, ether('10000000')); + + // bsc: 0x9e47c4f8654edfb45bc81e7e320c8fc1ad0acb73 + interestRateModel = await WhitePaperInterestRateModel.new( + // baseRatePerYear + 0, + // multiplierPerYear + ether('90'), + ); + + // bsc: 0xd8b6da2bfec71d684d3e2a2fc9492ddad5c3787f + oracle = await MockOracle.new(); + const replacement = xvs.address.substring(2).toLowerCase(); + const ComptrollerV4 = artifactFromBytecode('bsc/ComptrollerV4', [ + { substr: 'cf6bb5389c92bdda8a3747ddb454cb7a64626c63', newSubstr: replacement }, + ]); + + // bsc: 0xfD36E2c2a6789Db23113685031d7F16329158384 -> (0xba469fba7ea40d237b92bf30625513700f0afa47:V4) + const comptrollerV1 = await ComptrollerV1.new(); + const comptrollerV4 = await ComptrollerV4.new(); + const unitroller = await newCompContract(Unitroller); + const trollerV3 = await attachCompContract(ComptrollerV1, unitroller.address); + trollerV4 = await attachCompContract(ComptrollerV4, unitroller.address); + + // bump to V1 + await unitroller._setPendingImplementation(comptrollerV1.address); + await comptrollerV1._become(unitroller.address); + + // bsc: 0xecA88125a5ADbe82614ffC12D0DB554E2e2867C8 + const vUsdcImpl = await VBep20Delegate.new(); + vUsdc = await newCompContract( + VBep20Delegator, + // address underlying_, + usdc.address, + // ComptrollerInterface comptroller_, + unitroller.address, + // InterestRateModel interestRateModel_, + interestRateModel.address, + // uint initialExchangeRateMantissa_, + ether(1), + // string memory name_, + 'Venus USDC', + // string memory symbol_, + 'vUSDC', + // uint8 decimals_, + 8, + // address payable admin_, + venusOwner, + // address implementation_, + vUsdcImpl.address, + // bytes memory becomeImplementationData + '0x', + ); + vCake = await newCompContract( + VBep20Delegator, + // address underlying_, + cake.address, + // ComptrollerInterface comptroller_, + unitroller.address, + // InterestRateModel interestRateModel_, + interestRateModel.address, + // uint initialExchangeRateMantissa_, + ether(1), + // string memory name_, + 'Venus CAKE', + // string memory symbol_, + 'vCAKE', + // uint8 decimals_, + 8, + // address payable admin_, + venusOwner, + // address implementation_, + vUsdcImpl.address, + // bytes memory becomeImplementationData + '0x', + ); + + poolRestrictions = await PoolRestrictions.new(); + piUsdc = await WrappedPiErc20.new(usdc.address, stub, 'Wrapped USDC', 'piUSDC'); + poke = await MockPoke.new(true); + venusRouter = await VenusVBep20SupplyRouter.new( + piUsdc.address, + buildBasicRouterConfig( + poolRestrictions.address, + poke.address, + constants.ZERO_ADDRESS, + vUsdc.address, + ether('0.2'), + ether('0.02'), + '0', + pvp, + ether('0.15'), + [pool1, pool2], + ), + buildVenusRouterConfig(unitroller.address, xvs.address), + ); + + await piUsdc.changeRouter(venusRouter.address, { from: stub }); + + await oracle.setPrice(usdc.address, ether(1)); + await oracle.setPrice(cake.address, ether(20)); + await oracle.setWrapper(vUsdc.address, usdc.address); + await oracle.setWrapper(vCake.address, cake.address); + + await trollerV3._setPriceOracle(oracle.address); + await trollerV3._supportMarket(vUsdc.address); + await trollerV3._supportMarket(vCake.address); + await trollerV3._setVenusRate(ether(600000)); + await trollerV3._setMaxAssets(10); + await trollerV3._addVenusMarkets([vUsdc.address]); + await trollerV3._setCollateralFactor(vUsdc.address, ether(0.8)); + await trollerV3._setCollateralFactor(vCake.address, ether(0.8)); + + await trollerV3.enterMarkets([vUsdc.address, vCake.address], { from: bob }); + await trollerV3.enterMarkets([vUsdc.address, vCake.address], { from: charlie }); + + // bump to V4 + await unitroller._setPendingImplementation(comptrollerV4.address); + await comptrollerV4._become(unitroller.address); + await trollerV4._setVenusSpeed(vUsdc.address, ether(300000)); + + await venusRouter.initRouter(); + + await usdc.transfer(bob, ether(42000)); + await usdc.approve(vUsdc.address, ether(42000), { from: bob }); + await vUsdc.mint(ether(42000), { from: bob }); + + await cake.transfer(charlie, ether(5000)); + await cake.approve(vCake.address, ether(5000), { from: charlie }); + await vCake.mint(ether(5000), { from: charlie }); + + await venusRouter.transferOwnership(piGov); + + assert.equal(await venusRouter.owner(), piGov); + }); + + describe('owner methods', async () => { + beforeEach(async () => { + await venusRouter.transferOwnership(piGov, { from: piGov }); + }); + + describe('stake()/redeem()', () => { + beforeEach(async () => { + await usdc.transfer(alice, ether('10000')); + await usdc.approve(piUsdc.address, ether('10000'), { from: alice }); + await piUsdc.deposit(ether('10000'), { from: alice }); + + await venusRouter.poke(false); + + assert.equal(await usdc.balanceOf(piUsdc.address), ether(2000)); + assert.equal(await usdc.balanceOf(vUsdc.address), ether(50000)); + assert.equal(await vUsdc.balanceOf(piUsdc.address), ether(8000)); + }); + + describe('stake()', () => { + it('should allow the owner staking any amount of reserve tokens', async () => { + const res = await venusRouter.stake(ether(2000), { from: piGov }); + expectEvent(res, 'Stake', { + sender: piGov, + amount: ether(2000), + }); + assert.equal(await usdc.balanceOf(piUsdc.address), ether(0)); + assert.equal(await usdc.balanceOf(vUsdc.address), ether(52000)); + assert.equal(await vUsdc.balanceOf(piUsdc.address), ether(10000)); + }); + + it('should deny staking 0', async () => { + await expectRevert(venusRouter.stake(ether(0), { from: piGov }), 'CANT_STAKE_0'); + }); + + it('should deny non-owner staking any amount of reserve tokens', async () => { + await expectRevert(venusRouter.stake(ether(1), { from: alice }), 'Ownable: caller is not the owner'); + }); + }); + + describe('redeem()', () => { + it('should allow the owner redeeming any amount of reserve tokens', async () => { + const res = await venusRouter.redeem(ether(3000), { from: piGov }); + expectEvent(res, 'Redeem', { + sender: piGov, + amount: ether(3000), + }); + assert.equal(await usdc.balanceOf(piUsdc.address), ether(5000)); + assert.equal(await vUsdc.balanceOf(piUsdc.address), ether(5000)); + assert.equal(await usdc.balanceOf(vUsdc.address), ether(47000)); + }); + + it('should deny redeeming 0', async () => { + await expectRevert(venusRouter.redeem(ether(0), { from: piGov }), 'CANT_REDEEM_0'); + }); + + it('should deny non-owner staking any amount of reserve tokens', async () => { + await expectRevert(venusRouter.redeem(ether(1), { from: alice }), 'Ownable: caller is not the owner'); + }); + }); + }); + + describe('setRewardPools()', () => { + it('should allow the owner setting a new reward pool', async () => { + const res = await venusRouter.setRewardPools([alice, bob], { from: piGov }); + expectEvent(res, 'SetRewardPools', { + len: '2', + rewardPools: [alice, bob], + }); + }); + + it('should deny setting an empty reward pool', async () => { + await expectRevert(venusRouter.setRewardPools([], { from: piGov }), 'AT_LEAST_ONE_EXPECTED'); + }); + + it('should deny non-owner setting a new reward pool', async () => { + await expectRevert( + venusRouter.setRewardPools([alice, bob], { from: alice }), + 'Ownable: caller is not the owner', + ); + }); + }); + + describe('setPvpFee()', () => { + it('should allow the owner setting a new pvpFee', async () => { + const res = await venusRouter.setPvpFee(ether('0.1'), { from: piGov }); + expectEvent(res, 'SetPvpFee', { + pvpFee: ether('0.1'), + }); + }); + + it('should deny setting a fee greater or equal 100%', async () => { + await expectRevert(venusRouter.setPvpFee(ether('1'), { from: piGov }), 'PVP_FEE_OVER_THE_LIMIT'); + }); + + it('should deny non-owner setting a new pvpFee', async () => { + await expectRevert(venusRouter.setPvpFee(ether('0'), { from: alice }), 'Ownable: caller is not the owner'); + }); + }); + }); + + describe('viewers', () => { + it('should return the same amount for getPiEquivalentForUnderlying()', async () => { + assert.equal(await venusRouter.getPiEquivalentForUnderlying(123, alice, 789), 123); + }); + + it('should return the same amount for getUnderlyingEquivalentForPi()', async () => { + assert.equal(await venusRouter.getUnderlyingEquivalentForPi(123, alice, 789), 123); + }); + + it('should return the same amount for getPiEquivalentForUnderlyingPure()', async () => { + assert.equal(await venusRouter.getPiEquivalentForUnderlyingPure(123, 456, 789), 123); + }); + + it('should return the same amount for getUnderlyingEquivalentForPiPure()', async () => { + assert.equal(await venusRouter.getUnderlyingEquivalentForPiPure(123, 456, 789), 123); + }); + }); + + describe('reserve management', () => { + beforeEach(async () => { + await usdc.transfer(alice, ether(100000)); + await usdc.approve(piUsdc.address, ether(10000), { from: alice }); + await piUsdc.deposit(ether(10000), { from: alice }); + + await venusRouter.poke(false); + + assert.equal(await usdc.balanceOf(vUsdc.address), ether(50000)); + assert.equal(await usdc.balanceOf(piUsdc.address), ether(2000)); + }); + + describe('non-modified vToken ratio', () => { + it('should increase reserve on deposit', async () => { + assert.equal(await piUsdc.balanceOf(alice), ether(10000)); + await usdc.approve(piUsdc.address, ether(1000), { from: alice }); + await piUsdc.deposit(ether(1000), { from: alice }); + + await venusRouter.poke(false, { from: bob }); + + assert.equal(await piUsdc.balanceOf(alice), ether(11000)); + assert.equal(await usdc.balanceOf(vUsdc.address), ether(50800)); + assert.equal(await vUsdc.balanceOf(piUsdc.address), ether(8800)); + assert.equal(await usdc.balanceOf(piUsdc.address), ether(2200)); + }); + + it('should decrease reserve on withdrawal', async () => { + assert.equal(await piUsdc.balanceOf(alice), ether(10000)); + + await piUsdc.withdraw(ether(1000), { from: alice }); + + await venusRouter.poke(false, { from: bob }); + + assert.equal(await piUsdc.balanceOf(alice), ether(9000)); + assert.equal(await usdc.balanceOf(vUsdc.address), ether(49200)); + assert.equal(await vUsdc.balanceOf(piUsdc.address), ether(7200)); + assert.equal(await usdc.balanceOf(piUsdc.address), ether(1800)); + }); + }); + + describe('modified vToken ratio', () => { + beforeEach(async () => { + assert.equal(await piUsdc.balanceOf(alice), ether(10000)); + assert.equal(await usdc.balanceOf(vUsdc.address), ether(50000)); + assert.equal(await vUsdc.balanceOf(piUsdc.address), ether(8000)); + assert.equal(await usdc.balanceOf(piUsdc.address), ether(2000)); + assert.equal(await venusRouter.getTokenForVToken(ether(3160)), ether(3160)); + + await time.advanceBlock(1000); + await usdc.transfer(vUsdc.address, ether(30000)); + await time.advanceBlock(1000); + await time.increase(time.duration.years(2)); + await vUsdc.accrueInterest(); + + assert.equal(await piUsdc.balanceOf(alice), ether(10000)); + assert.equal(await usdc.balanceOf(vUsdc.address), ether(80000)); + assert.equal(await vUsdc.balanceOf(piUsdc.address), ether(8000)); + assert.equal(await usdc.balanceOf(piUsdc.address), ether(2000)); + assert.equal(await venusRouter.getUnderlyingStaked(), ether(8000)); + assert.equal(await venusRouter.getTokenForVToken(ether(2000)), ether(3200)); + assert.equal(await venusRouter.getUnderlyingBackedByVToken(), ether(12800)); + }); + + it('should mint a smaller amount of vToken', async () => { + await usdc.approve(piUsdc.address, ether(1000), { from: alice }); + await piUsdc.deposit(ether(1000), { from: alice }); + + await venusRouter.poke(false, { from: bob }); + + assert.equal(await piUsdc.balanceOf(alice), ether(11000)); + assert.equal(await usdc.balanceOf(vUsdc.address), ether(80800)); + assert.equal(await vUsdc.balanceOf(piUsdc.address), ether(8500)); + assert.equal(await usdc.balanceOf(piUsdc.address), ether(2200)); + assert.equal(await venusRouter.getUnderlyingStaked(), ether(8800)); + assert.equal(await venusRouter.getUnderlyingBackedByVToken(), ether(13600)); + assert.equal(await venusRouter.getPendingInterestReward(), addBN(ether(4800), '1')); + assert.equal(await venusRouter.getTokenForVToken(ether(3160)), ether(5056)); + }); + + it('should decrease reserve on withdrawal', async () => { + await piUsdc.withdraw(ether(1000), { from: alice }); + + await venusRouter.poke(false, { from: bob }); + + assert.equal(await piUsdc.balanceOf(alice), ether(9000)); + assert.equal(await usdc.balanceOf(vUsdc.address), ether(79200)); + assert.equal(await vUsdc.balanceOf(piUsdc.address), ether(7500)); + assert.equal(await usdc.balanceOf(piUsdc.address), ether(1800)); + assert.equal(await venusRouter.getUnderlyingStaked(), ether(7200)); + assert.equal(await venusRouter.getUnderlyingBackedByVToken(), ether(12000)); + assert.equal(await venusRouter.getPendingInterestReward(), addBN(ether(4800), '1')); + assert.equal(await venusRouter.getTokenForVToken(ether(3160)), ether(5056)); + }); + }); + + it('should revert rebalancing if the staking address is 0', async () => { + await venusRouter.redeem(ether(8000), { from: piGov }); + await venusRouter.setVotingAndStaking(vUsdc.address, constants.ZERO_ADDRESS, { from: piGov }); + + assert.equal(await usdc.balanceOf(vUsdc.address), ether(42000)); + assert.equal(await usdc.balanceOf(piUsdc.address), ether(10000)); + assert.equal(await piUsdc.balanceOf(alice), ether(10000)); + assert.equal(await piUsdc.totalSupply(), ether(10000)); + + await piUsdc.withdraw(ether(1000), { from: alice }); + + await expectRevert(venusRouter.poke(false, { from: bob }), 'STAKING_IS_NULL'); + + assert.equal(await usdc.balanceOf(vUsdc.address), ether(42000)); + assert.equal(await vUsdc.balanceOf(piUsdc.address), ether(0)); + assert.equal(await usdc.balanceOf(piUsdc.address), ether(9000)); + }); + + describe('when interval enabled', () => { + beforeEach(async () => { + await venusRouter.setReserveConfig(ether('0.2'), time.duration.hours(1), { from: piGov }); + await poke.setMinMaxReportIntervals(time.duration.hours(1), time.duration.hours(2)); + await venusRouter.poke(false, { from: bob }); + }); + + it('should DO rebalance on deposit if the rebalancing interval has passed', async () => { + await time.increase(time.duration.minutes(61)); + + await usdc.approve(piUsdc.address, ether(1000), { from: alice }); + await piUsdc.deposit(ether(1000), { from: alice }); + await venusRouter.pokeFromReporter('0', false, '0x', { from: bob }); + + assert.equal(await usdc.balanceOf(vUsdc.address), ether(50800)); + assert.equal(await vUsdc.balanceOf(piUsdc.address), ether(8800)); + assert.equal(await usdc.balanceOf(piUsdc.address), ether(2200)); + }); + + it('should DO rebalance on withdrawal if the rebalancing interval has passed', async () => { + await time.increase(time.duration.minutes(61)); + + await piUsdc.withdraw(ether(1000), { from: alice }); + await venusRouter.pokeFromReporter('0', false, '0x', { from: bob }); + + assert.equal(await usdc.balanceOf(vUsdc.address), ether(49200)); + assert.equal(await vUsdc.balanceOf(piUsdc.address), ether(7200)); + assert.equal(await usdc.balanceOf(piUsdc.address), ether(1800)); + }); + + it("should NOT rebalance if the rebalancing interval hasn't passed", async () => { + await time.increase(time.duration.minutes(59)); + + await usdc.approve(piUsdc.address, ether(1000), { from: alice }); + await piUsdc.deposit(ether(1000), { from: alice }); + + assert.equal(await venusRouter.getReserveStatusForStakedBalance().then(s => s.forceRebalance), false); + await expectRevert(venusRouter.pokeFromReporter('0', false, '0x', { from: bob }), 'MIN_INTERVAL_NOT_REACHED'); + + await time.increase(60); + + await venusRouter.pokeFromReporter('0', false, '0x', { from: bob }); + }); + + it('should rebalance if the rebalancing interval not passed but reserveRatioToForceRebalance has reached', async () => { + await time.increase(time.duration.minutes(59)); + + assert.equal(await venusRouter.getReserveStatusForStakedBalance().then(s => s.forceRebalance), false); + await piUsdc.withdraw(ether(2000), { from: alice }); + assert.equal(await venusRouter.getReserveStatusForStakedBalance().then(s => s.forceRebalance), true); + await venusRouter.pokeFromReporter('0', false, '0x', { from: bob }); + + assert.equal(await usdc.balanceOf(vUsdc.address), ether(48400)); + assert.equal(await vUsdc.balanceOf(piUsdc.address), ether(6400)); + assert.equal(await usdc.balanceOf(piUsdc.address), ether(1600)); + }); + }); + + describe('on poke', async () => { + it('should do nothing when nothing has changed', async () => { + await venusRouter.poke(false, { from: bob }); + + assert.equal(await usdc.balanceOf(vUsdc.address), ether(50000)); + assert.equal(await vUsdc.balanceOf(piUsdc.address), ether(8000)); + assert.equal(await usdc.balanceOf(piUsdc.address), ether(2000)); + }); + + it('should increase reserve if required', async () => { + await usdc.transfer(piUsdc.address, ether(1000), { from: alice }); + + assert.equal(await usdc.balanceOf(vUsdc.address), ether(50000)); + assert.equal(await vUsdc.balanceOf(piUsdc.address), ether(8000)); + assert.equal(await usdc.balanceOf(piUsdc.address), ether(3000)); + assert.equal(await piUsdc.totalSupply(), ether(10000)); + assert.equal(await venusRouter.getUnderlyingStaked(), ether(7000)); + assert.equal(await venusRouter.getUnderlyingBackedByVToken(), ether(8000)); + assert.equal(await venusRouter.getPendingInterestReward(), addBN(ether(1000), '1')); + + await venusRouter.poke(false, { from: bob }); + + assert.equal(await usdc.balanceOf(vUsdc.address), ether(51000)); + assert.equal(await vUsdc.balanceOf(piUsdc.address), ether(9000)); + assert.equal(await usdc.balanceOf(piUsdc.address), ether(2000)); + assert.equal(await piUsdc.totalSupply(), ether(10000)); + assert.equal(await venusRouter.getUnderlyingStaked(), ether(8000)); + assert.equal(await venusRouter.getUnderlyingBackedByVToken(), ether(9000)); + assert.equal(await venusRouter.getPendingInterestReward(), addBN(ether(1000), '1')); + }); + }); + + it('should stake all the underlying tokens with 0 RR', async () => { + await venusRouter.setReserveConfig(ether(0), 0, { from: piGov }); + + await venusRouter.poke(false, { from: bob }); + assert.equal(await usdc.balanceOf(vUsdc.address), ether(52000)); + assert.equal(await usdc.balanceOf(piUsdc.address), ether(0)); + }); + + it('should keep all the underlying tokens on piToken with 1 RR', async () => { + await venusRouter.setReserveConfig(ether(1), 0, { from: piGov }); + + await venusRouter.poke(false, { from: bob }); + assert.equal(await usdc.balanceOf(vUsdc.address), ether(42000)); + assert.equal(await usdc.balanceOf(piUsdc.address), ether(10000)); + }); + }); + + describe('reward distribution', async () => { + let poolA, poolB, poolC, poolD; + + beforeEach(async function() { + poolA = await MockGulpingBPool.new(); + poolB = await MockGulpingBPool.new(); + poolC = await MockGulpingBPool.new(); + poolD = await MockGulpingBPool.new(); + await venusRouter.setRewardPools([poolA.address, poolB.address, poolC.address], { from: piGov }); + + await poolRestrictions.setVotingAllowedForSenders(vUsdc.address, [alice], [true]); + + await usdc.transfer(alice, ether('10000')); + await usdc.approve(piUsdc.address, ether('10000'), { from: alice }); + await piUsdc.deposit(ether('10000'), { from: alice }); + + await venusRouter.poke(false); + + assert.equal(await piUsdc.totalSupply(), ether('10000')); + assert.equal(await piUsdc.balanceOf(alice), ether('10000')); + assert.equal(await vUsdc.totalSupply(), ether(50000)); + assert.equal(await usdc.balanceOf(vUsdc.address), ether(50000)); + + await piUsdc.transfer(poolA.address, 10, { from: alice }); + await piUsdc.transfer(poolB.address, 20, { from: alice }); + }); + + it('should allow withdrawing interest rewards from a vToken only', async () => { + await usdc.transfer(vUsdc.address, ether(2000)); + await vUsdc.accrueInterest(); + + assert.equal(await vUsdc.totalSupply(), ether(50000)); + assert.equal(await usdc.balanceOf(vUsdc.address), ether(52000)); + + assert.equal(await usdc.balanceOf(piUsdc.address), ether(2000)); + assert.equal(await venusRouter.getUnderlyingStaked(), ether(8000)); + assert.equal(await venusRouter.getUnderlyingBackedByVToken(), ether(8320)); + assert.equal(await venusRouter.getPendingInterestReward(), addBN(ether(320), '1')); + assert.equal(await venusRouter.getVTokenForToken(ether(320)), '307692307692307692307'); + + let res = await venusRouter.poke(true, { from: bob }); + expectEvent(res, 'ClaimRewards', { + sender: bob, + xvsEarned: ether(0), + underlyingEarned: addBN(ether(320), '1'), + }); + + expectEvent(res, 'DistributeUnderlyingReward', { + sender: bob, + underlyingReward: ether('320.000000000000000001'), + pvpReward: ether(48), + poolRewardsUnderlying: ether('272.000000000000000001'), + poolRewardsPi: ether('272.000000000000000001'), + pools: [poolA.address, poolB.address, poolC.address], + }); + + assert.equal(await usdc.balanceOf(piUsdc.address), addBN(ether(2000), ether('272.000000000000000001'))); + assert.equal(await usdc.balanceOf(venusRouter.address), '0'); + + assert.isTrue(parseInt(res.logs[3].args.poolRewardsUnderlying) > 1); + assert.isTrue(parseInt(res.logs[3].args.poolRewardsPi.length) > 1); + + await expectEvent.inTransaction(res.tx, poolA, 'Gulp'); + await expectEvent.inTransaction(res.tx, poolB, 'Gulp'); + await expectEvent.notEmitted.inTransaction(res.tx, poolC, 'Gulp'); + await expectEvent.notEmitted.inTransaction(res.tx, poolD, 'Gulp'); + + assert.equal(res.logs.length, 4); + assert.equal(res.logs[1].args.pool, poolA.address); + assert.equal(res.logs[1].args.amount, '90666666666666666667'); + assert.equal(res.logs[2].args.pool, poolB.address); + assert.equal(res.logs[2].args.amount, '181333333333333333334'); + + assert.equal(await piUsdc.balanceOf(poolA.address), 90666666666666666666 + 10); + assert.equal(await piUsdc.balanceOf(poolB.address), 181333333333333333333 + 20); + assert.equal(await piUsdc.balanceOf(poolC.address), '0'); + assert.equal(await piUsdc.balanceOf(poolD.address), '0'); + + assert.equal(await usdc.balanceOf(venusRouter.address), '0'); + }); + + it.skip('should keep XVS on the contract in the case with the UNDERLYING is different', async () => { + assert.equal(await piUsdc.balanceOf(poolA.address), 10); + assert.equal(await piUsdc.balanceOf(poolB.address), 20); + + await vUsdc.borrow(ether(21000), { from: charlie }); + + await xvs.transfer(trollerV4.address, ether(100000000)); + await time.advanceBlock(200); + + assert.equal(await vUsdc.totalSupply(), ether(50000)); + assert.equal(await usdc.balanceOf(vUsdc.address), ether(29000)); + + assert.equal(await usdc.balanceOf(piUsdc.address), ether(2000)); + assert.equal(await venusRouter.getUnderlyingStaked(), ether(8000)); + assert.equal(await venusRouter.getUnderlyingBackedByVToken(), ether(8000)); + assert.equal(await venusRouter.getPendingInterestReward(), ether(0)); + assert.equal(await venusRouter.getVTokenForToken(ether(320)), ether(320)); + + let res = await venusRouter.poke(true, { from: bob }); + expectEvent(res, 'ClaimRewards', { + sender: bob, + xvsEarned: ether(288000), + }); + + expectEvent(res, 'DistributeUnderlyingReward', { + sender: bob, + underlyingReward: ether('0.036246575342456001'), + pvpReward: ether('0.005436986301368400'), + poolRewardsUnderlying: ether('0.030809589041087601'), + poolRewardsPi: ether('0.030809589041087601'), + pools: [poolA.address, poolB.address, poolC.address], + }); + + assert.equal(await usdc.balanceOf(piUsdc.address), addBN(ether(2000), ether('0.030809589041087601'))); + assert.equal(await usdc.balanceOf(venusRouter.address), '0'); + assert.equal(await xvs.balanceOf(venusRouter.address), ether('288000')); + + assert.isTrue(parseInt(res.logs[3].args.poolRewardsUnderlying) > 1); + assert.isTrue(parseInt(res.logs[3].args.poolRewardsPi.length) > 1); + + await expectEvent.inTransaction(res.tx, poolA, 'Gulp'); + await expectEvent.inTransaction(res.tx, poolB, 'Gulp'); + await expectEvent.notEmitted.inTransaction(res.tx, poolC, 'Gulp'); + await expectEvent.notEmitted.inTransaction(res.tx, poolD, 'Gulp'); + + assert.equal(res.logs.length, 4); + assert.equal(res.logs[1].args.pool, poolA.address); + assert.equal(res.logs[1].args.amount, '10269863013695867'); + assert.equal(res.logs[2].args.pool, poolB.address); + assert.equal(res.logs[2].args.amount, '20539726027391734'); + + assert.equal(await piUsdc.balanceOf(poolA.address), '10269863013695877'); + assert.equal(await piUsdc.balanceOf(poolB.address), ether('0.020539726027391754')); + assert.equal(await piUsdc.balanceOf(poolC.address), '0'); + assert.equal(await piUsdc.balanceOf(poolD.address), '0'); + + assert.equal(await usdc.balanceOf(venusRouter.address), '0'); + assert.equal(await usdc.balanceOf(venusRouter.address), '0'); + }); + + it('should revert poke if there is no reward available', async () => { + await expectRevert(venusRouter.poke(true, { from: alice }), 'NOTHING_TO_DISTRIBUTE'); + }); + + it('should revert distributing rewards when missing reward pools config', async () => { + poke = await MockPoke.new(true); + const router = await VenusVBep20SupplyRouter.new( + piUsdc.address, + buildBasicRouterConfig( + poolRestrictions.address, + poke.address, + vUsdc.address, + vUsdc.address, + ether('0.2'), + ether('0.02'), + '0', + pvp, + ether('0.2'), + [], + ), + buildVenusRouterConfig(trollerV4.address, usdc.address), + ); + await venusRouter.migrateToNewRouter(piUsdc.address, router.address, [usdc.address, piUsdc.address], { + from: piGov, + }); + await usdc.transfer(vUsdc.address, ether(2000)); + await time.increase(1); + await expectRevert(router.poke(true, { from: bob }), 'MISSING_REWARD_POOLS'); + }); + }); +}); From a224f8da2a7e36fbe628074da91fe682c6763335 Mon Sep 17 00:00:00 2001 From: Poli Paul Date: Thu, 19 Aug 2021 10:53:43 +0200 Subject: [PATCH 12/33] Fix tests --- test/router/implementations/AaveRouter.unit.js | 2 +- test/router/implementations/SushiRouter.unit.js | 2 +- test/router/implementations/YearnRouter.test.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/router/implementations/AaveRouter.unit.js b/test/router/implementations/AaveRouter.unit.js index cd5a264b..90a714c8 100644 --- a/test/router/implementations/AaveRouter.unit.js +++ b/test/router/implementations/AaveRouter.unit.js @@ -391,7 +391,7 @@ describe('AaveRouter Tests', () => { assert.equal(await piAave.balanceOf(alice), ether(10000)); assert.equal(await piAave.totalSupply(), ether(10000)); - await expectRevert(aaveRouter.poke(false), 'call to a non-contract account'); + await expectRevert(aaveRouter.poke(false), 'STAKING_IS_NULL'); }); describe('when interval enabled', () => { diff --git a/test/router/implementations/SushiRouter.unit.js b/test/router/implementations/SushiRouter.unit.js index 67da1f49..70aad525 100644 --- a/test/router/implementations/SushiRouter.unit.js +++ b/test/router/implementations/SushiRouter.unit.js @@ -287,7 +287,7 @@ describe('SushiRouter Tests', () => { await piSushi.withdraw(ether(1000), { from: alice }); - await expectRevert(sushiRouter.poke(false, { from: bob }), 'STACKING_IS_NULL'); + await expectRevert(sushiRouter.poke(false, { from: bob }), 'STAKING_IS_NULL'); assert.equal(await sushi.balanceOf(xSushi.address), ether(42000)); assert.equal(await xSushi.balanceOf(piSushi.address), ether(0)); diff --git a/test/router/implementations/YearnRouter.test.js b/test/router/implementations/YearnRouter.test.js index da03e7d0..82115250 100644 --- a/test/router/implementations/YearnRouter.test.js +++ b/test/router/implementations/YearnRouter.test.js @@ -349,7 +349,7 @@ describe('YearnRouter Tests', () => { assert.equal(await piYfi.balanceOf(alice), ether(10000)); assert.equal(await piYfi.totalSupply(), ether(10000)); await piYfi.withdraw(ether(1000), { from: alice }); - await expectRevert(yfiRouter.poke(false), 'STACKING_IS_NULL'); + await expectRevert(yfiRouter.poke(false), 'STAKING_IS_NULL'); }); describe('when interval enabled', () => { From 7afd017138afc06e433a88b0a406612bcd0445ab Mon Sep 17 00:00:00 2001 From: Poli Paul Date: Thu, 19 Aug 2021 17:18:45 +0200 Subject: [PATCH 13/33] Make some router functions external --- contracts/powerindex-router/PowerIndexBasicRouter.sol | 8 ++++---- .../implementations/AutoPowerIndexRouter.sol | 4 ++-- .../implementations/BakeryChefPowerIndexRouter.sol | 2 +- .../implementations/MasterChefPowerIndexRouter.sol | 2 +- .../implementations/PancakeMasterChefPowerIndexRouter.sol | 2 +- .../implementations/SushiPowerIndexRouter.sol | 4 ++-- .../implementations/VenusVBep20SupplyRouter.sol | 6 +++--- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/contracts/powerindex-router/PowerIndexBasicRouter.sol b/contracts/powerindex-router/PowerIndexBasicRouter.sol index 1e129458..9cb467d3 100644 --- a/contracts/powerindex-router/PowerIndexBasicRouter.sol +++ b/contracts/powerindex-router/PowerIndexBasicRouter.sol @@ -116,7 +116,7 @@ contract PowerIndexBasicRouter is PowerIndexBasicRouterInterface, PowerIndexNaiv emit SetVotingAndStaking(_voting, _staking); } - function setReserveConfig(uint256 _reserveRatio, uint256 _claimRewardsInterval) public virtual override onlyOwner { + function setReserveConfig(uint256 _reserveRatio, uint256 _claimRewardsInterval) external virtual override onlyOwner { require(_reserveRatio <= HUNDRED_PCT, "RR_GREATER_THAN_100_PCT"); reserveRatio = _reserveRatio; claimRewardsInterval = _claimRewardsInterval; @@ -286,7 +286,7 @@ contract PowerIndexBasicRouter is PowerIndexBasicRouterInterface, PowerIndexNaiv * @dev Getting status and diff of actual staked balance and target reserve balance. */ function getReserveStatusForStakedBalance() - public + external view returns ( ReserveStatus status, @@ -343,7 +343,7 @@ contract PowerIndexBasicRouter is PowerIndexBasicRouterInterface, PowerIndexNaiv uint256 _underlyingAmount, IERC20 _underlyingToken, uint256 _piTotalSupply - ) public view virtual override returns (uint256) { + ) external view virtual override returns (uint256) { uint256 underlyingOnPiToken = _underlyingToken.balanceOf(address(piToken)); return getPiEquivalentForUnderlyingPure( @@ -370,7 +370,7 @@ contract PowerIndexBasicRouter is PowerIndexBasicRouterInterface, PowerIndexNaiv uint256 _piAmount, IERC20 _underlyingToken, uint256 _piTotalSupply - ) public view virtual override returns (uint256) { + ) external view virtual override returns (uint256) { uint256 underlyingOnPiToken = _underlyingToken.balanceOf(address(piToken)); return getUnderlyingEquivalentForPiPure( diff --git a/contracts/powerindex-router/implementations/AutoPowerIndexRouter.sol b/contracts/powerindex-router/implementations/AutoPowerIndexRouter.sol index 66bdf6f8..5f0584a8 100644 --- a/contracts/powerindex-router/implementations/AutoPowerIndexRouter.sol +++ b/contracts/powerindex-router/implementations/AutoPowerIndexRouter.sol @@ -123,7 +123,7 @@ contract AutoPowerIndexRouter is PowerIndexBasicRouter { uint256 _underlyingAmount, IERC20, /* _underlyingToken */ uint256 /* _piTotalSupply */ - ) public view override returns (uint256) { + ) external view override returns (uint256) { return _underlyingAmount; } @@ -139,7 +139,7 @@ contract AutoPowerIndexRouter is PowerIndexBasicRouter { uint256 _piAmount, IERC20, /* _underlyingToken */ uint256 /* _piTotalSupply */ - ) public view override returns (uint256) { + ) external view override returns (uint256) { return _piAmount; } diff --git a/contracts/powerindex-router/implementations/BakeryChefPowerIndexRouter.sol b/contracts/powerindex-router/implementations/BakeryChefPowerIndexRouter.sol index 98b82695..55abf446 100644 --- a/contracts/powerindex-router/implementations/BakeryChefPowerIndexRouter.sol +++ b/contracts/powerindex-router/implementations/BakeryChefPowerIndexRouter.sol @@ -25,7 +25,7 @@ contract BakeryChefPowerIndexRouter is AbstractMasterChefIndexRouter { /*** VIEWERS ***/ - function getPendingRewards() public view returns (uint256 amount) { + function getPendingRewards() external view returns (uint256 amount) { return IBakeryMasterChef(staking).pendingBake(address(TOKEN), address(piToken)); } diff --git a/contracts/powerindex-router/implementations/MasterChefPowerIndexRouter.sol b/contracts/powerindex-router/implementations/MasterChefPowerIndexRouter.sol index 2a5c24ea..da035077 100644 --- a/contracts/powerindex-router/implementations/MasterChefPowerIndexRouter.sol +++ b/contracts/powerindex-router/implementations/MasterChefPowerIndexRouter.sol @@ -31,7 +31,7 @@ contract MasterChefPowerIndexRouter is AbstractMasterChefIndexRouter { /*** VIEWERS ***/ - function getPendingRewards() public view returns (uint256 amount) { + function getPendingRewards() external view returns (uint256 amount) { return IMasterChefV1(staking).pending(MASTER_CHEF_PID, address(piToken)); } diff --git a/contracts/powerindex-router/implementations/PancakeMasterChefPowerIndexRouter.sol b/contracts/powerindex-router/implementations/PancakeMasterChefPowerIndexRouter.sol index cbb1fbdf..4a100de0 100644 --- a/contracts/powerindex-router/implementations/PancakeMasterChefPowerIndexRouter.sol +++ b/contracts/powerindex-router/implementations/PancakeMasterChefPowerIndexRouter.sol @@ -24,7 +24,7 @@ contract PancakeMasterChefIndexRouter is AbstractMasterChefIndexRouter { /*** VIEWERS ***/ - function getPendingRewards() public view returns (uint256 amount) { + function getPendingRewards() external view returns (uint256 amount) { return IPancakeMasterChef(staking).pendingCake(0, address(piToken)); } diff --git a/contracts/powerindex-router/implementations/SushiPowerIndexRouter.sol b/contracts/powerindex-router/implementations/SushiPowerIndexRouter.sol index 933babba..64265c2b 100644 --- a/contracts/powerindex-router/implementations/SushiPowerIndexRouter.sol +++ b/contracts/powerindex-router/implementations/SushiPowerIndexRouter.sol @@ -137,7 +137,7 @@ contract SushiPowerIndexRouter is PowerIndexBasicRouter { uint256 _underlyingAmount, IERC20, /* _underlyingToken */ uint256 /* _piTotalSupply */ - ) public view override returns (uint256) { + ) external view override returns (uint256) { return _underlyingAmount; } @@ -153,7 +153,7 @@ contract SushiPowerIndexRouter is PowerIndexBasicRouter { uint256 _piAmount, IERC20, /* _underlyingToken */ uint256 /* _piTotalSupply */ - ) public view override returns (uint256) { + ) external view override returns (uint256) { return _piAmount; } diff --git a/contracts/powerindex-router/implementations/VenusVBep20SupplyRouter.sol b/contracts/powerindex-router/implementations/VenusVBep20SupplyRouter.sol index 7ac7bcb1..ea09b4ed 100644 --- a/contracts/powerindex-router/implementations/VenusVBep20SupplyRouter.sol +++ b/contracts/powerindex-router/implementations/VenusVBep20SupplyRouter.sol @@ -164,7 +164,7 @@ contract VenusVBep20SupplyRouter is PowerIndexBasicRouter { * @param _tokenAmount The input amount of underlying tokens * @return The corresponding amount of vTokens tokens */ - function getVTokenForToken(uint256 _tokenAmount) public view returns (uint256) { + function getVTokenForToken(uint256 _tokenAmount) external view returns (uint256) { // token / exchangeRate return _tokenAmount.mul(1e18) / VBep20Interface(staking).exchangeRateStored(); } @@ -218,7 +218,7 @@ contract VenusVBep20SupplyRouter is PowerIndexBasicRouter { uint256 _underlyingAmount, IERC20, /* _underlyingToken */ uint256 /* _piTotalSupply */ - ) public view override returns (uint256) { + ) external view override returns (uint256) { return _underlyingAmount; } @@ -234,7 +234,7 @@ contract VenusVBep20SupplyRouter is PowerIndexBasicRouter { uint256 _piAmount, IERC20, /* _underlyingToken */ uint256 /* _piTotalSupply */ - ) public view override returns (uint256) { + ) external view override returns (uint256) { return _piAmount; } From 60fcaeb55747e90c2d11f03e201c962b9dfe1f34 Mon Sep 17 00:00:00 2001 From: Poli Paul Date: Thu, 19 Aug 2021 17:21:53 +0200 Subject: [PATCH 14/33] Update router compatibility comments --- .../implementations/AutoPowerIndexRouter.sol | 5 +++++ .../implementations/MasterChefPowerIndexRouter.sol | 2 -- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/contracts/powerindex-router/implementations/AutoPowerIndexRouter.sol b/contracts/powerindex-router/implementations/AutoPowerIndexRouter.sol index 5f0584a8..eefbf438 100644 --- a/contracts/powerindex-router/implementations/AutoPowerIndexRouter.sol +++ b/contracts/powerindex-router/implementations/AutoPowerIndexRouter.sol @@ -7,6 +7,11 @@ import "../../interfaces/IAutoFarm.sol"; import "../../interfaces/IAutoFarmStrategy.sol"; import "../PowerIndexBasicRouter.sol"; +/** + * Compatible with: + * - Auto: https://bscscan.com/address/0x763a05bdb9f8946d8c3fa72d1e0d3f5e68647e5c, + * pending rewards via stakedWantTokens(pid, user) + */ contract AutoPowerIndexRouter is PowerIndexBasicRouter { event Stake(address indexed sender, uint256 amount); event Redeem(address indexed sender, uint256 amount); diff --git a/contracts/powerindex-router/implementations/MasterChefPowerIndexRouter.sol b/contracts/powerindex-router/implementations/MasterChefPowerIndexRouter.sol index da035077..e9a8e45b 100644 --- a/contracts/powerindex-router/implementations/MasterChefPowerIndexRouter.sol +++ b/contracts/powerindex-router/implementations/MasterChefPowerIndexRouter.sol @@ -10,8 +10,6 @@ import "./AbstractMasterChefIndexRouter.sol"; * Compatible with: * - MDEX: https://bscscan.com/address/0x6aee12e5eb987b3be1ba8e621be7c4804925ba68, * pending rewards via pending(pid, user) - * - Auto: https://bscscan.com/address/0x763a05bdb9f8946d8c3fa72d1e0d3f5e68647e5c, - * pending rewards via stakedWantTokens(pid, user) */ contract MasterChefPowerIndexRouter is AbstractMasterChefIndexRouter { uint256 internal immutable MASTER_CHEF_PID; From c7ff5b311b02cb22ca77fac681d92975b7da2c2b Mon Sep 17 00:00:00 2001 From: Poli Paul Date: Thu, 19 Aug 2021 17:35:56 +0200 Subject: [PATCH 15/33] Fix some compiler warnings --- contracts/test/bsc/MockPancakeMasterChef.sol | 2 +- contracts/test/bsc/MockPancakeRouter.sol | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/contracts/test/bsc/MockPancakeMasterChef.sol b/contracts/test/bsc/MockPancakeMasterChef.sol index 44061059..0702dcd3 100644 --- a/contracts/test/bsc/MockPancakeMasterChef.sol +++ b/contracts/test/bsc/MockPancakeMasterChef.sol @@ -25,7 +25,7 @@ contract MockPancakeMasterChef { function leaveStaking(uint256) external {} - function userInfo(uint256, address) external view returns (uint256 amount, uint256 rewardDebt) { + function userInfo(uint256, address) external pure returns (uint256 amount, uint256 rewardDebt) { return (0, 0); } } diff --git a/contracts/test/bsc/MockPancakeRouter.sol b/contracts/test/bsc/MockPancakeRouter.sol index 9fc4ad3e..68f722bc 100644 --- a/contracts/test/bsc/MockPancakeRouter.sol +++ b/contracts/test/bsc/MockPancakeRouter.sol @@ -1,5 +1,12 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.6.12; + contract MockPancakeRouter { - function getAmountsOut(uint256 amountIn, address[] calldata path) external view returns (uint256[] memory amounts) { + function getAmountsOut( + uint256, /*amountIn*/ + address[] calldata path + ) external pure returns (uint256[] memory amounts) { amounts = new uint256[](path.length); } From edcfd23ec3c77ddbf61fd00c7a630531643d58d6 Mon Sep 17 00:00:00 2001 From: Poli Paul Date: Wed, 15 Sep 2021 18:21:34 +0200 Subject: [PATCH 16/33] Introduce router lower/upper reserve ratio bounds --- .../PowerIndexBasicRouterInterface.sol | 7 ++- .../PowerIndexBasicRouter.sol | 49 +++++++++++---- test/helpers/builders.js | 5 +- .../implementations/AaveRouter.stories.js | 1 + .../router/implementations/AaveRouter.unit.js | 14 +++-- .../router/implementations/AutoRouter.unit.js | 12 ++-- .../BakeryMasterChefRouter.unit.js | 12 ++-- .../MDXMasterChefRouter.unit.js | 12 ++-- .../PancakeMasterChefRouter.unit.js | 12 ++-- .../implementations/SushiRouter.stories.js | 11 ++-- .../implementations/SushiRouter.unit.js | 60 ++++++++++++++----- .../implementations/VenusRouter.unit.js | 8 ++- .../implementations/YearnRouter.test.js | 9 ++- 13 files changed, 149 insertions(+), 63 deletions(-) diff --git a/contracts/interfaces/PowerIndexBasicRouterInterface.sol b/contracts/interfaces/PowerIndexBasicRouterInterface.sol index 792fd4ae..6e0e7de1 100644 --- a/contracts/interfaces/PowerIndexBasicRouterInterface.sol +++ b/contracts/interfaces/PowerIndexBasicRouterInterface.sol @@ -7,7 +7,12 @@ import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; interface PowerIndexBasicRouterInterface { function setVotingAndStaking(address _voting, address _staking) external; - function setReserveConfig(uint256 _reserveRatio, uint256 _claimRewardsInterval) external; + function setReserveConfig( + uint256 _reserveRatio, + uint256 _reserveRatioLowerBound, + uint256 _reserveRatioUpperBound, + uint256 _claimRewardsInterval + ) external; function getPiEquivalentForUnderlying( uint256 _underlyingAmount, diff --git a/contracts/powerindex-router/PowerIndexBasicRouter.sol b/contracts/powerindex-router/PowerIndexBasicRouter.sol index 9cb467d3..af780a38 100644 --- a/contracts/powerindex-router/PowerIndexBasicRouter.sol +++ b/contracts/powerindex-router/PowerIndexBasicRouter.sol @@ -17,7 +17,7 @@ contract PowerIndexBasicRouter is PowerIndexBasicRouterInterface, PowerIndexNaiv uint256 public constant HUNDRED_PCT = 1 ether; event SetVotingAndStaking(address indexed voting, address indexed staking); - event SetReserveConfig(uint256 ratio, uint256 claimRewardsInterval); + event SetReserveConfig(uint256 ratio, uint256 ratioLowerBound, uint256 ratioUpperBound, uint256 claimRewardsInterval); event SetRebalancingInterval(uint256 rebalancingInterval); event IgnoreRebalancing(uint256 blockTimestamp, uint256 lastRebalancedAt, uint256 rebalancingInterval); event RewardPool(address indexed pool, uint256 amount); @@ -32,7 +32,8 @@ contract PowerIndexBasicRouter is PowerIndexBasicRouterInterface, PowerIndexNaiv address voting; address staking; uint256 reserveRatio; - uint256 reserveRatioToForceRebalance; + uint256 reserveRatioLowerBound; + uint256 reserveRatioUpperBound; uint256 claimRewardsInterval; address pvp; uint256 pvpFee; @@ -50,7 +51,8 @@ contract PowerIndexBasicRouter is PowerIndexBasicRouterInterface, PowerIndexNaiv uint256 public claimRewardsInterval; uint256 public lastClaimRewardsAt; uint256 public lastRebalancedAt; - uint256 public reserveRatioToForceRebalance; + uint256 public reserveRatioLowerBound; + uint256 public reserveRatioUpperBound; // 1 ether == 100% uint256 public pvpFee; @@ -84,7 +86,9 @@ contract PowerIndexBasicRouter is PowerIndexBasicRouterInterface, PowerIndexNaiv constructor(address _piToken, BasicConfig memory _basicConfig) public PowerIndexNaiveRouter() Ownable() { require(_piToken != address(0), "INVALID_PI_TOKEN"); - require(_basicConfig.reserveRatio <= HUNDRED_PCT, "RR_GT_HUNDRED_PCT"); + require(_basicConfig.reserveRatioUpperBound <= HUNDRED_PCT, "RR_GT_HUNDRED_PCT"); + require(_basicConfig.reserveRatio >= _basicConfig.reserveRatioLowerBound, "RR_LTE_LOWER_RR"); + require(_basicConfig.reserveRatio <= _basicConfig.reserveRatioUpperBound, "RR_GTE_UPPER_RR"); require(_basicConfig.pvpFee < HUNDRED_PCT, "PVP_FEE_GTE_HUNDRED_PCT"); require(_basicConfig.pvp != address(0), "INVALID_PVP_ADDR"); require(_basicConfig.poolRestrictions != address(0), "INVALID_POOL_RESTRICTIONS_ADDR"); @@ -95,7 +99,8 @@ contract PowerIndexBasicRouter is PowerIndexBasicRouterInterface, PowerIndexNaiv voting = _basicConfig.voting; staking = _basicConfig.staking; reserveRatio = _basicConfig.reserveRatio; - reserveRatioToForceRebalance = _basicConfig.reserveRatioToForceRebalance; + reserveRatioLowerBound = _basicConfig.reserveRatioLowerBound; + reserveRatioUpperBound = _basicConfig.reserveRatioUpperBound; claimRewardsInterval = _basicConfig.claimRewardsInterval; pvp = _basicConfig.pvp; pvpFee = _basicConfig.pvpFee; @@ -116,11 +121,21 @@ contract PowerIndexBasicRouter is PowerIndexBasicRouterInterface, PowerIndexNaiv emit SetVotingAndStaking(_voting, _staking); } - function setReserveConfig(uint256 _reserveRatio, uint256 _claimRewardsInterval) external virtual override onlyOwner { - require(_reserveRatio <= HUNDRED_PCT, "RR_GREATER_THAN_100_PCT"); + function setReserveConfig( + uint256 _reserveRatio, + uint256 _reserveRatioLowerBound, + uint256 _reserveRatioUpperBound, + uint256 _claimRewardsInterval + ) external virtual override onlyOwner { + require(_reserveRatioUpperBound <= HUNDRED_PCT, "UPPER_RR_GREATER_THAN_100_PCT"); + require(_reserveRatio >= _reserveRatioLowerBound, "RR_LT_LOWER_RR"); + require(_reserveRatio <= _reserveRatioUpperBound, "RR_GT_UPPER_RR"); + reserveRatio = _reserveRatio; + reserveRatioLowerBound = _reserveRatioLowerBound; + reserveRatioUpperBound = _reserveRatioUpperBound; claimRewardsInterval = _claimRewardsInterval; - emit SetReserveConfig(_reserveRatio, _claimRewardsInterval); + emit SetReserveConfig(_reserveRatio, _reserveRatioLowerBound, _reserveRatioUpperBound, _claimRewardsInterval); } function setRewardPools(address[] calldata _rewardPools) external onlyOwner { @@ -310,16 +325,28 @@ contract PowerIndexBasicRouter is PowerIndexBasicRouterInterface, PowerIndexNaiv ) { uint256 expectedReserveAmount; + uint256 underlyingBalance = piToken.getUnderlyingBalance(); (status, diff, expectedReserveAmount) = getReserveStatusPure( reserveRatio, - piToken.getUnderlyingBalance(), + underlyingBalance, _stakedBalance, _withdrawAmount ); + if (status == ReserveStatus.EQUILIBRIUM) { + return (status, diff, forceRebalance); + } + + uint256 denominator = underlyingBalance.add(_stakedBalance).sub(_withdrawAmount); + if (status == ReserveStatus.SHORTAGE) { - uint256 currentRatio = expectedReserveAmount.sub(diff).mul(HUNDRED_PCT).div(expectedReserveAmount); - forceRebalance = reserveRatioToForceRebalance >= currentRatio; + uint256 numerator = expectedReserveAmount.sub(diff).mul(HUNDRED_PCT); + uint256 currentRatio = numerator.div(denominator); + forceRebalance = reserveRatioLowerBound >= currentRatio; + } else if (status == ReserveStatus.EXCESS) { + uint256 numerator = expectedReserveAmount.add(diff).mul(HUNDRED_PCT); + uint256 currentRatio = numerator.div(denominator); + forceRebalance = reserveRatioUpperBound <= currentRatio; } } diff --git a/test/helpers/builders.js b/test/helpers/builders.js index 89f2e35b..64a6c152 100644 --- a/test/helpers/builders.js +++ b/test/helpers/builders.js @@ -1,11 +1,12 @@ -function buildBasicRouterConfig(poolRestrictions, powerPoke, voting, staking, reserveRatio, reserveRatioToForceRebalance, claimRewardsInterval, pvp, pvpFee, rewardPools) { +function buildBasicRouterConfig(poolRestrictions, powerPoke, voting, staking, reserveRatio, reserveRatioLowerBound, reserveRatioUpperBound, claimRewardsInterval, pvp, pvpFee, rewardPools) { return { poolRestrictions, powerPoke, voting, staking, reserveRatio, - reserveRatioToForceRebalance, + reserveRatioLowerBound, + reserveRatioUpperBound, claimRewardsInterval, pvp, pvpFee, diff --git a/test/router/implementations/AaveRouter.stories.js b/test/router/implementations/AaveRouter.stories.js index c47a0169..cd2ef16e 100644 --- a/test/router/implementations/AaveRouter.stories.js +++ b/test/router/implementations/AaveRouter.stories.js @@ -63,6 +63,7 @@ describe('AaveRouter Stories', () => { stakedAave.address, ether('0.2'), ether('0.02'), + ether('0.3'), '0', stub, ether('0.2'), diff --git a/test/router/implementations/AaveRouter.unit.js b/test/router/implementations/AaveRouter.unit.js index 90a714c8..2c775f6b 100644 --- a/test/router/implementations/AaveRouter.unit.js +++ b/test/router/implementations/AaveRouter.unit.js @@ -144,6 +144,7 @@ describe('AaveRouter Tests', () => { stakedAave.address, ether('0.2'), ether('0.02'), + ether('0.3'), '0', pvp, ether('0.2'), @@ -175,6 +176,7 @@ describe('AaveRouter Tests', () => { stakedAave.address, ether('0.2'), ether('0.02'), + ether('0.3'), '172801', pvp, ether('0.2'), @@ -189,9 +191,11 @@ describe('AaveRouter Tests', () => { describe('owner methods', async () => { describe('setReserveConfig()', () => { it('should allow the owner setting a reserve config', async () => { - const res = await aaveRouter.setReserveConfig(ether('0.2'), 3600, { from: piGov }); + const res = await aaveRouter.setReserveConfig(ether('0.2'), ether('0.1'), ether('0.5'), 3600, { from: piGov }); expectEvent(res, 'SetReserveConfig', { ratio: ether('0.2'), + ratioLowerBound: ether('0.1'), + ratioUpperBound: ether('0.5'), claimRewardsInterval: '3600' }); assert.equal(await aaveRouter.reserveRatio(), ether('0.2')) @@ -199,11 +203,11 @@ describe('AaveRouter Tests', () => { }); it('should deny setting a reserve ratio greater or equal 100%', async () => { - await expectRevert(aaveRouter.setReserveConfig(ether('1.01'), 0, { from: piGov }), 'RR_GREATER_THAN_100_PCT'); + await expectRevert(aaveRouter.setReserveConfig(ether('1.01'), ether('0.3'), ether('1.01'), 0, { from: piGov }), 'UPPER_RR_GREATER_THAN_100_PCT'); }); it('should deny non-owner setting reserve config', async () => { - await expectRevert(aaveRouter.setReserveConfig(ether('0.2'), 3600, { from: alice }), 'Ownable: caller is not the owner'); + await expectRevert(aaveRouter.setReserveConfig(ether('0.2'), ether('0.1'), ether('0.3'), 3600, { from: alice }), 'Ownable: caller is not the owner'); }); }); @@ -405,7 +409,7 @@ describe('AaveRouter Tests', () => { assert.equal(await aave.balanceOf(stakedAave.address), ether(50000)); assert.equal(await aave.balanceOf(piAave.address), ether(2000)); - await aaveRouter.setReserveConfig(ether('0.2'), time.duration.hours(1), { from: piGov }); + await aaveRouter.setReserveConfig(ether('0.2'), ether('0.1'), ether('0.5'), time.duration.hours(1), { from: piGov }); }); it('should DO rebalance on deposit if the rebalancing interval has passed', async () => { @@ -618,6 +622,7 @@ describe('AaveRouter Tests', () => { stakedAave.address, ether('0.2'), ether('0.02'), + ether('0.3'), '0', pvp, ether('0.2'), @@ -645,6 +650,7 @@ describe('AaveRouter Tests', () => { stakedAave.address, ether('0.2'), ether('0.02'), + ether('0.3'), '0', pvp, 0, diff --git a/test/router/implementations/AutoRouter.unit.js b/test/router/implementations/AutoRouter.unit.js index 0eb4aa65..95833252 100644 --- a/test/router/implementations/AutoRouter.unit.js +++ b/test/router/implementations/AutoRouter.unit.js @@ -111,6 +111,7 @@ describe('AutoRouter Tests', () => { autoFarm.address, ether('0.2'), ether('0.02'), + ether('0.3'), '0', pvp, ether('0.15'), @@ -379,7 +380,7 @@ describe('AutoRouter Tests', () => { describe('when interval enabled', () => { beforeEach(async () => { await time.increase(time.duration.weeks(1)); - await autoRouter.setReserveConfig(ether('0.2'), time.duration.hours(1), { from: piGov }); + await autoRouter.setReserveConfig(ether('0.2'), ether('0.01'), ether('0.9'), time.duration.hours(1), { from: piGov }); await poke.setMinMaxReportIntervals(time.duration.hours(1), time.duration.hours(2)); await autoRouter.poke(false, { from: bob }); }); @@ -468,7 +469,7 @@ describe('AutoRouter Tests', () => { }); it('should stake all the underlying tokens with 0 RR', async () => { - await autoRouter.setReserveConfig(ether(0), 0, { from: piGov }); + await autoRouter.setReserveConfig(ether(0), ether('0'), ether('0.5'), 0, { from: piGov }); await autoRouter.poke(false, { from: bob }); assert.equal(await auto.balanceOf(autoStrategy.address), ether(52000)); @@ -476,7 +477,7 @@ describe('AutoRouter Tests', () => { }) it('should keep all the underlying tokens on piToken with 1 RR', async () => { - await autoRouter.setReserveConfig(ether(1), 0, { from: piGov }); + await autoRouter.setReserveConfig(ether(1), ether('0'), ether(1), 0, { from: piGov }); await time.increase(time.duration.weeks(1)); await autoRouter.poke(false, { from: bob }); @@ -572,11 +573,11 @@ describe('AutoRouter Tests', () => { it('should revert poke if there is nothing released', async () => { const scammyChef = await MockAutoMasterChef.new(auto.address, ether(8320)); - await autoRouter.setReserveConfig(ether(1), 0, { from: piGov }); + await autoRouter.setReserveConfig(ether(1), ether(0), ether(1), 0, { from: piGov }); await time.increase(time.duration.weeks(1)); await autoRouter.poke(false); await autoRouter.setVotingAndStaking(constants.ZERO_ADDRESS, scammyChef.address, { from: piGov }); - await autoRouter.setReserveConfig(ether('0.2'), 0, { from: piGov }); + await autoRouter.setReserveConfig(ether('0.2'), ether('0.1'), ether('0.3'), 0, { from: piGov }); await autoRouter.poke(false); await auto.transfer(scammyChef.address, ether(1000)); await expectRevert(autoRouter.poke(true, { from: alice }), 'NOTHING_RELEASED'); @@ -593,6 +594,7 @@ describe('AutoRouter Tests', () => { autoFarm.address, ether('0.2'), ether('0.02'), + ether('0.3'), '0', pvp, ether('0.2'), diff --git a/test/router/implementations/BakeryMasterChefRouter.unit.js b/test/router/implementations/BakeryMasterChefRouter.unit.js index b7288d9b..e584ae14 100644 --- a/test/router/implementations/BakeryMasterChefRouter.unit.js +++ b/test/router/implementations/BakeryMasterChefRouter.unit.js @@ -63,6 +63,7 @@ describe('BakeryMasterChefRouter Tests', () => { bakeryChef.address, ether('0.2'), ether('0.02'), + ether('0.3'), '0', pvp, ether('0.15'), @@ -227,7 +228,7 @@ describe('BakeryMasterChefRouter Tests', () => { describe('when interval enabled', () => { beforeEach(async () => { - await myRouter.setReserveConfig(ether('0.2'), time.duration.hours(1), { from: piGov }); + await myRouter.setReserveConfig(ether('0.2'), ether('0.1'), ether('0.3'), time.duration.hours(1), { from: piGov }); await poke.setMinMaxReportIntervals(time.duration.hours(1), time.duration.hours(2), { from: piGov }); }); @@ -305,7 +306,7 @@ describe('BakeryMasterChefRouter Tests', () => { }); it('should stake all the underlying tokens with 0 RR', async () => { - await myRouter.setReserveConfig(ether(0), 0, { from: piGov }); + await myRouter.setReserveConfig(ether(0), ether(0), ether(1), 0, { from: piGov }); await myRouter.poke(false, { from: bob }); assert.equal(await bake.balanceOf(bakeryChef.address), ether('53073.015873016000000000')); @@ -313,7 +314,7 @@ describe('BakeryMasterChefRouter Tests', () => { }); it('should keep all the underlying tokens on piToken with 1 RR', async () => { - await myRouter.setReserveConfig(ether(1), 0, { from: piGov }); + await myRouter.setReserveConfig(ether(1), ether(0), ether(1), 0, { from: piGov }); await myRouter.poke(false, { from: bob }); assert.equal(await bake.balanceOf(bakeryChef.address), ether('43073.015873016000000000')); @@ -393,10 +394,10 @@ describe('BakeryMasterChefRouter Tests', () => { it('should revert poke if there is nothing released', async () => { const dishonestChef = await MockBakeryMasterChef.new(bake.address); - await myRouter.setReserveConfig(ether(1), 0, { from: piGov }); + await myRouter.setReserveConfig(ether(1), ether(0), ether(1), 0, { from: piGov }); await myRouter.poke(false); await myRouter.setVotingAndStaking(constants.ZERO_ADDRESS, dishonestChef.address, { from: piGov }); - await myRouter.setReserveConfig(ether('0.2'), 0, { from: piGov }); + await myRouter.setReserveConfig(ether('0.2'), ether('0.1'), ether('0.3'), 0, { from: piGov }); // there are still some rewards from rebalancing pokes await myRouter.poke(true, { from: alice }); @@ -416,6 +417,7 @@ describe('BakeryMasterChefRouter Tests', () => { bakeryChef.address, ether('0.2'), ether('0.02'), + ether('0.3'), '0', pvp, ether('0.2'), diff --git a/test/router/implementations/MDXMasterChefRouter.unit.js b/test/router/implementations/MDXMasterChefRouter.unit.js index a52bf9f1..31ccc803 100644 --- a/test/router/implementations/MDXMasterChefRouter.unit.js +++ b/test/router/implementations/MDXMasterChefRouter.unit.js @@ -51,6 +51,7 @@ describe('MDXMasterChefRouter Tests', () => { boardRoomMDX.address, ether('0.2'), ether('0.02'), + ether('0.3'), '0', pvp, ether('0.15'), @@ -222,7 +223,7 @@ describe('MDXMasterChefRouter Tests', () => { describe('when interval enabled', () => { beforeEach(async () => { - await myRouter.setReserveConfig(ether('0.2'), time.duration.hours(1), { from: piGov }); + await myRouter.setReserveConfig(ether('0.2'), ether('0.02'), ether('0.3'), time.duration.hours(1), { from: piGov }); await poke.setMinMaxReportIntervals(time.duration.hours(1), time.duration.hours(2), { from: piGov }); }); @@ -300,7 +301,7 @@ describe('MDXMasterChefRouter Tests', () => { }); it('should stake all the underlying tokens with 0 RR', async () => { - await myRouter.setReserveConfig(ether(0), 0, { from: piGov }); + await myRouter.setReserveConfig(ether(0), ether(0), ether(1), 0, { from: piGov }); await myRouter.poke(false, { from: bob }); assert.equal(await mdx.balanceOf(boardRoomMDX.address), ether('570396.160000000000000000')); @@ -308,7 +309,7 @@ describe('MDXMasterChefRouter Tests', () => { }); it('should keep all the underlying tokens on piToken with 1 RR', async () => { - await myRouter.setReserveConfig(ether(1), 0, { from: piGov }); + await myRouter.setReserveConfig(ether(1), ether(0), ether(1), 0, { from: piGov }); await myRouter.poke(false, { from: bob }); assert.equal(await mdx.balanceOf(boardRoomMDX.address), ether('560396.160000000000000000')); @@ -388,10 +389,10 @@ describe('MDXMasterChefRouter Tests', () => { it('should revert poke if there is nothing released', async () => { const dishonestChef = await MockGeneralMasterChef.new(mdx.address); - await myRouter.setReserveConfig(ether(1), 0, { from: piGov }); + await myRouter.setReserveConfig(ether(1), ether(0), ether(1), 0, { from: piGov }); await myRouter.poke(false); await myRouter.setVotingAndStaking(constants.ZERO_ADDRESS, dishonestChef.address, { from: piGov }); - await myRouter.setReserveConfig(ether('0.2'), 0, { from: piGov }); + await myRouter.setReserveConfig(ether('0.2'), ether(0), ether(1), 0, { from: piGov }); // there are still some rewards from rebalancing pokes await myRouter.poke(true, { from: alice }); @@ -411,6 +412,7 @@ describe('MDXMasterChefRouter Tests', () => { boardRoomMDX.address, ether('0.2'), ether('0.02'), + ether('0.3'), '0', pvp, ether('0.2'), diff --git a/test/router/implementations/PancakeMasterChefRouter.unit.js b/test/router/implementations/PancakeMasterChefRouter.unit.js index 49ae9826..0d48404b 100644 --- a/test/router/implementations/PancakeMasterChefRouter.unit.js +++ b/test/router/implementations/PancakeMasterChefRouter.unit.js @@ -55,6 +55,7 @@ describe('PancakeMasterChefRouter Tests', () => { masterChef.address, ether('0.2'), ether('0.02'), + ether('0.3'), '0', pvp, ether('0.15'), @@ -219,7 +220,7 @@ describe('PancakeMasterChefRouter Tests', () => { describe('when interval enabled', () => { beforeEach(async () => { - await myRouter.setReserveConfig(ether('0.2'), time.duration.hours(1), { from: piGov }); + await myRouter.setReserveConfig(ether('0.2'), ether('0.02'), ether('0.3'), time.duration.hours(1), { from: piGov }); await poke.setMinMaxReportIntervals(time.duration.hours(1), time.duration.hours(2), { from: piGov }); }); @@ -297,7 +298,7 @@ describe('PancakeMasterChefRouter Tests', () => { }); it('should stake all the underlying tokens with 0 RR', async () => { - await myRouter.setReserveConfig(ether(0), 0, { from: piGov }); + await myRouter.setReserveConfig(ether(0), ether(0), ether(1), 0, { from: piGov }); await myRouter.poke(false, { from: bob }); assert.equal(await cake.balanceOf(masterChef.address), ether(52000)); @@ -305,7 +306,7 @@ describe('PancakeMasterChefRouter Tests', () => { }); it('should keep all the underlying tokens on piToken with 1 RR', async () => { - await myRouter.setReserveConfig(ether(1), 0, { from: piGov }); + await myRouter.setReserveConfig(ether(1), ether(0), ether(1), 0, { from: piGov }); await myRouter.poke(false, { from: bob }); assert.equal(await cake.balanceOf(masterChef.address), ether(42000)); @@ -388,10 +389,10 @@ describe('PancakeMasterChefRouter Tests', () => { it('should revert poke if there is nothing released', async () => { const dishonestChef = await MockPancakeMasterChef.new(cake.address); - await myRouter.setReserveConfig(ether(1), 0, { from: piGov }); + await myRouter.setReserveConfig(ether(1), ether(0), ether(1), 0, { from: piGov }); await myRouter.poke(false); await myRouter.setVotingAndStaking(constants.ZERO_ADDRESS, dishonestChef.address, { from: piGov }); - await myRouter.setReserveConfig(ether('0.2'), 0, { from: piGov }); + await myRouter.setReserveConfig(ether('0.2'), ether('0.02'), ether('0.3'), 0, { from: piGov }); await myRouter.poke(true); await expectRevert(myRouter.poke(true, { from: alice }), 'NO_PENDING_REWARD'); }); @@ -407,6 +408,7 @@ describe('PancakeMasterChefRouter Tests', () => { masterChef.address, ether('0.2'), ether('0.02'), + ether('0.3'), '0', pvp, ether('0.2'), diff --git a/test/router/implementations/SushiRouter.stories.js b/test/router/implementations/SushiRouter.stories.js index a0bc9853..cad9bb85 100644 --- a/test/router/implementations/SushiRouter.stories.js +++ b/test/router/implementations/SushiRouter.stories.js @@ -46,6 +46,7 @@ describe('SushiRouter Stories', () => { xSushi.address, ether('0.2'), ether('0.02'), + ether('0.3'), '0', pvp, ether('0.15'), @@ -211,7 +212,7 @@ describe('SushiRouter Stories', () => { /////////////////////////////////////////// // Step #8. Bob router withdrawal 100 SUSHI - await sushiRouter.setReserveConfig(ether('0.4'), '0', {from: piGov}) + await sushiRouter.setReserveConfig(ether('0.4'), ether('0.1'), ether('0.5'),'0', {from: piGov}) await sushiRouter.poke(false); assert.equal(await sushi.balanceOf(piSushi.address), '173999999999999999999'); @@ -221,7 +222,7 @@ describe('SushiRouter Stories', () => { await piSushi.approve(piSushi.address, ether(100), { from: bob }); await piSushi.withdraw(ether(100), { from: bob }); - await sushiRouter.setReserveConfig(ether('0.2'), '0', {from: piGov}) + await sushiRouter.setReserveConfig(ether('0.2'), ether('0.1'), ether('0.5'), '0', {from: piGov}) await sushiRouter.poke(false); // assertions @@ -295,12 +296,12 @@ describe('SushiRouter Stories', () => { // Step #11. Alice router withdrawal 185 SUSHI await pool.transfer(piSushi.address, alice, ether(1)); - await sushiRouter.setReserveConfig(ether('0.8'), '0', {from: piGov}) + await sushiRouter.setReserveConfig(ether('0.8'), ether('0.1'), ether('0.9'), '0', {from: piGov}) await sushiRouter.poke(false); await piSushi.withdraw(ether(185), { from: alice }); - await sushiRouter.setReserveConfig(ether('0.2'), '0', {from: piGov}) + await sushiRouter.setReserveConfig(ether('0.2'), ether('0.1'), ether('0.5'), '0', {from: piGov}) await sushiRouter.poke(false); // assertions @@ -345,7 +346,7 @@ describe('SushiRouter Stories', () => { ////////////////////////////////////////////////////////////////////////////////// // Step #13. Bob router withdrawal 150 SUSHI - 5 wei - await sushiRouter.setReserveConfig(ether('1'), '0', {from: piGov}) + await sushiRouter.setReserveConfig(ether(1), ether('0.5'), ether(1), '0', {from: piGov}) await sushiRouter.poke(false); await piSushi.withdraw('149999999999999999995', { from: bob }); diff --git a/test/router/implementations/SushiRouter.unit.js b/test/router/implementations/SushiRouter.unit.js index 70aad525..b0db1e0f 100644 --- a/test/router/implementations/SushiRouter.unit.js +++ b/test/router/implementations/SushiRouter.unit.js @@ -46,6 +46,7 @@ describe('SushiRouter Tests', () => { xSushi.address, ether('0.2'), ether('0.02'), + ether('0.3'), '0', pvp, ether('0.15'), @@ -296,7 +297,7 @@ describe('SushiRouter Tests', () => { describe('when interval enabled', () => { beforeEach(async () => { - await sushiRouter.setReserveConfig(ether('0.2'), time.duration.hours(1), { from: piGov }); + await sushiRouter.setReserveConfig(ether('0.2'), ether('0.02'), ether('0.3'), time.duration.hours(1), { from: piGov }); await poke.setMinMaxReportIntervals(time.duration.hours(1), time.duration.hours(2)); await sushiRouter.poke(false, { from: bob }); }); @@ -338,17 +339,47 @@ describe('SushiRouter Tests', () => { await sushiRouter.pokeFromReporter('0', false, '0x', { from: bob }); }); - it('should rebalance if the rebalancing interval not passed but reserveRatioToForceRebalance has reached', async () => { - await time.increase(time.duration.minutes(59)); + describe('when the rebalancing interval hasnt passed yet', async () => { + beforeEach(async () => { + await time.increase(time.duration.minutes(59)); + assert.equal(await sushiRouter.getReserveStatusForStakedBalance().then(s => s.forceRebalance), false); + }); - assert.equal(await sushiRouter.getReserveStatusForStakedBalance().then(s => s.forceRebalance), false); - await piSushi.withdraw(ether(2000), { from: alice }); - assert.equal(await sushiRouter.getReserveStatusForStakedBalance().then(s => s.forceRebalance), true); - await sushiRouter.pokeFromReporter('0', false, '0x', { from: bob }); + it('should allow rabalancing if reserveRatioLowerBound has reached', async () => { + await piSushi.withdraw(ether(1900), { from: alice }); + + assert.equal(await sushiRouter.getReserveStatusForStakedBalance().then(s => s.forceRebalance), true); + await sushiRouter.pokeFromReporter('0', false, '0x', { from: bob }); + + assert.equal(await sushi.balanceOf(xSushi.address), ether(48480)); + assert.equal(await xSushi.balanceOf(piSushi.address), ether(6480)); + assert.equal(await sushi.balanceOf(piSushi.address), ether(1620)); + }); - assert.equal(await sushi.balanceOf(xSushi.address), ether(48400)); - assert.equal(await xSushi.balanceOf(piSushi.address), ether(6400)); - assert.equal(await sushi.balanceOf(piSushi.address), ether(1600)); + it('should not rebalance if the current RR is slightly higher than lowerBound', async () => { + await piSushi.withdraw(ether(1800), { from: alice }); + assert.equal(await sushiRouter.getReserveStatusForStakedBalance().then(s => s.forceRebalance), false); + await expectRevert(sushiRouter.pokeFromReporter('0', false, '0x', { from: bob }), 'MIN_INTERVAL_NOT_REACHED'); + }); + + it('should not rebalance if the current RR is slightly lower than upperBound', async () => { + await sushi.approve(piSushi.address, ether(1400), { from: alice }); + await piSushi.deposit(ether(1400), { from: alice }); + assert.equal(await sushiRouter.getReserveStatusForStakedBalance().then(s => s.forceRebalance), false); + await expectRevert(sushiRouter.pokeFromReporter('0', false, '0x', { from: bob }), 'MIN_INTERVAL_NOT_REACHED'); + }); + + it('should allow rabalancing if reserveRatioLowerBound has reached', async () => { + await sushi.approve(piSushi.address, ether(1500), { from: alice }); + await piSushi.deposit(ether(1500), { from: alice }); + + assert.equal(await sushiRouter.getReserveStatusForStakedBalance().then(s => s.forceRebalance), true); + await sushiRouter.pokeFromReporter('0', false, '0x', { from: bob }); + + assert.equal(await sushi.balanceOf(xSushi.address), ether(51200)); + assert.equal(await xSushi.balanceOf(piSushi.address), ether(9200)); + assert.equal(await sushi.balanceOf(piSushi.address), ether(2300)); + }); }); }); @@ -385,7 +416,7 @@ describe('SushiRouter Tests', () => { }); it('should stake all the underlying tokens with 0 RR', async () => { - await sushiRouter.setReserveConfig(ether(0), 0, { from: piGov }); + await sushiRouter.setReserveConfig(ether(0), ether(0), ether(1), 0, { from: piGov }); await sushiRouter.poke(false, { from: bob }); assert.equal(await sushi.balanceOf(xSushi.address), ether(52000)); @@ -393,7 +424,7 @@ describe('SushiRouter Tests', () => { }) it('should keep all the underlying tokens on piToken with 1 RR', async () => { - await sushiRouter.setReserveConfig(ether(1), 0, { from: piGov }); + await sushiRouter.setReserveConfig(ether(1), ether(0), ether(1), 0, { from: piGov }); await sushiRouter.poke(false, { from: bob }); assert.equal(await sushi.balanceOf(xSushi.address), ether(42000)); @@ -486,10 +517,10 @@ describe('SushiRouter Tests', () => { it('should revert poke if there is nothing released', async () => { const scammyBar = await MockSushiBar.new(sushi.address); - await sushiRouter.setReserveConfig(ether(1), 0, { from: piGov }); + await sushiRouter.setReserveConfig(ether(1), ether(0), ether(1), 0, { from: piGov }); await sushiRouter.poke(false); await sushiRouter.setVotingAndStaking(constants.ZERO_ADDRESS, scammyBar.address, { from: piGov }); - await sushiRouter.setReserveConfig(ether('0.2'), 0, { from: piGov }); + await sushiRouter.setReserveConfig(ether('0.2'), ether('0.1'), ether('0.2'), 0, { from: piGov }); await sushiRouter.poke(false); await sushi.transfer(scammyBar.address, ether(1000)); await expectRevert(sushiRouter.poke(true, { from: alice }), 'NOTHING_RELEASED'); @@ -506,6 +537,7 @@ describe('SushiRouter Tests', () => { xSushi.address, ether('0.2'), ether('0.02'), + ether('0.3'), '0', pvp, ether('0.2'), diff --git a/test/router/implementations/VenusRouter.unit.js b/test/router/implementations/VenusRouter.unit.js index 7cea2464..d0be46c3 100644 --- a/test/router/implementations/VenusRouter.unit.js +++ b/test/router/implementations/VenusRouter.unit.js @@ -128,6 +128,7 @@ describe('VenusRouter Tests', () => { vUsdc.address, ether('0.2'), ether('0.02'), + ether('0.3'), '0', pvp, ether('0.15'), @@ -408,7 +409,7 @@ describe('VenusRouter Tests', () => { describe('when interval enabled', () => { beforeEach(async () => { - await venusRouter.setReserveConfig(ether('0.2'), time.duration.hours(1), { from: piGov }); + await venusRouter.setReserveConfig(ether('0.2'), ether('0.02'), ether('0.3'), time.duration.hours(1), { from: piGov }); await poke.setMinMaxReportIntervals(time.duration.hours(1), time.duration.hours(2)); await venusRouter.poke(false, { from: bob }); }); @@ -497,7 +498,7 @@ describe('VenusRouter Tests', () => { }); it('should stake all the underlying tokens with 0 RR', async () => { - await venusRouter.setReserveConfig(ether(0), 0, { from: piGov }); + await venusRouter.setReserveConfig(ether(0), ether(0), ether(1), 0, { from: piGov }); await venusRouter.poke(false, { from: bob }); assert.equal(await usdc.balanceOf(vUsdc.address), ether(52000)); @@ -505,7 +506,7 @@ describe('VenusRouter Tests', () => { }); it('should keep all the underlying tokens on piToken with 1 RR', async () => { - await venusRouter.setReserveConfig(ether(1), 0, { from: piGov }); + await venusRouter.setReserveConfig(ether(1), ether(0), ether(1), 0, { from: piGov }); await venusRouter.poke(false, { from: bob }); assert.equal(await usdc.balanceOf(vUsdc.address), ether(42000)); @@ -669,6 +670,7 @@ describe('VenusRouter Tests', () => { vUsdc.address, ether('0.2'), ether('0.02'), + ether('0.2'), '0', pvp, ether('0.2'), diff --git a/test/router/implementations/YearnRouter.test.js b/test/router/implementations/YearnRouter.test.js index 82115250..58c21169 100644 --- a/test/router/implementations/YearnRouter.test.js +++ b/test/router/implementations/YearnRouter.test.js @@ -76,6 +76,7 @@ describe('YearnRouter Tests', () => { yearnGovernance.address, ether('0.2'), ether('0.02'), + ether('0.3'), '0', pvp, ether('0.15'), @@ -354,7 +355,7 @@ describe('YearnRouter Tests', () => { describe('when interval enabled', () => { beforeEach(async () => { - await yfiRouter.setReserveConfig(ether('0.2'), time.duration.hours(1), { from: piGov }); + await yfiRouter.setReserveConfig(ether('0.2'), ether('0.1'), ether('0.3'), time.duration.hours(1), { from: piGov }); await poke.setMinMaxReportIntervals(time.duration.hours(1), time.duration.hours(2), { from: piGov }); }); @@ -451,7 +452,7 @@ describe('YearnRouter Tests', () => { }); it('should stake all the underlying tokens with 0 RR', async () => { - await yfiRouter.setReserveConfig(ether(0), 0, { from: piGov }); + await yfiRouter.setReserveConfig(ether(0), ether(0), ether(1), 0, { from: piGov }); await yfiRouter.poke(false, { from: bob }); assert.equal(await yfi.balanceOf(yearnGovernance.address), ether(52000)); @@ -459,7 +460,7 @@ describe('YearnRouter Tests', () => { }) it('should keep all the underlying tokens on piToken with 1 RR', async () => { - await yfiRouter.setReserveConfig(ether(1), 0, { from: piGov }); + await yfiRouter.setReserveConfig(ether(1), ether(0), ether(1), 0, { from: piGov }); await yfiRouter.poke(false, { from: bob }); assert.equal(await yfi.balanceOf(yearnGovernance.address), ether(42000)); @@ -621,6 +622,7 @@ describe('YearnRouter Tests', () => { yearnGovernance.address, ether('0.2'), ether('0.02'), + ether('0.2'), '0', pvp, ether('0.2'), @@ -652,6 +654,7 @@ describe('YearnRouter Tests', () => { yearnGovernance.address, ether('0.2'), ether('0.02'), + ether('0.3'), '0', pvp, ether('0.2'), From 27597ae228981bdd501de2ff347c93afa63130e4 Mon Sep 17 00:00:00 2001 From: Poli Paul Date: Thu, 16 Sep 2021 16:21:33 +0200 Subject: [PATCH 17/33] Fix tests --- test/helpers/builders.js | 3 ++- test/pvp/CVPMaker.test.js | 4 +++- test/router/PowerIndexImplFactories.test.js | 13 ++++++++++-- test/router/PowerIndexRouter.test.js | 23 ++++++++++++++------- test/router/PowerIndexWrapper.test.js | 1 + test/router/WrappedPiErc20.unit.test.js | 1 + test/strategies/WeightStrategy.test.js | 1 + 7 files changed, 35 insertions(+), 11 deletions(-) diff --git a/test/helpers/builders.js b/test/helpers/builders.js index 64a6c152..5b909e2b 100644 --- a/test/helpers/builders.js +++ b/test/helpers/builders.js @@ -71,7 +71,8 @@ const BasicConfig = { voting: 'address', staking: 'address', reserveRatio: 'uint256', - reserveRatioToForceRebalance: 'uint256', + reserveRatioLowerBound: 'uint256', + reserveRatioUpperBound: 'uint256', claimRewardsInterval: 'uint256', pvp: 'address', pvpFee: 'uint256', diff --git a/test/pvp/CVPMaker.test.js b/test/pvp/CVPMaker.test.js index 4ccf2d16..1d4fe3d1 100644 --- a/test/pvp/CVPMaker.test.js +++ b/test/pvp/CVPMaker.test.js @@ -101,6 +101,7 @@ describe('CVPMaker test', () => { constants.ZERO_ADDRESS, ether(0), '0', + '0', '3600', stub, ether(0), @@ -113,7 +114,8 @@ describe('CVPMaker test', () => { voting: 'address', staking: 'address', reserveRatio: 'uint256', - reserveRatioToForceRebalance: 'uint256', + reserveRatioLowerBound: 'uint256', + reserveRatioUpperBound: 'uint256', claimRewardsInterval: 'uint256', pvp: 'address', pvpFee: 'uint256', diff --git a/test/router/PowerIndexImplFactories.test.js b/test/router/PowerIndexImplFactories.test.js index c108a5a9..a9bf42cd 100644 --- a/test/router/PowerIndexImplFactories.test.js +++ b/test/router/PowerIndexImplFactories.test.js @@ -84,6 +84,7 @@ describe('PowerIndex Implementation Factories Test', () => { stakedAave.address, ether('0.3'), ether('0.03'), + ether('0.4'), 4, pvp, ether('0.15'), @@ -97,7 +98,8 @@ describe('PowerIndex Implementation Factories Test', () => { voting: 'address', staking: 'address', reserveRatio: 'uint256', - reserveRatioToForceRebalance: 'uint256', + reserveRatioLowerBound: 'uint256', + reserveRatioUpperBound: 'uint256', claimRewardsInterval: 'uint256', pvp: 'address', pvpFee: 'uint256', @@ -121,6 +123,8 @@ describe('PowerIndex Implementation Factories Test', () => { assert.equal(await router.owner(), deployer); assert.equal(await router.reserveRatio(), ether('0.3')); + assert.equal(await router.reserveRatioLowerBound(), ether('0.03')); + assert.equal(await router.reserveRatioUpperBound(), ether('0.4')); assert.equal(await router.claimRewardsInterval(), 4); assert.equal(await router.staking(), stakedAave.address); assert.equal(await router.poolRestrictions(), poolRestrictions); @@ -149,7 +153,8 @@ describe('PowerIndex Implementation Factories Test', () => { voting: 'address', staking: 'address', reserveRatio: 'uint256', - reserveRatioToForceRebalance: 'uint256', + reserveRatioLowerBound: 'uint256', + reserveRatioUpperBound: 'uint256', claimRewardsInterval: 'uint256', pvp: 'address', pvpFee: 'uint256', @@ -180,6 +185,8 @@ describe('PowerIndex Implementation Factories Test', () => { assert.equal(await router.owner(), deployer); assert.equal(await router.reserveRatio(), ether('0.3')); + assert.equal(await router.reserveRatioLowerBound(), ether('0.03')); + assert.equal(await router.reserveRatioUpperBound(), ether('0.4')); assert.equal(await router.claimRewardsInterval(), 4); assert.equal(await router.staking(), stakedAave.address); assert.equal(await router.poolRestrictions(), poolRestrictions); @@ -208,6 +215,8 @@ describe('PowerIndex Implementation Factories Test', () => { assert.equal(await router.owner(), deployer); assert.equal(await router.reserveRatio(), ether('0.3')); + assert.equal(await router.reserveRatioLowerBound(), ether('0.03')); + assert.equal(await router.reserveRatioUpperBound(), ether('0.4')); assert.equal(await router.claimRewardsInterval(), 4); assert.equal(await router.staking(), stakedAave.address); assert.equal(await router.poolRestrictions(), poolRestrictions); diff --git a/test/router/PowerIndexRouter.test.js b/test/router/PowerIndexRouter.test.js index 3b533b21..9418cd90 100644 --- a/test/router/PowerIndexRouter.test.js +++ b/test/router/PowerIndexRouter.test.js @@ -36,6 +36,7 @@ describe('PowerIndex BasicRouter Test', () => { constants.ZERO_ADDRESS, ether(0), ether(0), + ether(0), 0, stub, ether(0), @@ -44,9 +45,9 @@ describe('PowerIndex BasicRouter Test', () => { }); describe('initialization', () => { - it('should deny initialization with a RR > 100%', async () => { - const basicConfig = Object.assign({}, defaultBasicConfig, { reserveRatio: ether('1.01') }); - await expectRevert(PowerIndexBasicRouter.new(alice, basicConfig), 'RR_GT_HUNDRED_PCT'); + it('should deny initialization with a RR UPPER BOUND > 100%', async () => { + const basicConfig = Object.assign({}, defaultBasicConfig, { reserveRatioUpperBound: ether('1.01') }); + await expectRevert(PowerIndexBasicRouter.new(alice, basicConfig), 'UPPER_RR_GREATER_THAN_100_PCT'); }); it('should deny initialization with a pvpFee >= 100%', async () => { @@ -134,7 +135,7 @@ describe('PowerIndex BasicRouter Test', () => { describe('setReserveConfig()', () => { it('should allow the owner setting a reserve config', async () => { - const res = await router.setReserveConfig(ether('0.2'), 3600, { from: piGov }); + const res = await router.setReserveConfig(ether('0.2'), ether('0.1'), ether('0.3'), 3600, { from: piGov }); expectEvent(res, 'SetReserveConfig', { ratio: ether('0.2'), claimRewardsInterval: '3600' @@ -143,12 +144,20 @@ describe('PowerIndex BasicRouter Test', () => { assert.equal(await router.claimRewardsInterval(), 3600) }); - it('should deny setting a reserve ratio greater or equal 100%', async () => { - await expectRevert(router.setReserveConfig(ether('1.01'), 0, { from: piGov }), 'RR_GREATER_THAN_100_PCT'); + it('should deny setting a reserve ratio upper bound greater or equal 100%', async () => { + await expectRevert(router.setReserveConfig(ether('1.00'), ether('0.1'), ether('1.01'), 0, { from: piGov }), 'RR_GREATER_THAN_100_PCT'); + }); + + it('should deny setting a reserve ratio upper bound lower than rr', async () => { + await expectRevert(router.setReserveConfig(ether('1.00'), ether('0.1'), ether('1.01'), 0, { from: piGov }), 'UPPER_RR_GREATER_THAN_100_PCT'); + }); + + it('should deny setting a reserve ratio lower bound higher than rr ', async () => { + await expectRevert(router.setReserveConfig(ether('0.99'), ether('1.00'), ether('1.00'), 0, { from: piGov }), 'RR_LT_LOWER_RR'); }); it('should deny non-owner setting reserve config', async () => { - await expectRevert(router.setReserveConfig(ether('0.2'), 3600, { from: alice }), 'Ownable: caller is not the owner'); + await expectRevert(router.setReserveConfig(ether('0.2'), ether(0), ether(1), 3600, { from: alice }), 'Ownable: caller is not the owner'); }); }); }); diff --git a/test/router/PowerIndexWrapper.test.js b/test/router/PowerIndexWrapper.test.js index 9930ff3b..28716736 100644 --- a/test/router/PowerIndexWrapper.test.js +++ b/test/router/PowerIndexWrapper.test.js @@ -96,6 +96,7 @@ describe('PowerIndexWrapper', () => { constants.ZERO_ADDRESS, ether(0), ether(0), + ether(0), '0', stub, ether(0), diff --git a/test/router/WrappedPiErc20.unit.test.js b/test/router/WrappedPiErc20.unit.test.js index 6c0b7495..54ed82c4 100644 --- a/test/router/WrappedPiErc20.unit.test.js +++ b/test/router/WrappedPiErc20.unit.test.js @@ -40,6 +40,7 @@ describe('WrappedPiErc20 Unit Tests', () => { constants.ZERO_ADDRESS, ether('0.2'), ether('0.02'), + ether('0.3'), '0', stub, ether(0), diff --git a/test/strategies/WeightStrategy.test.js b/test/strategies/WeightStrategy.test.js index c2bfbc95..ea289f3c 100644 --- a/test/strategies/WeightStrategy.test.js +++ b/test/strategies/WeightStrategy.test.js @@ -645,6 +645,7 @@ describe('WeightStrategy', () => { constants.ZERO_ADDRESS, ether(0), ether(0), + ether(0), '0', permanentVotingPower, ether(0), From b68d7138f7c1fcae0663714865dd7ccf23a18d56 Mon Sep 17 00:00:00 2001 From: Poli Paul Date: Thu, 16 Sep 2021 18:11:24 +0200 Subject: [PATCH 18/33] Fix tests --- test/EthPiptSwap.test.js | 1 + test/PowerIndexPoolController.test.js | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/test/EthPiptSwap.test.js b/test/EthPiptSwap.test.js index 56ab9b69..b0a80506 100644 --- a/test/EthPiptSwap.test.js +++ b/test/EthPiptSwap.test.js @@ -519,6 +519,7 @@ describe('EthPiptSwap and Erc20PiptSwap', () => { ether(0), '0', '0', + '0', feeReceiver, ether(0), [] diff --git a/test/PowerIndexPoolController.test.js b/test/PowerIndexPoolController.test.js index 76502fc5..f65feed7 100644 --- a/test/PowerIndexPoolController.test.js +++ b/test/PowerIndexPoolController.test.js @@ -67,7 +67,7 @@ async function getTimestamp(shift = 0) { return currentTimestamp + shift; } -describe('PowerIndexPoolController', () => { +describe.only('PowerIndexPoolController', () => { const zeroAddress = '0x0000000000000000000000000000000000000000'; const name = 'My Pool'; const symbol = 'MP'; @@ -103,6 +103,7 @@ describe('PowerIndexPoolController', () => { '0', '0', '0', + '0', stub, ether(0), [] @@ -114,7 +115,8 @@ describe('PowerIndexPoolController', () => { voting: 'address', staking: 'address', reserveRatio: 'uint256', - reserveRatioToForceRebalance: 'uint256', + reserveRatioUpperBound: 'uint256', + reserveRatioLowerBound: 'uint256', claimRewardsInterval: 'uint256', pvp: 'address', pvpFee: 'uint256', From bcf51afa2ac900fa5612f07c7243030b6f6b2dc9 Mon Sep 17 00:00:00 2001 From: Poli Paul Date: Fri, 17 Sep 2021 16:39:57 +0200 Subject: [PATCH 19/33] Remove permissionless router poke --- contracts/powerindex-router/PowerIndexBasicRouter.sol | 7 ------- 1 file changed, 7 deletions(-) diff --git a/contracts/powerindex-router/PowerIndexBasicRouter.sol b/contracts/powerindex-router/PowerIndexBasicRouter.sol index af780a38..2f40e133 100644 --- a/contracts/powerindex-router/PowerIndexBasicRouter.sol +++ b/contracts/powerindex-router/PowerIndexBasicRouter.sol @@ -203,13 +203,6 @@ contract PowerIndexBasicRouter is PowerIndexBasicRouterInterface, PowerIndexNaiv _afterPoke(status, _claimAndDistributeRewards); } - function poke(bool _claimAndDistributeRewards) external onlyEOA { - _beforePoke(); - (ReserveStatus status, uint256 diff, ) = getReserveStatus(_getUnderlyingStaked(), 0); - _rebalancePoke(status, diff); - _afterPoke(status, _claimAndDistributeRewards); - } - function _beforePoke() internal virtual { require(staking != address(0), "STAKING_IS_NULL"); } From 4b34ed17aaa3e2bb0f7fd4cfa17b89f2ae0932c6 Mon Sep 17 00:00:00 2001 From: Poli Paul Date: Fri, 17 Sep 2021 17:25:10 +0200 Subject: [PATCH 20/33] Rebalnace only if not equilibrium --- contracts/powerindex-router/PowerIndexBasicRouter.sol | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/contracts/powerindex-router/PowerIndexBasicRouter.sol b/contracts/powerindex-router/PowerIndexBasicRouter.sol index 2f40e133..42a501c0 100644 --- a/contracts/powerindex-router/PowerIndexBasicRouter.sol +++ b/contracts/powerindex-router/PowerIndexBasicRouter.sol @@ -184,8 +184,9 @@ contract PowerIndexBasicRouter is PowerIndexBasicRouterInterface, PowerIndexNaiv (uint256 minInterval, ) = _getMinMaxReportInterval(); (ReserveStatus status, uint256 diff, bool forceRebalance) = getReserveStatus(_getUnderlyingStaked(), 0); require(forceRebalance || lastRebalancedAt + minInterval < block.timestamp, "MIN_INTERVAL_NOT_REACHED"); - require(status != ReserveStatus.EQUILIBRIUM, "RESERVE_STATUS_EQUILIBRIUM"); - _rebalancePoke(status, diff); + if (status != ReserveStatus.EQUILIBRIUM) { + _rebalancePoke(status, diff); + } _afterPoke(status, _claimAndDistributeRewards); } @@ -198,8 +199,9 @@ contract PowerIndexBasicRouter is PowerIndexBasicRouterInterface, PowerIndexNaiv (, uint256 maxInterval) = _getMinMaxReportInterval(); (ReserveStatus status, uint256 diff, bool forceRebalance) = getReserveStatus(_getUnderlyingStaked(), 0); require(forceRebalance || lastRebalancedAt + maxInterval < block.timestamp, "MAX_INTERVAL_NOT_REACHED"); - require(status != ReserveStatus.EQUILIBRIUM, "RESERVE_STATUS_EQUILIBRIUM"); - _rebalancePoke(status, diff); + if (status != ReserveStatus.EQUILIBRIUM) { + _rebalancePoke(status, diff); + } _afterPoke(status, _claimAndDistributeRewards); } From acd7050090f73eec4e9a377626bda01a4b1f7a59 Mon Sep 17 00:00:00 2001 From: Poli Paul Date: Fri, 17 Sep 2021 17:32:14 +0200 Subject: [PATCH 21/33] Remove .only from test --- test/PowerIndexPoolController.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/PowerIndexPoolController.test.js b/test/PowerIndexPoolController.test.js index f65feed7..7ee9c25e 100644 --- a/test/PowerIndexPoolController.test.js +++ b/test/PowerIndexPoolController.test.js @@ -67,7 +67,7 @@ async function getTimestamp(shift = 0) { return currentTimestamp + shift; } -describe.only('PowerIndexPoolController', () => { +describe('PowerIndexPoolController', () => { const zeroAddress = '0x0000000000000000000000000000000000000000'; const name = 'My Pool'; const symbol = 'MP'; From 68b7c59744ba67f0eb514bb9bd800ff791d4b366 Mon Sep 17 00:00:00 2001 From: Poli Paul Date: Mon, 20 Sep 2021 15:05:29 +0300 Subject: [PATCH 22/33] Fix tests --- .../PowerIndexBasicRouter.sol | 2 +- .../implementations/AaveRouter.stories.js | 14 +++-- .../router/implementations/AaveRouter.unit.js | 57 ++++++++++--------- .../router/implementations/AutoRouter.unit.js | 40 ++++++------- .../BakeryMasterChefRouter.unit.js | 34 +++++------ .../MDXMasterChefRouter.unit.js | 34 +++++------ .../PancakeMasterChefRouter.unit.js | 34 +++++------ .../implementations/SushiRouter.stories.js | 20 ++++--- .../implementations/SushiRouter.unit.js | 41 ++++++------- .../implementations/VenusRouter.unit.js | 37 ++++++------ .../implementations/YearnRouter.test.js | 36 ++++++------ 11 files changed, 186 insertions(+), 163 deletions(-) diff --git a/contracts/powerindex-router/PowerIndexBasicRouter.sol b/contracts/powerindex-router/PowerIndexBasicRouter.sol index 42a501c0..a8380ed2 100644 --- a/contracts/powerindex-router/PowerIndexBasicRouter.sol +++ b/contracts/powerindex-router/PowerIndexBasicRouter.sol @@ -86,7 +86,7 @@ contract PowerIndexBasicRouter is PowerIndexBasicRouterInterface, PowerIndexNaiv constructor(address _piToken, BasicConfig memory _basicConfig) public PowerIndexNaiveRouter() Ownable() { require(_piToken != address(0), "INVALID_PI_TOKEN"); - require(_basicConfig.reserveRatioUpperBound <= HUNDRED_PCT, "RR_GT_HUNDRED_PCT"); + require(_basicConfig.reserveRatioUpperBound <= HUNDRED_PCT, "UPPER_RR_GREATER_THAN_100_PCT"); require(_basicConfig.reserveRatio >= _basicConfig.reserveRatioLowerBound, "RR_LTE_LOWER_RR"); require(_basicConfig.reserveRatio <= _basicConfig.reserveRatioUpperBound, "RR_GTE_UPPER_RR"); require(_basicConfig.pvpFee < HUNDRED_PCT, "PVP_FEE_GTE_HUNDRED_PCT"); diff --git a/test/router/implementations/AaveRouter.stories.js b/test/router/implementations/AaveRouter.stories.js index cd2ef16e..9d781f18 100644 --- a/test/router/implementations/AaveRouter.stories.js +++ b/test/router/implementations/AaveRouter.stories.js @@ -21,6 +21,8 @@ const COOLDOWN_STATUS = { UNSTAKE_WINDOW: 2, }; +const REPORTER_ID = 42; + describe('AaveRouter Stories', () => { let minter, bob, alice, rewardsVault, emissionManager, stub; let aave, stakedAave, piAave, aaveRouter, poolRestrictions; @@ -89,7 +91,7 @@ describe('AaveRouter Stories', () => { // Step #1. Deposit 10K await aave.approve(piAave.address, ether(10000), { from: alice }); await piAave.deposit(ether('10000'), { from: alice }); - let res = await aaveRouter.poke(false); + let res = await aaveRouter.pokeFromReporter(REPORTER_ID, false, '0x'); await expectEvent.notEmitted.inTransaction(res.tx, AavePowerIndexRouter, 'Redeem'); await expectEvent.notEmitted.inTransaction(res.tx, AavePowerIndexRouter, 'TriggerCooldown'); @@ -113,7 +115,7 @@ describe('AaveRouter Stories', () => { ////////////////////////// // Step #2. Withdraw 0.5K await piAave.withdraw(ether(500), { from: alice }); - res = await aaveRouter.poke(false); + res = await aaveRouter.pokeFromReporter(REPORTER_ID, false, '0x'); await expectEvent.notEmitted.inTransaction(res.tx, AavePowerIndexRouter, 'Stake'); await expectEvent.notEmitted.inTransaction(res.tx, AavePowerIndexRouter, 'Redeem'); @@ -132,7 +134,7 @@ describe('AaveRouter Stories', () => { /////////////////////////////////////////////////////// // Step #3. Withdraw 0.5K - waiting for a COOLDOWN ends await piAave.withdraw(ether(500), { from: alice }); - await expectRevert(aaveRouter.poke(false), 'COOLDOWN'); + await expectRevert(aaveRouter.pokeFromReporter(REPORTER_ID, false, '0x'), 'COOLDOWN'); assert.equal(await aave.balanceOf(piAave.address), ether(1000)); assert.equal(await stakedAave.balanceOf(piAave.address), ether(8000)); @@ -147,7 +149,7 @@ describe('AaveRouter Stories', () => { ////////////////////////////////////////////////////////// // Step #4. Withdraw 0.5K - while within an UNSTAKE_WINDOW await piAave.withdraw(ether(500), { from: alice }); - res = await aaveRouter.poke(false); + res = await aaveRouter.pokeFromReporter(REPORTER_ID, false, '0x'); await expectEvent.notEmitted.inTransaction(res.tx, AavePowerIndexRouter, 'Stake'); await expectEvent.notEmitted.inTransaction(res.tx, AavePowerIndexRouter, 'TriggerCooldown'); @@ -162,7 +164,7 @@ describe('AaveRouter Stories', () => { ////////////////////////////////////////////////////////// // Step #5. Withdraw 0.5K - while within an UNSTAKE_WINDOW await piAave.withdraw(ether(500), { from: alice }); - res = await aaveRouter.poke(false); + res = await aaveRouter.pokeFromReporter(REPORTER_ID, false, '0x'); await expectEvent.notEmitted.inTransaction(res.tx, AavePowerIndexRouter, 'Stake'); await expectEvent.notEmitted.inTransaction(res.tx, AavePowerIndexRouter, 'TriggerCooldown'); @@ -178,7 +180,7 @@ describe('AaveRouter Stories', () => { // Step #6. Deposit 3K - while within an UNSTAKE_WINDOW await aave.approve(piAave.address, ether(3000), { from: bob }); await piAave.deposit(ether(3000), { from: bob }); - res = await aaveRouter.poke(false); + res = await aaveRouter.pokeFromReporter(REPORTER_ID, false, '0x'); await expectEvent.notEmitted.inTransaction(res.tx, AavePowerIndexRouter, 'Redeem'); await expectEvent.notEmitted.inTransaction(res.tx, AavePowerIndexRouter, 'TriggerCooldown'); diff --git a/test/router/implementations/AaveRouter.unit.js b/test/router/implementations/AaveRouter.unit.js index 2c775f6b..68ab3b0b 100644 --- a/test/router/implementations/AaveRouter.unit.js +++ b/test/router/implementations/AaveRouter.unit.js @@ -59,6 +59,8 @@ const COOLDOWN_STATUS = { UNSTAKE_WINDOW: 2, }; +const REPORTER_ID = 42; + describe('AaveRouter Tests', () => { let deployer, aaveDistributor, @@ -66,6 +68,7 @@ describe('AaveRouter Tests', () => { alice, rewardsVault, emissionManager, + reporter, stub, guardian, piGov, @@ -79,6 +82,7 @@ describe('AaveRouter Tests', () => { alice, rewardsVault, emissionManager, + reporter, stub, guardian, piGov, @@ -131,7 +135,6 @@ describe('AaveRouter Tests', () => { // governance constants.ZERO_ADDRESS, ); - poolRestrictions = await PoolRestrictions.new(); piAave = await WrappedPiErc20.new(aave.address, stub, 'wrapped.aave', 'piAAVE'); poke = await MockPoke.new(true); @@ -216,7 +219,7 @@ describe('AaveRouter Tests', () => { await aave.transfer(alice, ether('10000'), { from: aaveDistributor }); await aave.approve(piAave.address, ether('10000'), { from: alice }); await piAave.deposit(ether('10000'), { from: alice }); - await aaveRouter.poke(false); + await aaveRouter.pokeFromReporter(REPORTER_ID, false, '0x', { from: reporter }); assert.equal(await aave.balanceOf(piAave.address), ether(2000)); assert.equal(await aave.balanceOf(stakedAave.address), ether(50000)); @@ -302,7 +305,7 @@ describe('AaveRouter Tests', () => { it('it should initially stake the excess of funds to the staking contract immediately', async () => { await aave.approve(piAave.address, ether(10000), { from: alice }); await piAave.deposit(ether('10000'), { from: alice }); - await aaveRouter.poke(false); + await aaveRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await piAave.totalSupply(), ether(10000)); assert.equal(await piAave.balanceOf(alice), ether(10000)); @@ -320,14 +323,14 @@ describe('AaveRouter Tests', () => { beforeEach(async () => { await aave.approve(piAave.address, ether(10000), { from: alice }); await piAave.deposit(ether(10000), { from: alice }); - await aaveRouter.poke(false); + await aaveRouter.pokeFromReporter(REPORTER_ID, false, '0x'); }); it('it should stake the excess of funds to the staking contract immediately', async () => { // 2nd await aave.approve(piAave.address, ether(10000), { from: bob }); await piAave.deposit(ether(10000), { from: bob }); - await aaveRouter.poke(false); + await aaveRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await piAave.totalSupply(), ether(20000)); assert.equal(await piAave.balanceOf(alice), ether(10000)); @@ -347,13 +350,13 @@ describe('AaveRouter Tests', () => { await piAave.withdraw(ether(500), { from: alice }); await piAave.withdraw(ether(500), { from: alice }); await piAave.withdraw(ether(500), { from: alice }); - await aaveRouter.poke(false); + await aaveRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal((await aaveRouter.getCoolDownStatus()).status, COOLDOWN_STATUS.COOLDOWN); await aave.approve(piAave.address, ether(10000), { from: bob }); await piAave.deposit(ether(10000), { from: bob }); - await aaveRouter.poke(false); + await aaveRouter.pokeFromReporter(REPORTER_ID, false, '0x'); }); }); }); @@ -363,14 +366,14 @@ describe('AaveRouter Tests', () => { await aave.transfer(alice, ether('10000'), { from: aaveDistributor }); await aave.approve(piAave.address, ether(1000), { from: alice }); await piAave.deposit(ether(1000), { from: alice }); - await aaveRouter.poke(false); + await aaveRouter.pokeFromReporter(REPORTER_ID, false, '0x'); await aave.transfer(piAave.address, ether(50), { from: alice }); assert.equal(await aave.balanceOf(piAave.address), ether(250)); assert.equal(await aave.balanceOf(stakedAave.address), ether(42800)); // 2nd await piAave.withdraw(ether(50), { from: alice }); - await aaveRouter.poke(false); + await aaveRouter.pokeFromReporter(REPORTER_ID, false, '0x'); // The router has partially staked the deposit with regard to the reserve ration value (20/80) assert.equal(await aave.balanceOf(piAave.address), ether(200)); @@ -382,7 +385,7 @@ describe('AaveRouter Tests', () => { await aave.transfer(alice, ether(100000), { from: aaveDistributor }); await aave.approve(piAave.address, ether(10000), { from: alice }); await piAave.deposit(ether(10000), { from: alice }); - await aaveRouter.poke(false); + await aaveRouter.pokeFromReporter(REPORTER_ID, false, '0x'); await aaveRouter.triggerCooldown({ from: piGov }); await time.increase(cooldownPeriod + 1); @@ -395,7 +398,7 @@ describe('AaveRouter Tests', () => { assert.equal(await piAave.balanceOf(alice), ether(10000)); assert.equal(await piAave.totalSupply(), ether(10000)); - await expectRevert(aaveRouter.poke(false), 'STAKING_IS_NULL'); + await expectRevert(aaveRouter.pokeFromReporter(REPORTER_ID, false, '0x'), 'STAKING_IS_NULL'); }); describe('when interval enabled', () => { @@ -404,7 +407,7 @@ describe('AaveRouter Tests', () => { await aave.transfer(alice, ether(100000), { from: aaveDistributor }); await aave.approve(piAave.address, ether(10000), { from: alice }); await piAave.deposit(ether(10000), { from: alice }); - await aaveRouter.poke(false); + await aaveRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await aave.balanceOf(stakedAave.address), ether(50000)); assert.equal(await aave.balanceOf(piAave.address), ether(2000)); @@ -417,7 +420,7 @@ describe('AaveRouter Tests', () => { await aave.approve(piAave.address, ether(1000), { from: alice }); await piAave.deposit(ether(1000), { from: alice }); - await aaveRouter.poke(false); + await aaveRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await aave.balanceOf(stakedAave.address), ether(50800)); assert.equal(await stakedAave.balanceOf(piAave.address), ether(8800)); @@ -428,7 +431,7 @@ describe('AaveRouter Tests', () => { await time.increase(time.duration.minutes(61)); await piAave.withdraw(ether(1000), { from: alice }); - const res = await aaveRouter.poke(false); + const res = await aaveRouter.pokeFromReporter(REPORTER_ID, false, '0x'); await expectEvent.inTransaction(res.tx, stakedAave, 'Cooldown', { user: piAave.address }); @@ -443,7 +446,7 @@ describe('AaveRouter Tests', () => { await time.increase(cooldownPeriod + 1); await piAave.withdraw(ether(1000), { from: alice }); - await aaveRouter.poke(false); + await aaveRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await aave.balanceOf(stakedAave.address), ether(49200)); assert.equal(await stakedAave.balanceOf(piAave.address), ether(7200)); @@ -454,7 +457,7 @@ describe('AaveRouter Tests', () => { await time.increase(time.duration.minutes(59)); await poke.setMinMaxReportIntervals(time.duration.minutes(59), time.duration.minutes(118)) - await aaveRouter.poke(false); + await aaveRouter.pokeFromReporter(REPORTER_ID, false, '0x'); await aave.approve(piAave.address, ether(1000), { from: alice }); await piAave.deposit(ether(1000), { from: alice }); await expectRevert(aaveRouter.pokeFromReporter('0', false, '0x'), 'MIN_INTERVAL_NOT_REACHED'); @@ -483,11 +486,11 @@ describe('AaveRouter Tests', () => { beforeEach(async () => { await piAave.deposit(ether(1000), { from: alice }); - await aaveRouter.poke(false); + await aaveRouter.pokeFromReporter(REPORTER_ID, false, '0x'); await time.increase(1); await piAave.withdraw(ether(200), { from: alice }); - let res = await aaveRouter.poke(false); + let res = await aaveRouter.pokeFromReporter(REPORTER_ID, false, '0x'); cooldownActivatedAt = parseInt(await getResTimestamp(res)); }); @@ -540,7 +543,7 @@ describe('AaveRouter Tests', () => { await aave.approve(piAave.address, ether(10000), { from: alice }); await piAave.deposit(ether('10000'), { from: alice }); - await aaveRouter.poke(false); + await aaveRouter.pokeFromReporter(REPORTER_ID, false, '0x'); await piAave.transfer(poolA.address, 10, { from: alice }); await piAave.transfer(poolB.address, 20, { from: alice }); @@ -561,7 +564,7 @@ describe('AaveRouter Tests', () => { await increaseTimeTo(increaseTo); } - const claimRes = await aaveRouter.poke(true, { from: bob }); + const claimRes = await aaveRouter.pokeFromReporter(REPORTER_ID, true, '0x', { from: bob }); // The following assertions will fail when running coverage expectEvent(claimRes, 'ClaimRewards', { @@ -608,7 +611,7 @@ describe('AaveRouter Tests', () => { [buildAaveAssetConfigInput(0, '0', stakedAave.address)], { from: emissionManager }, ); - await expectRevert(aaveRouter.poke(true, { from: alice }), 'NOTHING_TO_CLAIM'); + await expectRevert(aaveRouter.pokeFromReporter(REPORTER_ID, true, '0x', { from: alice }), 'NOTHING_TO_CLAIM'); }); it('should revert distributing rewards when missing reward pools config', async () => { @@ -634,7 +637,7 @@ describe('AaveRouter Tests', () => { ); await aaveRouter.migrateToNewRouter(piAave.address, router.address, [], { from: piGov }); await time.increase(1); - await expectRevert(router.poke(true, { from: bob }), 'MISSING_REWARD_POOLS'); + await expectRevert(router.pokeFromReporter(REPORTER_ID, true, '0x', { from: reporter }), 'MISSING_REWARD_POOLS'); }); it('should correctly distribute pvpFee', async () => { @@ -666,8 +669,8 @@ describe('AaveRouter Tests', () => { await aaveRouter.migrateToNewRouter(piAave.address, router.address, [], { from: piGov }); await time.increase(1); - await router.poke(true, { from: bob }); - const res = await router.poke(true, { from: bob }); + await router.pokeFromReporter(REPORTER_ID, true, '0x', { from: reporter }); + const res = await router.pokeFromReporter(REPORTER_ID, true, '0x', { from: bob }); expectEvent(res, 'DistributeRewards', { sender: bob, @@ -735,9 +738,9 @@ describe('AaveRouter Tests', () => { await aave.transfer(alice, ether('10000'), { from: aaveDistributor }); await aave.approve(piAave.address, ether('10000'), { from: alice }); await piAave.deposit(ether('10000'), { from: alice }); - await aaveRouter.poke(false); + await aaveRouter.pokeFromReporter(REPORTER_ID, false, '0x'); - await aaveRouter.poke(false); + await aaveRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await piAave.totalSupply(), ether('10000')); assert.equal(await piAave.balanceOf(alice), ether('10000')); @@ -753,7 +756,7 @@ describe('AaveRouter Tests', () => { await aave.transfer(alice, ether(12300000), { from: aaveDistributor }); await aave.approve(piAave.address, ether(12300000), { from: alice }); await piAave.deposit(ether(12300000), { from: alice }); - await aaveRouter.poke(false); + await aaveRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await stakedAave.balanceOf(piAave.address), ether(9848000)); assert.equal(await aave.balanceOf(piAave.address), ether(2462000)); diff --git a/test/router/implementations/AutoRouter.unit.js b/test/router/implementations/AutoRouter.unit.js index 95833252..501c96e3 100644 --- a/test/router/implementations/AutoRouter.unit.js +++ b/test/router/implementations/AutoRouter.unit.js @@ -25,6 +25,8 @@ const DEAD = '0x000000000000000000000000000000000000dead'; const { web3 } = MockERC20; +const REPORTER_ID = 42; + describe('AutoRouter Tests', () => { let autoOwner, bob, alice, piGov, stub, pvp, pool1, pool2; @@ -145,7 +147,7 @@ describe('AutoRouter Tests', () => { await auto.approve(piAuto.address, ether('10000'), { from: alice }); await piAuto.deposit(ether('10000'), { from: alice }); - await autoRouter.poke(false); + await autoRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await auto.balanceOf(piAuto.address), ether(2000)); assert.equal(await auto.balanceOf(autoStrategy.address), ether(50000)); @@ -260,7 +262,7 @@ describe('AutoRouter Tests', () => { await auto.approve(piAuto.address, ether(10000), { from: alice }); await piAuto.deposit(ether(10000), { from: alice }); - await autoRouter.poke(false); + await autoRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await auto.balanceOf(autoStrategy.address), ether(50000)); assert.equal(await auto.balanceOf(piAuto.address), ether(2000)); @@ -272,7 +274,7 @@ describe('AutoRouter Tests', () => { await auto.approve(piAuto.address, ether(1000), { from: alice }); await piAuto.deposit(ether(1000), { from: alice }); - await autoRouter.poke(false, { from: bob }); + await autoRouter.pokeFromReporter(REPORTER_ID, false, '0x', { from: bob }); assert.equal(await piAuto.balanceOf(alice), ether(11000)); assert.equal(await auto.balanceOf(autoStrategy.address), ether(50800)); @@ -286,7 +288,7 @@ describe('AutoRouter Tests', () => { await time.increase(time.duration.weeks(1)); await piAuto.withdraw(ether(1000), { from: alice }); - await autoRouter.poke(false, { from: bob }); + await autoRouter.pokeFromReporter(REPORTER_ID, false, '0x', { from: bob }); assert.equal(await piAuto.balanceOf(alice), ether(9000)); assert.equal(await auto.balanceOf(autoStrategy.address), ether(49200)); @@ -327,7 +329,7 @@ describe('AutoRouter Tests', () => { await auto.approve(piAuto.address, ether(1000), { from: alice }); await piAuto.deposit(ether(1000), { from: alice }); - await autoRouter.poke(false, { from: bob }); + await autoRouter.pokeFromReporter(REPORTER_ID, false, '0x', { from: bob }); assert.equal(await piAuto.balanceOf(alice), ether(11000)); assert.equal(await auto.balanceOf(autoStrategy.address), ether(80800)); @@ -344,7 +346,7 @@ describe('AutoRouter Tests', () => { await time.increase(time.duration.weeks(1)); await piAuto.withdraw(ether(1000), { from: alice }); - await autoRouter.poke(false, { from: bob }); + await autoRouter.pokeFromReporter(REPORTER_ID, false, '0x', { from: bob }); assert.equal(await piAuto.balanceOf(alice), ether(9000)); assert.equal(await auto.balanceOf(autoStrategy.address), ether(79200)); @@ -370,7 +372,7 @@ describe('AutoRouter Tests', () => { await piAuto.withdraw(ether(1000), { from: alice }); - await expectRevert(autoRouter.poke(false, { from: bob }), 'STAKING_IS_NULL'); + await expectRevert(autoRouter.pokeFromReporter(REPORTER_ID, false, '0x', { from: bob }), 'STAKING_IS_NULL'); assert.equal(await auto.balanceOf(autoStrategy.address), ether(42000)); assert.equal(await autoFarm.stakedWantTokens(0, piAuto.address), ether(0)); @@ -382,7 +384,7 @@ describe('AutoRouter Tests', () => { await time.increase(time.duration.weeks(1)); await autoRouter.setReserveConfig(ether('0.2'), ether('0.01'), ether('0.9'), time.duration.hours(1), { from: piGov }); await poke.setMinMaxReportIntervals(time.duration.hours(1), time.duration.hours(2)); - await autoRouter.poke(false, { from: bob }); + await autoRouter.pokeFromReporter(REPORTER_ID, false, '0x', { from: bob }); }); it('should DO rebalance on deposit if the rebalancing interval has passed', async () => { @@ -438,7 +440,7 @@ describe('AutoRouter Tests', () => { describe('on poke', async () => { it('should do nothing when nothing has changed', async () => { - await autoRouter.poke(false, { from: bob }); + await autoRouter.pokeFromReporter(REPORTER_ID, false, '0x', { from: bob }); assert.equal(await auto.balanceOf(autoStrategy.address), ether(50000)); assert.equal(await autoFarm.stakedWantTokens(0, piAuto.address), ether(8000)); @@ -456,7 +458,7 @@ describe('AutoRouter Tests', () => { assert.equal(await autoRouter.getUnderlyingOnAutoFarm(), ether(8000)); assert.equal(await autoRouter.getPendingRewards(), ether(1000)); - await autoRouter.poke(false, { from: bob }); + await autoRouter.pokeFromReporter(REPORTER_ID, false, '0x', { from: bob }); assert.equal(await auto.balanceOf(autoStrategy.address), ether(51000)); assert.equal(await autoFarm.stakedWantTokens(0, piAuto.address), ether(9000)); @@ -471,7 +473,7 @@ describe('AutoRouter Tests', () => { it('should stake all the underlying tokens with 0 RR', async () => { await autoRouter.setReserveConfig(ether(0), ether('0'), ether('0.5'), 0, { from: piGov }); - await autoRouter.poke(false, { from: bob }); + await autoRouter.pokeFromReporter(REPORTER_ID, false, '0x', { from: bob }); assert.equal(await auto.balanceOf(autoStrategy.address), ether(52000)); assert.equal(await auto.balanceOf(piAuto.address), ether(0)); }) @@ -480,7 +482,7 @@ describe('AutoRouter Tests', () => { await autoRouter.setReserveConfig(ether(1), ether('0'), ether(1), 0, { from: piGov }); await time.increase(time.duration.weeks(1)); - await autoRouter.poke(false, { from: bob }); + await autoRouter.pokeFromReporter(REPORTER_ID, false, '0x', { from: bob }); assert.equal(await auto.balanceOf(autoStrategy.address), ether(42000)); assert.equal(await auto.balanceOf(piAuto.address), ether(10000)); }) @@ -502,7 +504,7 @@ describe('AutoRouter Tests', () => { await auto.approve(piAuto.address, ether('10000'), { from: alice }); await piAuto.deposit(ether('10000'), { from: alice }); - await autoRouter.poke(false); + await autoRouter.pokeFromReporter(REPORTER_ID, false, '0x'); await autoStrategy.earn({ from: autoOwner }); assert.equal(await piAuto.totalSupply(), ether('10000')); @@ -525,7 +527,7 @@ describe('AutoRouter Tests', () => { assert.equal(await autoRouter.getPendingRewards(), ether(320)); assert.equal(await autoRouter.getAutoForShares(ether(320)), ether('332.8')); - let res = await autoRouter.poke(true, { from: bob }); + let res = await autoRouter.pokeFromReporter(REPORTER_ID, true, '0x', { from: bob }); expectEvent(res, 'ClaimRewards', { sender: bob, expectedAutoReward: ether(320), @@ -568,19 +570,19 @@ describe('AutoRouter Tests', () => { }); it('should revert poke if there is no reward available', async () => { - await expectRevert(autoRouter.poke(true, { from: alice }), 'NOTHING_TO_CLAIM'); + await expectRevert(autoRouter.pokeFromReporter(REPORTER_ID, true, '0x', { from: alice }), 'NOTHING_TO_CLAIM'); }); it('should revert poke if there is nothing released', async () => { const scammyChef = await MockAutoMasterChef.new(auto.address, ether(8320)); await autoRouter.setReserveConfig(ether(1), ether(0), ether(1), 0, { from: piGov }); await time.increase(time.duration.weeks(1)); - await autoRouter.poke(false); + await autoRouter.pokeFromReporter(REPORTER_ID, false, '0x'); await autoRouter.setVotingAndStaking(constants.ZERO_ADDRESS, scammyChef.address, { from: piGov }); await autoRouter.setReserveConfig(ether('0.2'), ether('0.1'), ether('0.3'), 0, { from: piGov }); - await autoRouter.poke(false); + await autoRouter.pokeFromReporter(REPORTER_ID, false, '0x'); await auto.transfer(scammyChef.address, ether(1000)); - await expectRevert(autoRouter.poke(true, { from: alice }), 'NOTHING_RELEASED'); + await expectRevert(autoRouter.pokeFromReporter(REPORTER_ID, true, '0x', { from: alice }), 'NOTHING_RELEASED'); }); it('should revert distributing rewards when missing reward pools config', async () => { @@ -608,7 +610,7 @@ describe('AutoRouter Tests', () => { await auto.transfer(autoStrategy.address, ether(2000)); await autoStrategy.earn({ from: autoOwner }); await time.increase(time.duration.weeks(1)); - await expectRevert(router.poke(true, { from: bob }), 'MISSING_REWARD_POOLS'); + await expectRevert(router.pokeFromReporter(REPORTER_ID, true, '0x'), 'MISSING_REWARD_POOLS'); }); }); }); diff --git a/test/router/implementations/BakeryMasterChefRouter.unit.js b/test/router/implementations/BakeryMasterChefRouter.unit.js index e584ae14..be55cda0 100644 --- a/test/router/implementations/BakeryMasterChefRouter.unit.js +++ b/test/router/implementations/BakeryMasterChefRouter.unit.js @@ -17,6 +17,8 @@ WrappedPiErc20.numberFormat = 'String'; const { web3 } = WrappedPiErc20; +const REPORTER_ID = 42; + describe('BakeryMasterChefRouter Tests', () => { let deployer, bob, alice, piGov, stub, pvp, pool1, pool2; @@ -91,7 +93,7 @@ describe('BakeryMasterChefRouter Tests', () => { await bake.approve(piBake.address, ether('10000'), { from: alice }); await piBake.deposit(ether('10000'), { from: alice }); - await myRouter.poke(false); + await myRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await bake.balanceOf(piBake.address), ether(2000)); assert.equal(await bake.balanceOf(bakeryChef.address), ether(8000)); @@ -182,7 +184,7 @@ describe('BakeryMasterChefRouter Tests', () => { await bake.approve(bakeryChef.address, ether('42000'), { from: bob }); await bakeryChef.deposit(bake.address, ether('42000'), { from: bob }); - await myRouter.poke(false); + await myRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await bake.balanceOf(bakeryChef.address), ether(50400)); assert.equal(await bake.balanceOf(piBake.address), ether(2000)); @@ -192,7 +194,7 @@ describe('BakeryMasterChefRouter Tests', () => { assert.equal(await piBake.balanceOf(alice), ether(10000)); await bake.approve(piBake.address, ether(1000), { from: alice }); await piBake.deposit(ether(1000), { from: alice }); - await myRouter.poke(false); + await myRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await piBake.balanceOf(alice), ether(11000)); assert.equal(await bake.balanceOf(bakeryChef.address), ether('52209.523809528000000000')); @@ -205,7 +207,7 @@ describe('BakeryMasterChefRouter Tests', () => { assert.equal(await piBake.balanceOf(alice), ether(10000)); await piBake.withdraw(ether(1000), { from: alice }); - await myRouter.poke(false); + await myRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await piBake.balanceOf(alice), ether(9000)); assert.equal(await bake.balanceOf(bakeryChef.address), ether('50273.015873016000000000')); @@ -223,7 +225,7 @@ describe('BakeryMasterChefRouter Tests', () => { assert.equal(await piBake.balanceOf(alice), ether(10000)); assert.equal(await piBake.totalSupply(), ether(10000)); await piBake.withdraw(ether(1000), { from: alice }); - await expectRevert(myRouter.poke(false), 'STAKING_IS_NULL'); + await expectRevert(myRouter.pokeFromReporter(REPORTER_ID, false, '0x'), 'STAKING_IS_NULL'); }); describe('when interval enabled', () => { @@ -256,7 +258,7 @@ describe('BakeryMasterChefRouter Tests', () => { await time.increase(time.duration.minutes(61)); await piBake.withdraw(ether(1000), { from: alice }); - await myRouter.poke(false); + await myRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await bake.balanceOf(bakeryChef.address), ether('51282.539682544000000000')); assert.equal((await bakeryChef.poolUserInfoMap(bake.address, piBake.address)).amount, ether(7200)); @@ -283,7 +285,7 @@ describe('BakeryMasterChefRouter Tests', () => { describe('on poke', async () => { it('should do nothing when nothing has changed', async () => { - await myRouter.poke(false, { from: bob }); + await myRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await bake.balanceOf(bakeryChef.address), ether(50400)); assert.equal((await bakeryChef.poolUserInfoMap(bake.address, piBake.address)).amount, ether(8000)); @@ -297,7 +299,7 @@ describe('BakeryMasterChefRouter Tests', () => { assert.equal((await bakeryChef.poolUserInfoMap(bake.address, piBake.address)).amount, ether(8000)); assert.equal(await bake.balanceOf(piBake.address), ether(3000)); - await myRouter.poke(false, { from: bob }); + await myRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await bake.balanceOf(bakeryChef.address), ether('51873.015873016000000000')); assert.equal((await bakeryChef.poolUserInfoMap(bake.address, piBake.address)).amount, ether(8800)); @@ -308,7 +310,7 @@ describe('BakeryMasterChefRouter Tests', () => { it('should stake all the underlying tokens with 0 RR', async () => { await myRouter.setReserveConfig(ether(0), ether(0), ether(1), 0, { from: piGov }); - await myRouter.poke(false, { from: bob }); + await myRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await bake.balanceOf(bakeryChef.address), ether('53073.015873016000000000')); assert.equal(await bake.balanceOf(piBake.address), ether(0)); }); @@ -316,7 +318,7 @@ describe('BakeryMasterChefRouter Tests', () => { it('should keep all the underlying tokens on piToken with 1 RR', async () => { await myRouter.setReserveConfig(ether(1), ether(0), ether(1), 0, { from: piGov }); - await myRouter.poke(false, { from: bob }); + await myRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await bake.balanceOf(bakeryChef.address), ether('43073.015873016000000000')); assert.equal(await bake.balanceOf(piBake.address), ether(10000)); }); @@ -339,7 +341,7 @@ describe('BakeryMasterChefRouter Tests', () => { await bake.approve(piBake.address, ether('10000'), { from: alice }); await piBake.deposit(ether('10000'), { from: alice }); - await myRouter.poke(false); + await myRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await piBake.totalSupply(), ether('10000')); assert.equal(await piBake.balanceOf(alice), ether('10000')); @@ -355,7 +357,7 @@ describe('BakeryMasterChefRouter Tests', () => { assert.equal(await myRouter.getUnderlyingStaked(), ether(8000)); assert.equal(await myRouter.getPendingRewards(), ether(960)); - let res = await myRouter.poke(true, { from: bob }); + let res = await myRouter.pokeFromReporter(REPORTER_ID, true, '0x', { from: bob }); expectEvent(res, 'DistributeRewards', { sender: bob, @@ -395,15 +397,15 @@ describe('BakeryMasterChefRouter Tests', () => { it('should revert poke if there is nothing released', async () => { const dishonestChef = await MockBakeryMasterChef.new(bake.address); await myRouter.setReserveConfig(ether(1), ether(0), ether(1), 0, { from: piGov }); - await myRouter.poke(false); + await myRouter.pokeFromReporter(REPORTER_ID, false, '0x'); await myRouter.setVotingAndStaking(constants.ZERO_ADDRESS, dishonestChef.address, { from: piGov }); await myRouter.setReserveConfig(ether('0.2'), ether('0.1'), ether('0.3'), 0, { from: piGov }); // there are still some rewards from rebalancing pokes - await myRouter.poke(true, { from: alice }); + await myRouter.pokeFromReporter(REPORTER_ID, true, '0x'); // and now there are no rewards - await expectRevert(myRouter.poke(true, { from: alice }), 'NO_PENDING_REWARD'); + await expectRevert(myRouter.pokeFromReporter(REPORTER_ID, true, '0x'), 'NO_PENDING_REWARD'); }); it('should revert distributing rewards when missing reward pools config', async () => { @@ -428,7 +430,7 @@ describe('BakeryMasterChefRouter Tests', () => { await myRouter.migrateToNewRouter(piBake.address, router.address, [], { from: piGov }); await bake.transfer(bakeryChef.address, ether(2000)); await time.increase(1); - await expectRevert(router.poke(true, { from: bob }), 'MISSING_REWARD_POOLS'); + await expectRevert(router.pokeFromReporter(REPORTER_ID, true, '0x'), 'MISSING_REWARD_POOLS'); }); }); }); diff --git a/test/router/implementations/MDXMasterChefRouter.unit.js b/test/router/implementations/MDXMasterChefRouter.unit.js index 31ccc803..4c620a0a 100644 --- a/test/router/implementations/MDXMasterChefRouter.unit.js +++ b/test/router/implementations/MDXMasterChefRouter.unit.js @@ -17,6 +17,8 @@ WrappedPiErc20.numberFormat = 'String'; const { web3 } = WrappedPiErc20; +const REPORTER_ID = 42; + describe('MDXMasterChefRouter Tests', () => { let deployer, bob, alice, piGov, stub, pvp, pool1, pool2; @@ -85,7 +87,7 @@ describe('MDXMasterChefRouter Tests', () => { await mdx.approve(piMdx.address, ether('10000'), { from: alice }); await piMdx.deposit(ether('10000'), { from: alice }); - await myRouter.poke(false); + await myRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await mdx.balanceOf(piMdx.address), ether(2000)); assert.equal(await mdx.balanceOf(boardRoomMDX.address), ether(526400)); @@ -177,7 +179,7 @@ describe('MDXMasterChefRouter Tests', () => { await boardRoomMDX.deposit(0, ether('42000'), { from: bob }); - await myRouter.poke(false); + await myRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await mdx.balanceOf(boardRoomMDX.address), ether(518400 + 50000)); assert.equal(await mdx.balanceOf(piMdx.address), ether(2000)); @@ -187,7 +189,7 @@ describe('MDXMasterChefRouter Tests', () => { assert.equal(await piMdx.balanceOf(alice), ether(10000)); await mdx.approve(piMdx.address, ether(1000), { from: alice }); await piMdx.deposit(ether(1000), { from: alice }); - await myRouter.poke(false); + await myRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await piMdx.balanceOf(alice), ether(11000)); assert.equal(await mdx.balanceOf(boardRoomMDX.address), ether('569194.240000000000000000')); @@ -200,7 +202,7 @@ describe('MDXMasterChefRouter Tests', () => { assert.equal(await piMdx.balanceOf(alice), ether(10000)); await piMdx.withdraw(ether(1000), { from: alice }); - await myRouter.poke(false); + await myRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await piMdx.balanceOf(alice), ether(9000)); assert.equal(await mdx.balanceOf(boardRoomMDX.address), ether('567596.160000000000000000')); @@ -218,7 +220,7 @@ describe('MDXMasterChefRouter Tests', () => { assert.equal(await piMdx.balanceOf(alice), ether(10000)); assert.equal(await piMdx.totalSupply(), ether(10000)); await piMdx.withdraw(ether(1000), { from: alice }); - await expectRevert(myRouter.poke(false), 'STAKING_IS_NULL'); + await expectRevert(myRouter.pokeFromReporter(REPORTER_ID, false, '0x'), 'STAKING_IS_NULL'); }); describe('when interval enabled', () => { @@ -251,7 +253,7 @@ describe('MDXMasterChefRouter Tests', () => { await time.increase(time.duration.minutes(61)); await piMdx.withdraw(ether(1000), { from: alice }); - await myRouter.poke(false); + await myRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await mdx.balanceOf(boardRoomMDX.address), ether('567590.400000000000000000')); assert.equal((await boardRoomMDX.userInfo(0, piMdx.address)).amount, ether(7200)); @@ -278,7 +280,7 @@ describe('MDXMasterChefRouter Tests', () => { describe('on poke', async () => { it('should do nothing when nothing has changed', async () => { - await myRouter.poke(false, { from: bob }); + await myRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await mdx.balanceOf(boardRoomMDX.address), ether(568400)); assert.equal((await boardRoomMDX.userInfo(0, piMdx.address)).amount, ether(8000)); @@ -292,7 +294,7 @@ describe('MDXMasterChefRouter Tests', () => { assert.equal((await boardRoomMDX.userInfo(0, piMdx.address)).amount, ether(8000)); assert.equal(await mdx.balanceOf(piMdx.address), ether(3000)); - await myRouter.poke(false, { from: bob }); + await myRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await mdx.balanceOf(boardRoomMDX.address), ether('569196.160000000000000000')); assert.equal((await boardRoomMDX.userInfo(0, piMdx.address)).amount, ether(8800)); @@ -303,7 +305,7 @@ describe('MDXMasterChefRouter Tests', () => { it('should stake all the underlying tokens with 0 RR', async () => { await myRouter.setReserveConfig(ether(0), ether(0), ether(1), 0, { from: piGov }); - await myRouter.poke(false, { from: bob }); + await myRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await mdx.balanceOf(boardRoomMDX.address), ether('570396.160000000000000000')); assert.equal(await mdx.balanceOf(piMdx.address), ether(0)); }); @@ -311,7 +313,7 @@ describe('MDXMasterChefRouter Tests', () => { it('should keep all the underlying tokens on piToken with 1 RR', async () => { await myRouter.setReserveConfig(ether(1), ether(0), ether(1), 0, { from: piGov }); - await myRouter.poke(false, { from: bob }); + await myRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await mdx.balanceOf(boardRoomMDX.address), ether('560396.160000000000000000')); assert.equal(await mdx.balanceOf(piMdx.address), ether(10000)); }); @@ -334,7 +336,7 @@ describe('MDXMasterChefRouter Tests', () => { await mdx.approve(piMdx.address, ether('10000'), { from: alice }); await piMdx.deposit(ether('10000'), { from: alice }); - await myRouter.poke(false); + await myRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await piMdx.totalSupply(), ether('10000')); assert.equal(await piMdx.balanceOf(alice), ether('10000')); @@ -350,7 +352,7 @@ describe('MDXMasterChefRouter Tests', () => { assert.equal(await myRouter.getUnderlyingStaked(), ether(8000)); assert.equal(await myRouter.getPendingRewards(), ether(36)); - let res = await myRouter.poke(true, { from: bob }); + let res = await myRouter.pokeFromReporter(REPORTER_ID, true, '0x', { from: bob }); expectEvent(res, 'DistributeRewards', { sender: bob, @@ -390,15 +392,15 @@ describe('MDXMasterChefRouter Tests', () => { it('should revert poke if there is nothing released', async () => { const dishonestChef = await MockGeneralMasterChef.new(mdx.address); await myRouter.setReserveConfig(ether(1), ether(0), ether(1), 0, { from: piGov }); - await myRouter.poke(false); + await myRouter.pokeFromReporter(REPORTER_ID, false, '0x'); await myRouter.setVotingAndStaking(constants.ZERO_ADDRESS, dishonestChef.address, { from: piGov }); await myRouter.setReserveConfig(ether('0.2'), ether(0), ether(1), 0, { from: piGov }); // there are still some rewards from rebalancing pokes - await myRouter.poke(true, { from: alice }); + await myRouter.pokeFromReporter(REPORTER_ID, true, '0x'); // and now there are no rewards - await expectRevert(myRouter.poke(true, { from: alice }), 'NO_PENDING_REWARD'); + await expectRevert(myRouter.pokeFromReporter(REPORTER_ID, true, '0x'), 'NO_PENDING_REWARD'); }); it('should revert distributing rewards when missing reward pools config', async () => { @@ -423,7 +425,7 @@ describe('MDXMasterChefRouter Tests', () => { await myRouter.migrateToNewRouter(piMdx.address, router.address, [], { from: piGov }); await mdx.transfer(boardRoomMDX.address, ether(2000)); await time.increase(1); - await expectRevert(router.poke(true, { from: bob }), 'MISSING_REWARD_POOLS'); + await expectRevert(router.pokeFromReporter(REPORTER_ID, true, '0x'), 'MISSING_REWARD_POOLS'); }); }); }); diff --git a/test/router/implementations/PancakeMasterChefRouter.unit.js b/test/router/implementations/PancakeMasterChefRouter.unit.js index 0d48404b..8e6a8db7 100644 --- a/test/router/implementations/PancakeMasterChefRouter.unit.js +++ b/test/router/implementations/PancakeMasterChefRouter.unit.js @@ -19,6 +19,8 @@ WrappedPiErc20.numberFormat = 'String'; const { web3 } = MockERC20; +const REPORTER_ID = 42; + describe('PancakeMasterChefRouter Tests', () => { let deployer, bob, alice, piGov, stub, pvp, pool1, pool2; @@ -83,7 +85,7 @@ describe('PancakeMasterChefRouter Tests', () => { await cake.approve(piCake.address, ether('10000'), { from: alice }); await piCake.deposit(ether('10000'), { from: alice }); - await myRouter.poke(false); + await myRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await cake.balanceOf(piCake.address), ether(2000)); assert.equal(await cake.balanceOf(masterChef.address), ether(8000)); @@ -174,7 +176,7 @@ describe('PancakeMasterChefRouter Tests', () => { await cake.approve(masterChef.address, ether('42000'), { from: bob }); await masterChef.enterStaking(ether('42000'), { from: bob }); - await myRouter.poke(false); + await myRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await cake.balanceOf(masterChef.address), ether(50000)); assert.equal(await cake.balanceOf(piCake.address), ether(2000)); @@ -184,7 +186,7 @@ describe('PancakeMasterChefRouter Tests', () => { assert.equal(await piCake.balanceOf(alice), ether(10000)); await cake.approve(piCake.address, ether(1000), { from: alice }); await piCake.deposit(ether(1000), { from: alice }); - await myRouter.poke(false); + await myRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await piCake.balanceOf(alice), ether(11000)); assert.equal(await cake.balanceOf(masterChef.address), ether(50800)); @@ -197,7 +199,7 @@ describe('PancakeMasterChefRouter Tests', () => { assert.equal(await piCake.balanceOf(alice), ether(10000)); await piCake.withdraw(ether(1000), { from: alice }); - await myRouter.poke(false); + await myRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await piCake.balanceOf(alice), ether(9000)); assert.equal(await cake.balanceOf(masterChef.address), ether(49200)); @@ -215,7 +217,7 @@ describe('PancakeMasterChefRouter Tests', () => { assert.equal(await piCake.balanceOf(alice), ether(10000)); assert.equal(await piCake.totalSupply(), ether(10000)); await piCake.withdraw(ether(1000), { from: alice }); - await expectRevert(myRouter.poke(false), 'STAKING_IS_NULL'); + await expectRevert(myRouter.pokeFromReporter(REPORTER_ID, false, '0x'), 'STAKING_IS_NULL'); }); describe('when interval enabled', () => { @@ -248,7 +250,7 @@ describe('PancakeMasterChefRouter Tests', () => { await time.increase(time.duration.minutes(61)); await piCake.withdraw(ether(1000), { from: alice }); - await myRouter.poke(false); + await myRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await cake.balanceOf(masterChef.address), ether(49200)); assert.equal((await masterChef.userInfo(0, piCake.address)).amount, ether(7200)); @@ -275,7 +277,7 @@ describe('PancakeMasterChefRouter Tests', () => { describe('on poke', async () => { it('should do nothing when nothing has changed', async () => { - await myRouter.poke(false, { from: bob }); + await myRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await cake.balanceOf(masterChef.address), ether(50000)); assert.equal((await masterChef.userInfo(0, piCake.address)).amount, ether(8000)); @@ -289,7 +291,7 @@ describe('PancakeMasterChefRouter Tests', () => { assert.equal((await masterChef.userInfo(0, piCake.address)).amount, ether(8000)); assert.equal(await cake.balanceOf(piCake.address), ether(3000)); - await myRouter.poke(false, { from: bob }); + await myRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await cake.balanceOf(masterChef.address), ether(50800)); assert.equal((await masterChef.userInfo(0, piCake.address)).amount, ether(8800)); @@ -300,7 +302,7 @@ describe('PancakeMasterChefRouter Tests', () => { it('should stake all the underlying tokens with 0 RR', async () => { await myRouter.setReserveConfig(ether(0), ether(0), ether(1), 0, { from: piGov }); - await myRouter.poke(false, { from: bob }); + await myRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await cake.balanceOf(masterChef.address), ether(52000)); assert.equal(await cake.balanceOf(piCake.address), ether(0)); }); @@ -308,7 +310,7 @@ describe('PancakeMasterChefRouter Tests', () => { it('should keep all the underlying tokens on piToken with 1 RR', async () => { await myRouter.setReserveConfig(ether(1), ether(0), ether(1), 0, { from: piGov }); - await myRouter.poke(false, { from: bob }); + await myRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await cake.balanceOf(masterChef.address), ether(42000)); assert.equal(await cake.balanceOf(piCake.address), ether(10000)); }); @@ -331,7 +333,7 @@ describe('PancakeMasterChefRouter Tests', () => { await cake.approve(piCake.address, ether('10000'), { from: alice }); await piCake.deposit(ether('10000'), { from: alice }); - await myRouter.poke(false); + await myRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await piCake.totalSupply(), ether('10000')); assert.equal(await piCake.balanceOf(alice), ether('10000')); @@ -350,7 +352,7 @@ describe('PancakeMasterChefRouter Tests', () => { assert.equal(await myRouter.getUnderlyingStaked(), ether(8000)); assert.equal(await myRouter.getPendingRewards(), ether('47.996454152000000000')); - let res = await myRouter.poke(true, { from: bob }); + let res = await myRouter.pokeFromReporter(REPORTER_ID, true, '0x', { from: bob }); expectEvent(res, 'DistributeRewards', { sender: bob, @@ -390,11 +392,11 @@ describe('PancakeMasterChefRouter Tests', () => { it('should revert poke if there is nothing released', async () => { const dishonestChef = await MockPancakeMasterChef.new(cake.address); await myRouter.setReserveConfig(ether(1), ether(0), ether(1), 0, { from: piGov }); - await myRouter.poke(false); + await myRouter.pokeFromReporter(REPORTER_ID, false, '0x'); await myRouter.setVotingAndStaking(constants.ZERO_ADDRESS, dishonestChef.address, { from: piGov }); await myRouter.setReserveConfig(ether('0.2'), ether('0.02'), ether('0.3'), 0, { from: piGov }); - await myRouter.poke(true); - await expectRevert(myRouter.poke(true, { from: alice }), 'NO_PENDING_REWARD'); + await myRouter.pokeFromReporter(REPORTER_ID, true, '0x'); + await expectRevert(myRouter.pokeFromReporter(REPORTER_ID, true, '0x'), 'NO_PENDING_REWARD'); }); it('should revert distributing rewards when missing reward pools config', async () => { @@ -419,7 +421,7 @@ describe('PancakeMasterChefRouter Tests', () => { await myRouter.migrateToNewRouter(piCake.address, router.address, [], { from: piGov }); await cake.transfer(masterChef.address, ether(2000)); await time.increase(1); - await expectRevert(router.poke(true, { from: bob }), 'MISSING_REWARD_POOLS'); + await expectRevert(router.pokeFromReporter(REPORTER_ID, true, '0x'), 'MISSING_REWARD_POOLS'); }); }); }); diff --git a/test/router/implementations/SushiRouter.stories.js b/test/router/implementations/SushiRouter.stories.js index cad9bb85..3ef26a92 100644 --- a/test/router/implementations/SushiRouter.stories.js +++ b/test/router/implementations/SushiRouter.stories.js @@ -17,6 +17,8 @@ SushiBar.numberFormat = 'String'; const { web3 } = MockERC20; +const REPORTER_ID = 42; + describe('SushiRouter Stories', () => { let alice, bob, charlie, piGov, stub, pvp; @@ -98,7 +100,7 @@ describe('SushiRouter Stories', () => { await sushi.approve(piSushi.address, ether(125), { from: alice }); await piSushi.deposit(ether(125), { from: alice }); - await sushiRouter.poke(false); + await sushiRouter.pokeFromReporter(REPORTER_ID, false, '0x'); // assertions assert.equal(await piSushi.totalSupply(), ether(125)); @@ -120,7 +122,7 @@ describe('SushiRouter Stories', () => { await sushi.approve(piSushi.address, ether(250), { from: bob }); await piSushi.deposit(ether(250), { from: bob }); - await sushiRouter.poke(false); + await sushiRouter.pokeFromReporter(REPORTER_ID, false, '0x'); // assertions assert.equal(await piSushi.totalSupply(), ether(375)); @@ -190,7 +192,7 @@ describe('SushiRouter Stories', () => { await sushi.approve(piSushi.address, ether(60), { from: alice }); await piSushi.deposit(ether(60), { from: alice }); - await sushiRouter.poke(false); + await sushiRouter.pokeFromReporter(REPORTER_ID, false, '0x'); // assertions assert.equal(await piSushi.totalSupply(), ether(435)); @@ -213,7 +215,7 @@ describe('SushiRouter Stories', () => { /////////////////////////////////////////// // Step #8. Bob router withdrawal 100 SUSHI await sushiRouter.setReserveConfig(ether('0.4'), ether('0.1'), ether('0.5'),'0', {from: piGov}) - await sushiRouter.poke(false); + await sushiRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await sushi.balanceOf(piSushi.address), '173999999999999999999'); assert.equal(await sushi.balanceOf(xSushi.address), '811000000000000000001'); @@ -223,7 +225,7 @@ describe('SushiRouter Stories', () => { await piSushi.withdraw(ether(100), { from: bob }); await sushiRouter.setReserveConfig(ether('0.2'), ether('0.1'), ether('0.5'), '0', {from: piGov}) - await sushiRouter.poke(false); + await sushiRouter.pokeFromReporter(REPORTER_ID, false, '0x'); // assertions assert.equal(await piSushi.totalSupply(), ether(335)); @@ -248,7 +250,7 @@ describe('SushiRouter Stories', () => { assert.equal(await sushiRouter.getSushiForXSushi(await xSushi.balanceOf(piSushi.address)), '332285714285714285712'); await piSushi.transfer(pool.address, ether(1), {from: alice}) - await sushiRouter.poke(true, { from: charlie }); + await sushiRouter.pokeFromReporter(REPORTER_ID, true, '0x'); assert.equal(await sushiRouter.getSushiForXSushi(await xSushi.balanceOf(piSushi.address)), '268000000000000000001'); @@ -297,12 +299,12 @@ describe('SushiRouter Stories', () => { await pool.transfer(piSushi.address, alice, ether(1)); await sushiRouter.setReserveConfig(ether('0.8'), ether('0.1'), ether('0.9'), '0', {from: piGov}) - await sushiRouter.poke(false); + await sushiRouter.pokeFromReporter(REPORTER_ID, false, '0x'); await piSushi.withdraw(ether(185), { from: alice }); await sushiRouter.setReserveConfig(ether('0.2'), ether('0.1'), ether('0.5'), '0', {from: piGov}) - await sushiRouter.poke(false); + await sushiRouter.pokeFromReporter(REPORTER_ID, false, '0x'); // assertions assert.equal(await piSushi.totalSupply(), '204642857142857142855'); @@ -347,7 +349,7 @@ describe('SushiRouter Stories', () => { ////////////////////////////////////////////////////////////////////////////////// // Step #13. Bob router withdrawal 150 SUSHI - 5 wei await sushiRouter.setReserveConfig(ether(1), ether('0.5'), ether(1), '0', {from: piGov}) - await sushiRouter.poke(false); + await sushiRouter.pokeFromReporter(REPORTER_ID, false, '0x'); await piSushi.withdraw('149999999999999999995', { from: bob }); // await pool.transfer(piSushi.address, alice, ether(1)); diff --git a/test/router/implementations/SushiRouter.unit.js b/test/router/implementations/SushiRouter.unit.js index b0db1e0f..9d1b9e72 100644 --- a/test/router/implementations/SushiRouter.unit.js +++ b/test/router/implementations/SushiRouter.unit.js @@ -18,6 +18,8 @@ SushiBar.numberFormat = 'String'; const { web3 } = MockERC20; +const REPORTER_ID = 42; + describe('SushiRouter Tests', () => { let bob, alice, piGov, stub, pvp, pool1, pool2; @@ -79,7 +81,7 @@ describe('SushiRouter Tests', () => { await sushi.approve(piSushi.address, ether('10000'), { from: alice }); await piSushi.deposit(ether('10000'), { from: alice }); - await sushiRouter.poke(false); + await sushiRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await sushi.balanceOf(piSushi.address), ether(2000)); assert.equal(await sushi.balanceOf(xSushi.address), ether(50000)); @@ -190,7 +192,7 @@ describe('SushiRouter Tests', () => { await sushi.approve(piSushi.address, ether(10000), { from: alice }); await piSushi.deposit(ether(10000), { from: alice }); - await sushiRouter.poke(false); + await sushiRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await sushi.balanceOf(xSushi.address), ether(50000)); assert.equal(await sushi.balanceOf(piSushi.address), ether(2000)); @@ -202,7 +204,7 @@ describe('SushiRouter Tests', () => { await sushi.approve(piSushi.address, ether(1000), { from: alice }); await piSushi.deposit(ether(1000), { from: alice }); - await sushiRouter.poke(false, { from: bob }); + await sushiRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await piSushi.balanceOf(alice), ether(11000)); assert.equal(await sushi.balanceOf(xSushi.address), ether(50800)); @@ -215,7 +217,7 @@ describe('SushiRouter Tests', () => { await piSushi.withdraw(ether(1000), { from: alice }); - await sushiRouter.poke(false, { from: bob }); + await sushiRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await piSushi.balanceOf(alice), ether(9000)); assert.equal(await sushi.balanceOf(xSushi.address), ether(49200)); @@ -249,7 +251,7 @@ describe('SushiRouter Tests', () => { await sushi.approve(piSushi.address, ether(1000), { from: alice }); await piSushi.deposit(ether(1000), { from: alice }); - await sushiRouter.poke(false, { from: bob }); + await sushiRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await piSushi.balanceOf(alice), ether(11000)); assert.equal(await sushi.balanceOf(xSushi.address), ether(80800)); @@ -264,7 +266,7 @@ describe('SushiRouter Tests', () => { it('should decrease reserve on withdrawal', async () => { await piSushi.withdraw(ether(1000), { from: alice }); - await sushiRouter.poke(false, { from: bob }); + await sushiRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await piSushi.balanceOf(alice), ether(9000)); assert.equal(await sushi.balanceOf(xSushi.address), ether(79200)); @@ -288,7 +290,7 @@ describe('SushiRouter Tests', () => { await piSushi.withdraw(ether(1000), { from: alice }); - await expectRevert(sushiRouter.poke(false, { from: bob }), 'STAKING_IS_NULL'); + await expectRevert(sushiRouter.pokeFromReporter(REPORTER_ID, false, '0x'), 'STAKING_IS_NULL'); assert.equal(await sushi.balanceOf(xSushi.address), ether(42000)); assert.equal(await xSushi.balanceOf(piSushi.address), ether(0)); @@ -299,7 +301,8 @@ describe('SushiRouter Tests', () => { beforeEach(async () => { await sushiRouter.setReserveConfig(ether('0.2'), ether('0.02'), ether('0.3'), time.duration.hours(1), { from: piGov }); await poke.setMinMaxReportIntervals(time.duration.hours(1), time.duration.hours(2)); - await sushiRouter.poke(false, { from: bob }); + await time.increase(time.duration.minutes(61)); + await sushiRouter.pokeFromReporter(REPORTER_ID, false, '0x'); }); it('should DO rebalance on deposit if the rebalancing interval has passed', async () => { @@ -385,7 +388,7 @@ describe('SushiRouter Tests', () => { describe('on poke', async () => { it('should do nothing when nothing has changed', async () => { - await sushiRouter.poke(false, { from: bob }); + await sushiRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await sushi.balanceOf(xSushi.address), ether(50000)); assert.equal(await xSushi.balanceOf(piSushi.address), ether(8000)); @@ -403,7 +406,7 @@ describe('SushiRouter Tests', () => { assert.equal(await sushiRouter.getUnderlyingBackedByXSushi(), ether(8000)); assert.equal(await sushiRouter.getPendingRewards(), addBN(ether(1000), '1')); - await sushiRouter.poke(false, { from: bob }); + await sushiRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await sushi.balanceOf(xSushi.address), ether(51000)); assert.equal(await xSushi.balanceOf(piSushi.address), ether(9000)); @@ -418,7 +421,7 @@ describe('SushiRouter Tests', () => { it('should stake all the underlying tokens with 0 RR', async () => { await sushiRouter.setReserveConfig(ether(0), ether(0), ether(1), 0, { from: piGov }); - await sushiRouter.poke(false, { from: bob }); + await sushiRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await sushi.balanceOf(xSushi.address), ether(52000)); assert.equal(await sushi.balanceOf(piSushi.address), ether(0)); }) @@ -426,7 +429,7 @@ describe('SushiRouter Tests', () => { it('should keep all the underlying tokens on piToken with 1 RR', async () => { await sushiRouter.setReserveConfig(ether(1), ether(0), ether(1), 0, { from: piGov }); - await sushiRouter.poke(false, { from: bob }); + await sushiRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await sushi.balanceOf(xSushi.address), ether(42000)); assert.equal(await sushi.balanceOf(piSushi.address), ether(10000)); }) @@ -448,7 +451,7 @@ describe('SushiRouter Tests', () => { await sushi.approve(piSushi.address, ether('10000'), { from: alice }); await piSushi.deposit(ether('10000'), { from: alice }); - await sushiRouter.poke(false); + await sushiRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await piSushi.totalSupply(), ether('10000')); assert.equal(await piSushi.balanceOf(alice), ether('10000')); @@ -468,7 +471,7 @@ describe('SushiRouter Tests', () => { assert.equal(await sushiRouter.getPendingRewards(), addBN(ether(320), '1')); assert.equal(await sushiRouter.getXSushiForSushi(ether(320)), '307692307692307692307'); - let res = await sushiRouter.poke(true, { from: bob }); + let res = await sushiRouter.pokeFromReporter(REPORTER_ID, true, '0x', { from: bob }); expectEvent(res, 'ClaimRewards', { sender: bob, xSushiBurned: '307692307692307692308', @@ -512,18 +515,18 @@ describe('SushiRouter Tests', () => { }); it('should revert poke if there is no reward available', async () => { - await expectRevert(sushiRouter.poke(true, { from: alice }), 'NOTHING_TO_CLAIM'); + await expectRevert(sushiRouter.pokeFromReporter(REPORTER_ID, true, '0x'), 'NOTHING_TO_CLAIM'); }); it('should revert poke if there is nothing released', async () => { const scammyBar = await MockSushiBar.new(sushi.address); await sushiRouter.setReserveConfig(ether(1), ether(0), ether(1), 0, { from: piGov }); - await sushiRouter.poke(false); + await sushiRouter.pokeFromReporter(REPORTER_ID, false, '0x'); await sushiRouter.setVotingAndStaking(constants.ZERO_ADDRESS, scammyBar.address, { from: piGov }); await sushiRouter.setReserveConfig(ether('0.2'), ether('0.1'), ether('0.2'), 0, { from: piGov }); - await sushiRouter.poke(false); + await sushiRouter.pokeFromReporter(REPORTER_ID, false, '0x'); await sushi.transfer(scammyBar.address, ether(1000)); - await expectRevert(sushiRouter.poke(true, { from: alice }), 'NOTHING_RELEASED'); + await expectRevert(sushiRouter.pokeFromReporter(REPORTER_ID, true, '0x'), 'NOTHING_RELEASED'); }); it('should revert distributing rewards when missing reward pools config', async () => { @@ -550,7 +553,7 @@ describe('SushiRouter Tests', () => { await sushiRouter.migrateToNewRouter(piSushi.address, router.address, [], { from: piGov }); await sushi.transfer(xSushi.address, ether(2000)); await time.increase(1); - await expectRevert(router.poke(true, { from: bob }), 'MISSING_REWARD_POOLS'); + await expectRevert(router.pokeFromReporter(REPORTER_ID, true, '0x'), 'MISSING_REWARD_POOLS'); }); }); }); diff --git a/test/router/implementations/VenusRouter.unit.js b/test/router/implementations/VenusRouter.unit.js index d0be46c3..552480d3 100644 --- a/test/router/implementations/VenusRouter.unit.js +++ b/test/router/implementations/VenusRouter.unit.js @@ -24,6 +24,8 @@ const WhitePaperInterestRateModel = artifactFromBytecode('bsc/WhitePaperInterest const { web3 } = MockERC20; +const REPORTER_ID = 42; + describe('VenusRouter Tests', () => { let bob, alice, charlie, venusOwner, piGov, stub, pvp, pool1, pool2; @@ -187,7 +189,7 @@ describe('VenusRouter Tests', () => { await usdc.approve(piUsdc.address, ether('10000'), { from: alice }); await piUsdc.deposit(ether('10000'), { from: alice }); - await venusRouter.poke(false); + await venusRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await usdc.balanceOf(piUsdc.address), ether(2000)); assert.equal(await usdc.balanceOf(vUsdc.address), ether(50000)); @@ -300,7 +302,7 @@ describe('VenusRouter Tests', () => { await usdc.approve(piUsdc.address, ether(10000), { from: alice }); await piUsdc.deposit(ether(10000), { from: alice }); - await venusRouter.poke(false); + await venusRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await usdc.balanceOf(vUsdc.address), ether(50000)); assert.equal(await usdc.balanceOf(piUsdc.address), ether(2000)); @@ -312,7 +314,7 @@ describe('VenusRouter Tests', () => { await usdc.approve(piUsdc.address, ether(1000), { from: alice }); await piUsdc.deposit(ether(1000), { from: alice }); - await venusRouter.poke(false, { from: bob }); + await venusRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await piUsdc.balanceOf(alice), ether(11000)); assert.equal(await usdc.balanceOf(vUsdc.address), ether(50800)); @@ -325,7 +327,7 @@ describe('VenusRouter Tests', () => { await piUsdc.withdraw(ether(1000), { from: alice }); - await venusRouter.poke(false, { from: bob }); + await venusRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await piUsdc.balanceOf(alice), ether(9000)); assert.equal(await usdc.balanceOf(vUsdc.address), ether(49200)); @@ -361,7 +363,7 @@ describe('VenusRouter Tests', () => { await usdc.approve(piUsdc.address, ether(1000), { from: alice }); await piUsdc.deposit(ether(1000), { from: alice }); - await venusRouter.poke(false, { from: bob }); + await venusRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await piUsdc.balanceOf(alice), ether(11000)); assert.equal(await usdc.balanceOf(vUsdc.address), ether(80800)); @@ -376,7 +378,7 @@ describe('VenusRouter Tests', () => { it('should decrease reserve on withdrawal', async () => { await piUsdc.withdraw(ether(1000), { from: alice }); - await venusRouter.poke(false, { from: bob }); + await venusRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await piUsdc.balanceOf(alice), ether(9000)); assert.equal(await usdc.balanceOf(vUsdc.address), ether(79200)); @@ -400,7 +402,7 @@ describe('VenusRouter Tests', () => { await piUsdc.withdraw(ether(1000), { from: alice }); - await expectRevert(venusRouter.poke(false, { from: bob }), 'STAKING_IS_NULL'); + await expectRevert(venusRouter.pokeFromReporter(REPORTER_ID, false, '0x'), 'STAKING_IS_NULL'); assert.equal(await usdc.balanceOf(vUsdc.address), ether(42000)); assert.equal(await vUsdc.balanceOf(piUsdc.address), ether(0)); @@ -411,7 +413,8 @@ describe('VenusRouter Tests', () => { beforeEach(async () => { await venusRouter.setReserveConfig(ether('0.2'), ether('0.02'), ether('0.3'), time.duration.hours(1), { from: piGov }); await poke.setMinMaxReportIntervals(time.duration.hours(1), time.duration.hours(2)); - await venusRouter.poke(false, { from: bob }); + await time.increase(time.duration.minutes(61)); + await venusRouter.pokeFromReporter(REPORTER_ID, false, '0x'); }); it('should DO rebalance on deposit if the rebalancing interval has passed', async () => { @@ -467,7 +470,7 @@ describe('VenusRouter Tests', () => { describe('on poke', async () => { it('should do nothing when nothing has changed', async () => { - await venusRouter.poke(false, { from: bob }); + await venusRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await usdc.balanceOf(vUsdc.address), ether(50000)); assert.equal(await vUsdc.balanceOf(piUsdc.address), ether(8000)); @@ -485,7 +488,7 @@ describe('VenusRouter Tests', () => { assert.equal(await venusRouter.getUnderlyingBackedByVToken(), ether(8000)); assert.equal(await venusRouter.getPendingInterestReward(), addBN(ether(1000), '1')); - await venusRouter.poke(false, { from: bob }); + await venusRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await usdc.balanceOf(vUsdc.address), ether(51000)); assert.equal(await vUsdc.balanceOf(piUsdc.address), ether(9000)); @@ -500,7 +503,7 @@ describe('VenusRouter Tests', () => { it('should stake all the underlying tokens with 0 RR', async () => { await venusRouter.setReserveConfig(ether(0), ether(0), ether(1), 0, { from: piGov }); - await venusRouter.poke(false, { from: bob }); + await venusRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await usdc.balanceOf(vUsdc.address), ether(52000)); assert.equal(await usdc.balanceOf(piUsdc.address), ether(0)); }); @@ -508,7 +511,7 @@ describe('VenusRouter Tests', () => { it('should keep all the underlying tokens on piToken with 1 RR', async () => { await venusRouter.setReserveConfig(ether(1), ether(0), ether(1), 0, { from: piGov }); - await venusRouter.poke(false, { from: bob }); + await venusRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await usdc.balanceOf(vUsdc.address), ether(42000)); assert.equal(await usdc.balanceOf(piUsdc.address), ether(10000)); }); @@ -530,7 +533,7 @@ describe('VenusRouter Tests', () => { await usdc.approve(piUsdc.address, ether('10000'), { from: alice }); await piUsdc.deposit(ether('10000'), { from: alice }); - await venusRouter.poke(false); + await venusRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await piUsdc.totalSupply(), ether('10000')); assert.equal(await piUsdc.balanceOf(alice), ether('10000')); @@ -554,7 +557,7 @@ describe('VenusRouter Tests', () => { assert.equal(await venusRouter.getPendingInterestReward(), addBN(ether(320), '1')); assert.equal(await venusRouter.getVTokenForToken(ether(320)), '307692307692307692307'); - let res = await venusRouter.poke(true, { from: bob }); + let res = await venusRouter.pokeFromReporter(REPORTER_ID, true, '0x', { from: bob }); expectEvent(res, 'ClaimRewards', { sender: bob, xvsEarned: ether(0), @@ -613,7 +616,7 @@ describe('VenusRouter Tests', () => { assert.equal(await venusRouter.getPendingInterestReward(), ether(0)); assert.equal(await venusRouter.getVTokenForToken(ether(320)), ether(320)); - let res = await venusRouter.poke(true, { from: bob }); + let res = await venusRouter.pokeFromReporter(REPORTER_ID, true, '0x', { from: bob }); expectEvent(res, 'ClaimRewards', { sender: bob, xvsEarned: ether(288000), @@ -656,7 +659,7 @@ describe('VenusRouter Tests', () => { }); it('should revert poke if there is no reward available', async () => { - await expectRevert(venusRouter.poke(true, { from: alice }), 'NOTHING_TO_DISTRIBUTE'); + await expectRevert(venusRouter.pokeFromReporter(REPORTER_ID, true, '0x'), 'NOTHING_TO_DISTRIBUTE'); }); it('should revert distributing rewards when missing reward pools config', async () => { @@ -683,7 +686,7 @@ describe('VenusRouter Tests', () => { }); await usdc.transfer(vUsdc.address, ether(2000)); await time.increase(1); - await expectRevert(router.poke(true, { from: bob }), 'MISSING_REWARD_POOLS'); + await expectRevert(router.pokeFromReporter(REPORTER_ID, true, '0x'), 'MISSING_REWARD_POOLS'); }); }); }); diff --git a/test/router/implementations/YearnRouter.test.js b/test/router/implementations/YearnRouter.test.js index 58c21169..46be91af 100644 --- a/test/router/implementations/YearnRouter.test.js +++ b/test/router/implementations/YearnRouter.test.js @@ -21,6 +21,8 @@ MockYearnGovernance.numberFormat = 'String'; const { web3 } = MockERC20; +const REPORTER_ID = 42; + async function buildUniswapPair(weth, yfi, usdc, lpTokensTo) { const factory = await UniswapV2Factory.new(lpTokensTo); const router = await UniswapV2Router02.new(factory.address, weth.address); @@ -115,7 +117,7 @@ describe('YearnRouter Tests', () => { await yfi.transfer(alice, ether('10000')); await yfi.approve(piYfi.address, ether('10000'), { from: alice }); await piYfi.deposit(ether('10000'), { from: alice }); - await yfiRouter.poke(false); + await yfiRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await piYfi.totalSupply(), ether('10000')); assert.equal(await piYfi.balanceOf(alice), ether('10000')); @@ -172,7 +174,7 @@ describe('YearnRouter Tests', () => { await yfi.transfer(alice, ether('10000')); await yfi.approve(piYfi.address, ether('10000'), { from: alice }); await piYfi.deposit(ether('10000'), { from: alice }); - await yfiRouter.poke(false); + await yfiRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await yfi.balanceOf(piYfi.address), ether(2000)); assert.equal(await yfi.balanceOf(yearnGovernance.address), ether(50000)); @@ -308,7 +310,7 @@ describe('YearnRouter Tests', () => { await yfi.transfer(alice, ether(100000)); await yfi.approve(piYfi.address, ether(10000), { from: alice }); const res = await piYfi.deposit(ether(10000), { from: alice }); - await yfiRouter.poke(false); + await yfiRouter.pokeFromReporter(REPORTER_ID, false, '0x'); await getResTimestamp(res); assert.equal(await yfi.balanceOf(yearnGovernance.address), ether(50000)); @@ -319,7 +321,7 @@ describe('YearnRouter Tests', () => { assert.equal(await piYfi.balanceOf(alice), ether(10000)); await yfi.approve(piYfi.address, ether(1000), { from: alice }); await piYfi.deposit(ether(1000), { from: alice }); - await yfiRouter.poke(false); + await yfiRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await piYfi.balanceOf(alice), ether(11000)); assert.equal(await yfi.balanceOf(yearnGovernance.address), ether(50800)); @@ -332,7 +334,7 @@ describe('YearnRouter Tests', () => { assert.equal(await piYfi.balanceOf(alice), ether(10000)); await piYfi.withdraw(ether(1000), { from: alice }); - await yfiRouter.poke(false); + await yfiRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await piYfi.balanceOf(alice), ether(9000)); assert.equal(await yfi.balanceOf(yearnGovernance.address), ether(49200)); @@ -350,7 +352,7 @@ describe('YearnRouter Tests', () => { assert.equal(await piYfi.balanceOf(alice), ether(10000)); assert.equal(await piYfi.totalSupply(), ether(10000)); await piYfi.withdraw(ether(1000), { from: alice }); - await expectRevert(yfiRouter.poke(false), 'STAKING_IS_NULL'); + await expectRevert(yfiRouter.pokeFromReporter(REPORTER_ID, false, '0x'), 'STAKING_IS_NULL'); }); describe('when interval enabled', () => { @@ -383,7 +385,7 @@ describe('YearnRouter Tests', () => { await time.increase(time.duration.minutes(61)); await piYfi.withdraw(ether(1000), { from: alice }); - await yfiRouter.poke(false); + await yfiRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await yfi.balanceOf(yearnGovernance.address), ether(49200)); assert.equal(await yearnGovernance.balanceOf(piYfi.address), ether(7200)); @@ -419,7 +421,7 @@ describe('YearnRouter Tests', () => { it('should not decrease reserve if vote is locked', async () => { await piYfi.withdraw(ether(1000), { from: alice }); - await expectRevert(yfiRouter.poke(false), 'VOTE_LOCK'); + await expectRevert(yfiRouter.pokeFromReporter(REPORTER_ID, false, '0x'), 'VOTE_LOCK'); }); it('should revert if there is not enough funds in reserve', async () => { @@ -429,7 +431,7 @@ describe('YearnRouter Tests', () => { describe('on poke', async () => { it('should do nothing when nothing has changed', async () => { - await yfiRouter.poke(false, { from: bob }); + await yfiRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await yfi.balanceOf(yearnGovernance.address), ether(50000)); assert.equal(await yearnGovernance.balanceOf(piYfi.address), ether(8000)); @@ -443,7 +445,7 @@ describe('YearnRouter Tests', () => { assert.equal(await yearnGovernance.balanceOf(piYfi.address), ether(8000)); assert.equal(await yfi.balanceOf(piYfi.address), ether(3000)); - await yfiRouter.poke(false, { from: bob }); + await yfiRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await yfi.balanceOf(yearnGovernance.address), ether(50800)); assert.equal(await yearnGovernance.balanceOf(piYfi.address), ether(8800)); @@ -454,7 +456,7 @@ describe('YearnRouter Tests', () => { it('should stake all the underlying tokens with 0 RR', async () => { await yfiRouter.setReserveConfig(ether(0), ether(0), ether(1), 0, { from: piGov }); - await yfiRouter.poke(false, { from: bob }); + await yfiRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await yfi.balanceOf(yearnGovernance.address), ether(52000)); assert.equal(await yfi.balanceOf(piYfi.address), ether(0)); }) @@ -462,7 +464,7 @@ describe('YearnRouter Tests', () => { it('should keep all the underlying tokens on piToken with 1 RR', async () => { await yfiRouter.setReserveConfig(ether(1), ether(0), ether(1), 0, { from: piGov }); - await yfiRouter.poke(false, { from: bob }); + await yfiRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await yfi.balanceOf(yearnGovernance.address), ether(42000)); assert.equal(await yfi.balanceOf(piYfi.address), ether(10000)); }) @@ -490,7 +492,7 @@ describe('YearnRouter Tests', () => { await yfi.transfer(alice, ether('10000')); await yfi.approve(piYfi.address, ether('10000'), { from: alice }); await piYfi.deposit(ether('10000'), { from: alice }); - await yfiRouter.poke(false); + await yfiRouter.pokeFromReporter(REPORTER_ID, false, '0x'); assert.equal(await piYfi.totalSupply(), ether('10000')); assert.equal(await piYfi.balanceOf(alice), ether('10000')); @@ -508,7 +510,7 @@ describe('YearnRouter Tests', () => { await yearnGovernance.notifyRewardAmount(ether(2000), { from: rewardDistributor }); await time.increase(time.duration.days(8)); - let res = await yfiRouter.poke(true, { from: bob }); + let res = await yfiRouter.pokeFromReporter(REPORTER_ID, true, '0x', { from: bob }); expectEvent(res, 'ClaimRewards', { sender: bob, yCrvAmount: '1999999999999999464000' @@ -608,7 +610,7 @@ describe('YearnRouter Tests', () => { }); it('should revert distribute rewards() if there is no yCrv on the balance', async () => { - await expectRevert(yfiRouter.poke(true, { from: bob }), 'NO_YCRV_REWARD_ON_PI'); + await expectRevert(yfiRouter.pokeFromReporter(REPORTER_ID, true, '0x'), 'NO_YCRV_REWARD_ON_PI'); }); it('should revert distributing rewards when missing reward pools config', async () => { @@ -640,7 +642,7 @@ describe('YearnRouter Tests', () => { await yfiRouter.migrateToNewRouter(piYfi.address, router.address, [], { from: piGov }); await yearnGovernance.notifyRewardAmount(ether(2000), { from: rewardDistributor }); await time.increase(1); - await expectRevert(router.poke(true, { from: bob }), 'MISSING_REWARD_POOLS'); + await expectRevert(router.pokeFromReporter(REPORTER_ID, true, '0x'), 'MISSING_REWARD_POOLS'); }); it('should revert when missing reward swap path', async () => { @@ -672,7 +674,7 @@ describe('YearnRouter Tests', () => { await yfiRouter.migrateToNewRouter(piYfi.address, router.address, [], { from: piGov }); await yearnGovernance.notifyRewardAmount(ether(2000), { from: rewardDistributor }); await time.increase(1); - await expectRevert(router.poke(true, { from: bob }), 'MISSING_REWARD_SWAP_PATH'); + await expectRevert(router.pokeFromReporter(REPORTER_ID, true, '0x'), 'MISSING_REWARD_SWAP_PATH'); }); }); }); From eab05f5149f26083cbdc2e533ced9db8cce3eb16 Mon Sep 17 00:00:00 2001 From: Poli Paul Date: Tue, 5 Oct 2021 19:27:16 +0200 Subject: [PATCH 23/33] Explicitly specify Pancake pool ID by a constant --- .../implementations/PancakeMasterChefPowerIndexRouter.sol | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/contracts/powerindex-router/implementations/PancakeMasterChefPowerIndexRouter.sol b/contracts/powerindex-router/implementations/PancakeMasterChefPowerIndexRouter.sol index 4a100de0..0be337c0 100644 --- a/contracts/powerindex-router/implementations/PancakeMasterChefPowerIndexRouter.sol +++ b/contracts/powerindex-router/implementations/PancakeMasterChefPowerIndexRouter.sol @@ -12,6 +12,8 @@ import "./AbstractMasterChefIndexRouter.sol"; * To get pending rewards use IPancakeStaking(0x73feaa1ee314f8c655e354234017be2193c9e24e).pendingCake(0, piToken). */ contract PancakeMasterChefIndexRouter is AbstractMasterChefIndexRouter { + uint256 internal constant PANCAKE_POOL_ID = 0; + struct PancakeMasterChefConfig { address cake; } @@ -25,7 +27,7 @@ contract PancakeMasterChefIndexRouter is AbstractMasterChefIndexRouter { /*** VIEWERS ***/ function getPendingRewards() external view returns (uint256 amount) { - return IPancakeMasterChef(staking).pendingCake(0, address(piToken)); + return IPancakeMasterChef(staking).pendingCake(PANCAKE_POOL_ID, address(piToken)); } /*** OVERRIDES ***/ @@ -34,7 +36,7 @@ contract PancakeMasterChefIndexRouter is AbstractMasterChefIndexRouter { if (staking == address(0)) { return 0; } - (uint256 amount, ) = IPancakeMasterChef(staking).userInfo(0, address(piToken)); + (uint256 amount, ) = IPancakeMasterChef(staking).userInfo(PANCAKE_POOL_ID, address(piToken)); return amount; } From 7b6ecc978d38ce74c8ef3f5394c5f283342cb61d Mon Sep 17 00:00:00 2001 From: Poli Paul Date: Tue, 5 Oct 2021 19:52:05 +0200 Subject: [PATCH 24/33] Use safeTransfer for the calls proxied by piToken --- .../powerindex-router/PowerIndexBasicRouter.sol | 13 +++++++++++++ .../AbstractMasterChefIndexRouter.sol | 4 ++-- .../implementations/AutoPowerIndexRouter.sol | 2 +- .../implementations/SushiPowerIndexRouter.sol | 2 +- .../implementations/VenusVBep20SupplyRouter.sol | 13 ++++--------- .../implementations/YearnPowerIndexRouter.sol | 4 ++-- 6 files changed, 23 insertions(+), 15 deletions(-) diff --git a/contracts/powerindex-router/PowerIndexBasicRouter.sol b/contracts/powerindex-router/PowerIndexBasicRouter.sol index a8380ed2..38a60838 100644 --- a/contracts/powerindex-router/PowerIndexBasicRouter.sol +++ b/contracts/powerindex-router/PowerIndexBasicRouter.sol @@ -486,6 +486,19 @@ contract PowerIndexBasicRouter is PowerIndexBasicRouterInterface, PowerIndexNaiv ); } + function _safeTransfer( + IERC20 _token, + address _to, + uint256 _value + ) internal { + bytes memory response = piToken.callExternal(address(_token), IERC20.transfer.selector, abi.encode(_to, _value), 0); + + if (response.length > 0) { + // Return data is optional + require(abi.decode(response, (bool)), "ERC20 operation did not succeed"); + } + } + function _reward( uint256 _reporterId, uint256 _gasStart, diff --git a/contracts/powerindex-router/implementations/AbstractMasterChefIndexRouter.sol b/contracts/powerindex-router/implementations/AbstractMasterChefIndexRouter.sol index 2ce9b0db..6550dc89 100644 --- a/contracts/powerindex-router/implementations/AbstractMasterChefIndexRouter.sol +++ b/contracts/powerindex-router/implementations/AbstractMasterChefIndexRouter.sol @@ -90,7 +90,7 @@ abstract contract AbstractMasterChefIndexRouter is PowerIndexBasicRouter { _stakeImpl(_amount); uint256 receivedReward = TOKEN.balanceOf(address(piToken)).sub(tokenBefore.sub(_amount)); - piToken.callExternal(address(TOKEN), IERC20.transfer.selector, abi.encode(address(this), receivedReward), 0); + _safeTransfer(TOKEN, address(this), receivedReward); emit Stake(msg.sender, _amount, receivedReward); } @@ -101,7 +101,7 @@ abstract contract AbstractMasterChefIndexRouter is PowerIndexBasicRouter { _redeemImpl(_amount); uint256 receivedReward = TOKEN.balanceOf(address(piToken)).sub(tokenBefore).sub(_amount); - piToken.callExternal(address(TOKEN), IERC20.transfer.selector, abi.encode(address(this), receivedReward), 0); + _safeTransfer(TOKEN, address(this), receivedReward); emit Redeem(msg.sender, _amount, receivedReward); } diff --git a/contracts/powerindex-router/implementations/AutoPowerIndexRouter.sol b/contracts/powerindex-router/implementations/AutoPowerIndexRouter.sol index eefbf438..96979211 100644 --- a/contracts/powerindex-router/implementations/AutoPowerIndexRouter.sol +++ b/contracts/powerindex-router/implementations/AutoPowerIndexRouter.sol @@ -57,7 +57,7 @@ contract AutoPowerIndexRouter is PowerIndexBasicRouter { require(released > 0, "NOTHING_RELEASED"); // Step #2. Transfer the claimed AUTO to the router - piToken.callExternal(address(AUTO), IERC20.transfer.selector, abi.encode(address(this), released), 0); + _safeTransfer(AUTO, address(this), released); emit ClaimRewards(msg.sender, rewardsPending, released); } diff --git a/contracts/powerindex-router/implementations/SushiPowerIndexRouter.sol b/contracts/powerindex-router/implementations/SushiPowerIndexRouter.sol index 64265c2b..560325d6 100644 --- a/contracts/powerindex-router/implementations/SushiPowerIndexRouter.sol +++ b/contracts/powerindex-router/implementations/SushiPowerIndexRouter.sol @@ -57,7 +57,7 @@ contract SushiPowerIndexRouter is PowerIndexBasicRouter { require(released > 0, "NOTHING_RELEASED"); // Step #2. Transfer the claimed SUSHI to the router - piToken.callExternal(address(SUSHI), SUSHI.transfer.selector, abi.encode(address(this), released), 0); + _safeTransfer(SUSHI, address(this), released); emit ClaimRewards(msg.sender, xSushiToBurn, rewardsPending, released); } diff --git a/contracts/powerindex-router/implementations/VenusVBep20SupplyRouter.sol b/contracts/powerindex-router/implementations/VenusVBep20SupplyRouter.sol index ea09b4ed..77fac527 100644 --- a/contracts/powerindex-router/implementations/VenusVBep20SupplyRouter.sol +++ b/contracts/powerindex-router/implementations/VenusVBep20SupplyRouter.sol @@ -60,7 +60,7 @@ contract VenusVBep20SupplyRouter is PowerIndexBasicRouter { ); uint256 xvsEarned = XVS.balanceOf(address(piToken)).sub(xvsBefore); if (xvsEarned > 0) { - piToken.callExternal(address(XVS), IERC20.transfer.selector, abi.encode(address(this), xvsEarned), 0); + _safeTransfer(XVS, address(this), xvsEarned); } // #2. Redeem underlying interest @@ -74,12 +74,7 @@ contract VenusVBep20SupplyRouter is PowerIndexBasicRouter { } if (underlyingEarned > 0) { - piToken.callExternal( - address(UNDERLYING), - IERC20.transfer.selector, - abi.encode(address(this), underlyingEarned), - 0 - ); + _safeTransfer(UNDERLYING, address(this), underlyingEarned); } // #3. Emit claim results @@ -262,7 +257,7 @@ contract VenusVBep20SupplyRouter is PowerIndexBasicRouter { _callCompStaking(VBep20Interface(0).mint.selector, abi.encode(_amount)); uint256 receivedReward = UNDERLYING.balanceOf(address(piToken)).sub(underlyingBefore.sub(_amount)); - piToken.callExternal(address(UNDERLYING), IERC20.transfer.selector, abi.encode(address(this), receivedReward), 0); + _safeTransfer(UNDERLYING, address(this), receivedReward); emit Stake(msg.sender, _amount, receivedReward); } @@ -273,7 +268,7 @@ contract VenusVBep20SupplyRouter is PowerIndexBasicRouter { uint256 underlyingBefore = UNDERLYING.balanceOf(address(piToken)); _callCompStaking(VBep20Interface(0).redeemUnderlying.selector, abi.encode(_amount)); uint256 receivedReward = UNDERLYING.balanceOf(address(piToken)).sub(underlyingBefore).sub(_amount); - piToken.callExternal(address(UNDERLYING), IERC20.transfer.selector, abi.encode(address(this), receivedReward), 0); + _safeTransfer(UNDERLYING, address(this), receivedReward); emit Redeem(msg.sender, _amount, receivedReward); } diff --git a/contracts/powerindex-router/implementations/YearnPowerIndexRouter.sol b/contracts/powerindex-router/implementations/YearnPowerIndexRouter.sol index f7f544c0..90bbe677 100644 --- a/contracts/powerindex-router/implementations/YearnPowerIndexRouter.sol +++ b/contracts/powerindex-router/implementations/YearnPowerIndexRouter.sol @@ -74,7 +74,7 @@ contract YearnPowerIndexRouter is PowerIndexBasicRouter { require(yCrvReward > 0, "NO_YCRV_REWARD_ON_PI"); // Step #2. Transfer yCrv reward to the router - piToken.callExternal(address(YCRV), YCRV.transfer.selector, abi.encode(address(this), yCrvReward), 0); + _safeTransfer(YCRV, address(this), yCrvReward); emit ClaimRewards(msg.sender, yCrvReward); } @@ -92,7 +92,7 @@ contract YearnPowerIndexRouter is PowerIndexBasicRouter { // Step #2. Transfer yCrv reward to the router uint256 yCrvReward = YCRV.balanceOf(address(piToken)); if (yCrvReward > 0) { - piToken.callExternal(address(YCRV), YCRV.transfer.selector, abi.encode(address(this), yCrvReward), 0); + _safeTransfer(YCRV, address(this), yCrvReward); } emit Exit(msg.sender, yfiBalanceAfter - yfiBalanceBefore, yCrvReward); From 7bd309754f47aae1f4695d035c317b169e65ec72 Mon Sep 17 00:00:00 2001 From: Poli Paul Date: Mon, 11 Oct 2021 17:17:34 +0200 Subject: [PATCH 25/33] Routers: Mark withdrawAmount as deprecated --- contracts/powerindex-router/PowerIndexBasicRouter.sol | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/contracts/powerindex-router/PowerIndexBasicRouter.sol b/contracts/powerindex-router/PowerIndexBasicRouter.sol index 38a60838..9ab36c30 100644 --- a/contracts/powerindex-router/PowerIndexBasicRouter.sol +++ b/contracts/powerindex-router/PowerIndexBasicRouter.sol @@ -420,8 +420,7 @@ contract PowerIndexBasicRouter is PowerIndexBasicRouterInterface, PowerIndexNaiv * @param _reserveRatioPct The reserve ratio in %, 1 ether == 100 ether * @param _leftOnPiToken The amount of origin tokens left on the piToken (WrappedPiErc20) contract * @param _stakedBalance The amount of original tokens staked on the staking contract - * @param _withdrawAmount The amount to be withdrawn within the current transaction - * (could be negative in a case of deposit) + * @param _withdrawAmount The amount to be withdrawn within the current transaction. Deprecated, pass in 0. * @return status The reserve status: * * SHORTAGE - There is not enough underlying funds on the wrapper contract to satisfy the reserve ratio, * the diff amount should be redeemed from the staking contract @@ -466,8 +465,9 @@ contract PowerIndexBasicRouter is PowerIndexBasicRouterInterface, PowerIndexNaiv * @param _reserveRatioPct % of a reserve ratio, 1 ether == 100% * @param _leftOnPiToken The amount of origin tokens left on the piToken (WrappedPiErc20) contract * @param _stakedBalance The amount of original tokens staked on the staking contract - * @param _withdrawAmount The amount to be withdrawn within the current transaction - * (could be negative in a case of deposit) + * @param _withdrawAmount The amount to be withdrawn within the current transaction. Deprecated, now it is always 0. + * Introduced when the rebalancing logic was triggered by deposit/withdraw actions of piToken. Now this logic + * is triggered by the poke*() methods only. * @return expectedReserveAmount The expected reserve amount * * / %reserveRatio * (staked + _leftOnPiToken - withdrawAmount) \ From 960d3b4eb9531a33d34df51bd721fc6009c02a93 Mon Sep 17 00:00:00 2001 From: Poli Paul Date: Mon, 11 Oct 2021 17:26:59 +0200 Subject: [PATCH 26/33] Routers: Unify function selector codestyle --- .../implementations/AavePowerIndexRouter.sol | 10 +++++----- .../implementations/AutoPowerIndexRouter.sol | 4 ++-- .../implementations/SushiPowerIndexRouter.sol | 4 ++-- .../implementations/VenusVBep20SupplyRouter.sol | 6 +++--- .../implementations/YearnPowerIndexRouter.sol | 16 ++++++++-------- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/contracts/powerindex-router/implementations/AavePowerIndexRouter.sol b/contracts/powerindex-router/implementations/AavePowerIndexRouter.sol index 7e2a5276..ab03d7ab 100644 --- a/contracts/powerindex-router/implementations/AavePowerIndexRouter.sol +++ b/contracts/powerindex-router/implementations/AavePowerIndexRouter.sol @@ -48,12 +48,12 @@ contract AavePowerIndexRouter is PowerIndexBasicRouter { function callCreate(bytes calldata _args) external { _checkVotingSenderAllowed(); - _callVoting(IAaveGovernanceV2(0).create.selector, _args); + _callVoting(IAaveGovernanceV2.create.selector, _args); } function callSubmitVote(uint256 _proposalId, bool _support) external { _checkVotingSenderAllowed(); - _callVoting(IAaveGovernanceV2(0).submitVote.selector, abi.encode(_proposalId, _support)); + _callVoting(IAaveGovernanceV2.submitVote.selector, abi.encode(_proposalId, _support)); } function _claimRewards(ReserveStatus) internal override { @@ -153,7 +153,7 @@ contract AavePowerIndexRouter is PowerIndexBasicRouter { } function _triggerCoolDown() internal { - _callStaking(IStakedAave(0).cooldown.selector, ""); + _callStaking(IStakedAave.cooldown.selector, ""); emit TriggerCooldown(); } @@ -161,7 +161,7 @@ contract AavePowerIndexRouter is PowerIndexBasicRouter { require(_amount > 0, "CANT_STAKE_0"); piToken.approveUnderlying(staking, _amount); - _callStaking(IStakedAave(0).stake.selector, abi.encode(piToken, _amount)); + _callStaking(IStakedAave.stake.selector, abi.encode(piToken, _amount)); emit Stake(msg.sender, _amount); } @@ -169,7 +169,7 @@ contract AavePowerIndexRouter is PowerIndexBasicRouter { function _redeem(uint256 _amount) internal { require(_amount > 0, "CANT_REDEEM_0"); - _callStaking(IStakedAave(0).redeem.selector, abi.encode(address(piToken), _amount)); + _callStaking(IStakedAave.redeem.selector, abi.encode(address(piToken), _amount)); emit Redeem(msg.sender, _amount); } diff --git a/contracts/powerindex-router/implementations/AutoPowerIndexRouter.sol b/contracts/powerindex-router/implementations/AutoPowerIndexRouter.sol index 96979211..b11a5abc 100644 --- a/contracts/powerindex-router/implementations/AutoPowerIndexRouter.sol +++ b/contracts/powerindex-router/implementations/AutoPowerIndexRouter.sol @@ -201,7 +201,7 @@ contract AutoPowerIndexRouter is PowerIndexBasicRouter { require(_amount > 0, "CANT_STAKE_0"); piToken.approveUnderlying(staking, _amount); - _callStaking(IAutoFarm(0).deposit.selector, abi.encode(AUTO_FARM_PID, _amount)); + _callStaking(IAutoFarm.deposit.selector, abi.encode(AUTO_FARM_PID, _amount)); emit Stake(msg.sender, _amount); } @@ -209,7 +209,7 @@ contract AutoPowerIndexRouter is PowerIndexBasicRouter { function _redeem(uint256 _amount) internal { require(_amount > 0, "CANT_REDEEM_0"); - _callStaking(IAutoFarm(0).withdraw.selector, abi.encode(AUTO_FARM_PID, _amount)); + _callStaking(IAutoFarm.withdraw.selector, abi.encode(AUTO_FARM_PID, _amount)); emit Redeem(msg.sender, _amount); } diff --git a/contracts/powerindex-router/implementations/SushiPowerIndexRouter.sol b/contracts/powerindex-router/implementations/SushiPowerIndexRouter.sol index 560325d6..16ea8d1a 100644 --- a/contracts/powerindex-router/implementations/SushiPowerIndexRouter.sol +++ b/contracts/powerindex-router/implementations/SushiPowerIndexRouter.sol @@ -210,7 +210,7 @@ contract SushiPowerIndexRouter is PowerIndexBasicRouter { require(_sushi > 0, "CANT_STAKE_0"); piToken.approveUnderlying(staking, _sushi); - _callStaking(ISushiBar(0).enter.selector, abi.encode(_sushi)); + _callStaking(ISushiBar.enter.selector, abi.encode(_sushi)); emit Stake(msg.sender, _sushi); } @@ -218,7 +218,7 @@ contract SushiPowerIndexRouter is PowerIndexBasicRouter { function _redeem(uint256 _xSushi) internal { require(_xSushi > 0, "CANT_REDEEM_0"); - _callStaking(ISushiBar(0).leave.selector, abi.encode(_xSushi)); + _callStaking(ISushiBar.leave.selector, abi.encode(_xSushi)); emit Redeem(msg.sender, _xSushi); } diff --git a/contracts/powerindex-router/implementations/VenusVBep20SupplyRouter.sol b/contracts/powerindex-router/implementations/VenusVBep20SupplyRouter.sol index 77fac527..769157b0 100644 --- a/contracts/powerindex-router/implementations/VenusVBep20SupplyRouter.sol +++ b/contracts/powerindex-router/implementations/VenusVBep20SupplyRouter.sol @@ -69,7 +69,7 @@ contract VenusVBep20SupplyRouter is PowerIndexBasicRouter { uint256 underlyingEarned = 0; if (pendingInterestReward > 0) { uint256 underlyingBefore = UNDERLYING.balanceOf(address(piToken)); - _callCompStaking(VBep20Interface(0).redeemUnderlying.selector, abi.encode(pendingInterestReward)); + _callCompStaking(VBep20Interface.redeemUnderlying.selector, abi.encode(pendingInterestReward)); underlyingEarned = UNDERLYING.balanceOf(address(piToken)).sub(underlyingBefore); } @@ -255,7 +255,7 @@ contract VenusVBep20SupplyRouter is PowerIndexBasicRouter { piToken.approveUnderlying(staking, _amount); - _callCompStaking(VBep20Interface(0).mint.selector, abi.encode(_amount)); + _callCompStaking(VBep20Interface.mint.selector, abi.encode(_amount)); uint256 receivedReward = UNDERLYING.balanceOf(address(piToken)).sub(underlyingBefore.sub(_amount)); _safeTransfer(UNDERLYING, address(this), receivedReward); @@ -266,7 +266,7 @@ contract VenusVBep20SupplyRouter is PowerIndexBasicRouter { require(_amount > 0, "CANT_REDEEM_0"); uint256 underlyingBefore = UNDERLYING.balanceOf(address(piToken)); - _callCompStaking(VBep20Interface(0).redeemUnderlying.selector, abi.encode(_amount)); + _callCompStaking(VBep20Interface.redeemUnderlying.selector, abi.encode(_amount)); uint256 receivedReward = UNDERLYING.balanceOf(address(piToken)).sub(underlyingBefore).sub(_amount); _safeTransfer(UNDERLYING, address(this), receivedReward); diff --git a/contracts/powerindex-router/implementations/YearnPowerIndexRouter.sol b/contracts/powerindex-router/implementations/YearnPowerIndexRouter.sol index 90bbe677..d83d00bf 100644 --- a/contracts/powerindex-router/implementations/YearnPowerIndexRouter.sol +++ b/contracts/powerindex-router/implementations/YearnPowerIndexRouter.sol @@ -68,7 +68,7 @@ contract YearnPowerIndexRouter is PowerIndexBasicRouter { function _claimRewards(ReserveStatus) internal override { // Step #1. Claim yCrv reward from YFI governance pool - _callVoting(YearnGovernanceInterface(0).getReward.selector, ""); + _callVoting(YearnGovernanceInterface.getReward.selector, ""); uint256 yCrvReward = YCRV.balanceOf(address(piToken)); require(yCrvReward > 0, "NO_YCRV_REWARD_ON_PI"); @@ -85,7 +85,7 @@ contract YearnPowerIndexRouter is PowerIndexBasicRouter { uint256 yfiBalanceBefore = YFI.balanceOf(address(piToken)); // Step #1. Exit (get all the stake back) and claim yCrv reward from YFI governance pool - _callVoting(YearnGovernanceInterface(0).exit.selector, ""); + _callVoting(YearnGovernanceInterface.exit.selector, ""); uint256 yfiBalanceAfter = YFI.balanceOf(address(piToken)); @@ -182,22 +182,22 @@ contract YearnPowerIndexRouter is PowerIndexBasicRouter { function callRegister() external { _checkVotingSenderAllowed(); - _callVoting(YearnGovernanceInterface(0).register.selector, ""); + _callVoting(YearnGovernanceInterface.register.selector, ""); } function callPropose(address _executor, string calldata _hash) external { _checkVotingSenderAllowed(); - _callVoting(YearnGovernanceInterface(0).propose.selector, abi.encode(_executor, _hash)); + _callVoting(YearnGovernanceInterface.propose.selector, abi.encode(_executor, _hash)); } function callVoteFor(uint256 _id) external { _checkVotingSenderAllowed(); - _callVoting(YearnGovernanceInterface(0).voteFor.selector, abi.encode(_id)); + _callVoting(YearnGovernanceInterface.voteFor.selector, abi.encode(_id)); } function callVoteAgainst(uint256 _id) external { _checkVotingSenderAllowed(); - _callVoting(YearnGovernanceInterface(0).voteAgainst.selector, abi.encode(_id)); + _callVoting(YearnGovernanceInterface.voteAgainst.selector, abi.encode(_id)); } /*** OWNER METHODS ***/ @@ -242,7 +242,7 @@ contract YearnPowerIndexRouter is PowerIndexBasicRouter { require(_amount > 0, "CANT_STAKE_0"); piToken.approveUnderlying(voting, _amount); - _callVoting(YearnGovernanceInterface(0).stake.selector, abi.encode(_amount)); + _callVoting(YearnGovernanceInterface.stake.selector, abi.encode(_amount)); emit Stake(msg.sender, _amount); } @@ -250,7 +250,7 @@ contract YearnPowerIndexRouter is PowerIndexBasicRouter { function _redeem(uint256 _amount) internal { require(_amount > 0, "CANT_REDEEM_0"); - _callVoting(YearnGovernanceInterface(0).withdraw.selector, abi.encode(_amount)); + _callVoting(YearnGovernanceInterface.withdraw.selector, abi.encode(_amount)); emit Redeem(msg.sender, _amount); } From 08b80f7f7519698ad4e0e36413499a53bb3110fd Mon Sep 17 00:00:00 2001 From: Poli Paul Date: Mon, 11 Oct 2021 17:33:44 +0200 Subject: [PATCH 27/33] Routers: Mark _afterPoke virtual --- contracts/powerindex-router/PowerIndexBasicRouter.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/powerindex-router/PowerIndexBasicRouter.sol b/contracts/powerindex-router/PowerIndexBasicRouter.sol index 9ab36c30..f25d637d 100644 --- a/contracts/powerindex-router/PowerIndexBasicRouter.sol +++ b/contracts/powerindex-router/PowerIndexBasicRouter.sol @@ -209,7 +209,7 @@ contract PowerIndexBasicRouter is PowerIndexBasicRouterInterface, PowerIndexNaiv require(staking != address(0), "STAKING_IS_NULL"); } - function _afterPoke(ReserveStatus reserveStatus, bool _claimAndDistributeRewards) internal { + function _afterPoke(ReserveStatus reserveStatus, bool _claimAndDistributeRewards) internal virtual { lastRebalancedAt = block.timestamp; if (_claimAndDistributeRewards && lastClaimRewardsAt + claimRewardsInterval < block.timestamp) { From 354d8df3d577b633d6d0b28a1f28e055f4a860d4 Mon Sep 17 00:00:00 2001 From: Poli Paul Date: Mon, 11 Oct 2021 17:39:44 +0200 Subject: [PATCH 28/33] Fix misleading signature in comment --- .../implementations/BakeryChefPowerIndexRouter.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/powerindex-router/implementations/BakeryChefPowerIndexRouter.sol b/contracts/powerindex-router/implementations/BakeryChefPowerIndexRouter.sol index 55abf446..1fc4ebfb 100644 --- a/contracts/powerindex-router/implementations/BakeryChefPowerIndexRouter.sol +++ b/contracts/powerindex-router/implementations/BakeryChefPowerIndexRouter.sol @@ -10,7 +10,7 @@ import "./AbstractMasterChefIndexRouter.sol"; /** * Compatible with: * - Bakery: https://bscscan.com/address/0x20ec291bb8459b6145317e7126532ce7ece5056f, - * pending rewards via pendingBake(pid, user) + * pending rewards via pendingBake(pair, user) */ contract BakeryChefPowerIndexRouter is AbstractMasterChefIndexRouter { struct BakeryMasterChefConfig { From 1e82df8a57bdf7c9dbc99292a21d7a28933eaee4 Mon Sep 17 00:00:00 2001 From: Poli Paul Date: Mon, 11 Oct 2021 17:40:46 +0200 Subject: [PATCH 29/33] Remove unused import --- .../implementations/BakeryChefPowerIndexRouter.sol | 1 - 1 file changed, 1 deletion(-) diff --git a/contracts/powerindex-router/implementations/BakeryChefPowerIndexRouter.sol b/contracts/powerindex-router/implementations/BakeryChefPowerIndexRouter.sol index 1fc4ebfb..265f1eca 100644 --- a/contracts/powerindex-router/implementations/BakeryChefPowerIndexRouter.sol +++ b/contracts/powerindex-router/implementations/BakeryChefPowerIndexRouter.sol @@ -3,7 +3,6 @@ pragma solidity 0.6.12; pragma experimental ABIEncoderV2; -import "../../interfaces/sushi/IMasterChefV1.sol"; import "../../interfaces/IBakeryMasterChef.sol"; import "./AbstractMasterChefIndexRouter.sol"; From 9cad645b9a62301d24dd735f3642be0def41ab31 Mon Sep 17 00:00:00 2001 From: Poli Paul Date: Mon, 11 Oct 2021 17:54:16 +0200 Subject: [PATCH 30/33] Routers/Bakery: Add a notice on the staking contract signature specifics --- .../implementations/BakeryChefPowerIndexRouter.sol | 2 ++ 1 file changed, 2 insertions(+) diff --git a/contracts/powerindex-router/implementations/BakeryChefPowerIndexRouter.sol b/contracts/powerindex-router/implementations/BakeryChefPowerIndexRouter.sol index 265f1eca..cce7cb64 100644 --- a/contracts/powerindex-router/implementations/BakeryChefPowerIndexRouter.sol +++ b/contracts/powerindex-router/implementations/BakeryChefPowerIndexRouter.sol @@ -10,6 +10,8 @@ import "./AbstractMasterChefIndexRouter.sol"; * Compatible with: * - Bakery: https://bscscan.com/address/0x20ec291bb8459b6145317e7126532ce7ece5056f, * pending rewards via pendingBake(pair, user) + * @dev Notice that in deposit/withdraw/pendingBake method signatures Bakery uses the staking token addresses + * instead of numerical pool IDs like in the majority of masterChef forks. */ contract BakeryChefPowerIndexRouter is AbstractMasterChefIndexRouter { struct BakeryMasterChefConfig { From c1648185ec212f29e7f1ed97e1ead771586333e1 Mon Sep 17 00:00:00 2001 From: Poli Paul Date: Fri, 15 Oct 2021 12:14:38 +0200 Subject: [PATCH 31/33] Add a no fee whiteslit to PiToken contract --- .../interfaces/WrappedPiErc20Interface.sol | 2 + .../PowerIndexBasicRouter.sol | 4 ++ .../powerindex-router/WrappedPiErc20.sol | 21 ++++++- test/router/WrappedPiErc20.unit.test.js | 57 +++++++++++++++++++ 4 files changed, 82 insertions(+), 2 deletions(-) diff --git a/contracts/interfaces/WrappedPiErc20Interface.sol b/contracts/interfaces/WrappedPiErc20Interface.sol index c8579fb1..c5fd4d6b 100644 --- a/contracts/interfaces/WrappedPiErc20Interface.sol +++ b/contracts/interfaces/WrappedPiErc20Interface.sol @@ -12,6 +12,8 @@ interface WrappedPiErc20Interface is IERC20 { function changeRouter(address _newRouter) external; + function setNoFee(address _for, bool _noFee) external; + function setEthFee(uint256 _newEthFee) external; function withdrawEthFee(address payable receiver) external; diff --git a/contracts/powerindex-router/PowerIndexBasicRouter.sol b/contracts/powerindex-router/PowerIndexBasicRouter.sol index f25d637d..b1d012a0 100644 --- a/contracts/powerindex-router/PowerIndexBasicRouter.sol +++ b/contracts/powerindex-router/PowerIndexBasicRouter.sol @@ -155,6 +155,10 @@ contract PowerIndexBasicRouter is PowerIndexBasicRouterInterface, PowerIndexNaiv piToken.setEthFee(_ethFee); } + function setPiTokenNoFee(address _for, bool _noFee) external onlyOwner { + piToken.setNoFee(_for, _noFee); + } + function withdrawEthFee(address payable _receiver) external onlyOwner { piToken.withdrawEthFee(_receiver); } diff --git a/contracts/powerindex-router/WrappedPiErc20.sol b/contracts/powerindex-router/WrappedPiErc20.sol index 7529a57d..6f7660c1 100644 --- a/contracts/powerindex-router/WrappedPiErc20.sol +++ b/contracts/powerindex-router/WrappedPiErc20.sol @@ -18,12 +18,14 @@ contract WrappedPiErc20 is ERC20, ReentrancyGuard, WrappedPiErc20Interface { IERC20 public immutable underlying; address public router; uint256 public ethFee; + mapping(address => bool) public noFeeWhitelist; event Deposit(address indexed account, uint256 undelyingDeposited, uint256 piMinted); event Withdraw(address indexed account, uint256 underlyingWithdrawn, uint256 piBurned); event Approve(address indexed to, uint256 amount); event ChangeRouter(address indexed newRouter); event SetEthFee(uint256 newEthFee); + event SetNoFee(address indexed addr, bool noFee); event WithdrawEthFee(uint256 value); event CallExternal(address indexed destination, bytes4 indexed inputSig, bytes inputData, bytes outputData); @@ -47,7 +49,12 @@ contract WrappedPiErc20 is ERC20, ReentrancyGuard, WrappedPiErc20Interface { * @param _depositAmount The amount to deposit in underlying tokens */ function deposit(uint256 _depositAmount) external payable override nonReentrant returns (uint256) { - require(msg.value >= ethFee, "FEE"); + if (noFeeWhitelist[msg.sender]) { + require(msg.value == 0, "NO_FEE_FOR_WL"); + } else { + require(msg.value >= ethFee, "FEE"); + } + require(_depositAmount > 0, "ZERO_DEPOSIT"); uint256 mintAmount = getPiEquivalentForUnderlying(_depositAmount); @@ -68,7 +75,12 @@ contract WrappedPiErc20 is ERC20, ReentrancyGuard, WrappedPiErc20Interface { * @param _withdrawAmount The amount to withdraw in underlying tokens */ function withdraw(uint256 _withdrawAmount) external payable override nonReentrant returns (uint256) { - require(msg.value >= ethFee, "FEE"); + if (noFeeWhitelist[msg.sender]) { + require(msg.value == 0, "NO_FEE_FOR_WL"); + } else { + require(msg.value >= ethFee, "FEE"); + } + require(_withdrawAmount > 0, "ZERO_WITHDRAWAL"); PowerIndexNaiveRouterInterface(router).piTokenCallback{ value: msg.value }(msg.sender, _withdrawAmount); @@ -106,6 +118,11 @@ contract WrappedPiErc20 is ERC20, ReentrancyGuard, WrappedPiErc20Interface { emit ChangeRouter(router); } + function setNoFee(address _for, bool _noFee) external override onlyRouter { + noFeeWhitelist[_for] = _noFee; + emit SetNoFee(_for, _noFee); + } + function setEthFee(uint256 _ethFee) external override onlyRouter { ethFee = _ethFee; emit SetEthFee(_ethFee); diff --git a/test/router/WrappedPiErc20.unit.test.js b/test/router/WrappedPiErc20.unit.test.js index 54ed82c4..802bb01d 100644 --- a/test/router/WrappedPiErc20.unit.test.js +++ b/test/router/WrappedPiErc20.unit.test.js @@ -236,6 +236,27 @@ describe('WrappedPiErc20 Unit Tests', () => { assert.equal(await web3.eth.getBalance(router.address), ethFee); }); + it('should ignore fee for the whitelisted addresses', async () => { + assert.equal(await piYfi.ethFee(), ether(0)); + + const ethFee = ether(0.001); + + await router.setPiTokenEthFee(ethFee, { from: owner }); + await router.setPiTokenNoFee(alice, true, { from: owner }); + + assert.equal(await piYfi.ethFee(), ethFee); + + await yfi.approve(piYfi.address, ether(42), { from: alice }); + await expectRevert(piYfi.deposit(ether(42), { from: alice, value: ethFee }), 'NO_FEE_FOR_WL'); + const res = await piYfi.deposit(ether(42), { from: alice }); + + expectEvent(res, 'Deposit', { + account: alice, + undelyingDeposited: ether(42), + piMinted: ether(42), + }); + }); + describe('imbalanced router', () => { beforeEach(async () => { assert.equal(await yfi.balanceOf(alice), ether(10000)); @@ -385,6 +406,26 @@ describe('WrappedPiErc20 Unit Tests', () => { assert.equal(await web3.eth.getBalance(router.address), ethFee); assert.equal(await web3.eth.getBalance(piYfi.address), 0); }); + + it('should ignore fee for the whitelisted addresses', async () => { + assert.equal(await piYfi.ethFee(), ether(0)); + + const ethFee = ether(0.001); + + await router.setPiTokenEthFee(ethFee, { from: owner }); + await router.setPiTokenNoFee(alice, true, { from: owner }); + + assert.equal(await piYfi.ethFee(), ethFee); + + await expectRevert(piYfi.withdraw(ether(42), { from: alice, value: ethFee }), 'NO_FEE_FOR_WL'); + + const res = await piYfi.withdraw(ether(42), { from: alice }); + expectEvent(res, 'Withdraw', { + account: alice, + underlyingWithdrawn: ether(42), + piBurned: ether(42), + }); + }); }); describe('imbalanced wrapper', () => { @@ -515,6 +556,22 @@ describe('WrappedPiErc20 Unit Tests', () => { }); }); + describe('setNoFee', async () => { + it('should allow setting no fee values', async () => { + assert.equal(await piYfi.noFeeWhitelist(bob), false); + let data = await piYfi.contract.methods.setNoFee(bob, true).encodeABI(); + await router.execute(piYfi.address, data); + assert.equal(await piYfi.noFeeWhitelist(bob), true); + data = await piYfi.contract.methods.setNoFee(bob, false).encodeABI(); + await router.execute(piYfi.address, data); + assert.equal(await piYfi.noFeeWhitelist(bob), false); + }); + + it('should deny calling the method from non-router address', async () => { + await expectRevert(piYfi.setNoFee(bob, { from: alice }), 'ONLY_ROUTER'); + }); + }); + describe('approveToken', async () => { it('should allow the router approving locked tokens', async () => { const data = await piYfi.contract.methods.approveUnderlying(bob, ether(55)).encodeABI(); From 0f0032c83addace2c2769ffc5eae0c58ad4a36dd Mon Sep 17 00:00:00 2001 From: Poli Paul Date: Fri, 15 Oct 2021 12:23:37 +0200 Subject: [PATCH 32/33] Add Alpaca assets --- assets/bsc/AlpacaConfigurableInterestVaultConfig.json | 4 ++++ assets/bsc/AlpacaFairLaunch.json | 4 ++++ assets/bsc/AlpacaToken.json | 4 ++++ assets/bsc/AlpacaTripleSlopeModel.json | 4 ++++ assets/bsc/AlpacaVault.json | 4 ++++ 5 files changed, 20 insertions(+) create mode 100644 assets/bsc/AlpacaConfigurableInterestVaultConfig.json create mode 100644 assets/bsc/AlpacaFairLaunch.json create mode 100644 assets/bsc/AlpacaToken.json create mode 100644 assets/bsc/AlpacaTripleSlopeModel.json create mode 100644 assets/bsc/AlpacaVault.json diff --git a/assets/bsc/AlpacaConfigurableInterestVaultConfig.json b/assets/bsc/AlpacaConfigurableInterestVaultConfig.json new file mode 100644 index 00000000..567eaf85 --- /dev/null +++ b/assets/bsc/AlpacaConfigurableInterestVaultConfig.json @@ -0,0 +1,4 @@ +{ + "bytecode": "608060405234801561001057600080fd5b50611929806100206000396000f3fe608060405234801561001057600080fd5b506004361061018a5760003560e01c80620237f01461018f578063044d6d6f146101c957806304df1f5e146101ed57806309956f661461020757806313f6321b1461020f57806314735d8a1461023b5780631613d4ac146102ad57806317c1a8641461030d5780631bb8c61d1461032a578063205eea771461039a578063231850d61461040a578063238d19ed1461041257806328ae433e146104385780634048a257146104405780634f69476a1461046657806361d027b314610492578063715018a61461049a5780638da5cb5b146104a257806398cb0614146104aa578063990c850b146104d0578063aa15664514610530578063ac165d7a14610556578063ad58e5731461055e578063bb6a0e041461058a578063bfbbd53f146105b0578063c6dfa13f146105b8578063d1783fa8146105db578063d9ed3def146105e3578063e1ed428614610609578063ef3bac5e14610611578063f0ef07a914610619578063f2fde38b146106d7578063ffc97ce9146106fd575b600080fd5b6101b5600480360360208110156101a557600080fd5b50356001600160a01b0316610723565b604080519115158252519081900360200190f35b6101d16107aa565b604080516001600160a01b039092168252519081900360200190f35b6101f56107ea565b60408051918252519081900360200190f35b6101f56107f0565b6101f56004803603604081101561022557600080fd5b506001600160a01b0381351690602001356107f6565b6102ab6004803603604081101561025157600080fd5b810190602081018135600160201b81111561026b57600080fd5b82018360208201111561027d57600080fd5b803590602001918460208302840111600160201b8311171561029e57600080fd5b9193509150351515610888565b005b6102ab60048036036101208110156102c457600080fd5b508035906020810135906040810135906001600160a01b036060820135811691608081013582169160a082013581169160c081013582169160e0820135916101000135166109bd565b6102ab6004803603602081101561032357600080fd5b5035610b6b565b6102ab6004803603604081101561034057600080fd5b810190602081018135600160201b81111561035a57600080fd5b82018360208201111561036c57600080fd5b803590602001918460208302840111600160201b8311171561038d57600080fd5b9193509150351515610c55565b6102ab600480360360408110156103b057600080fd5b810190602081018135600160201b8111156103ca57600080fd5b8201836020820111156103dc57600080fd5b803590602001918460208302840111600160201b831117156103fd57600080fd5b9193509150351515610d87565b6101f5610eb9565b6101b56004803603602081101561042857600080fd5b50356001600160a01b0316610ebf565b6101f5610ed4565b6101d16004803603602081101561045657600080fd5b50356001600160a01b0316610eda565b6101f56004803603604081101561047c57600080fd5b506001600160a01b038135169060200135610ef5565b6101d1610f54565b6102ab610f63565b6101d1610ff3565b6101b5600480360360208110156104c057600080fd5b50356001600160a01b0316611002565b6102ab60048036036101208110156104e757600080fd5b508035906020810135906040810135906001600160a01b036060820135811691608081013582169160a082013581169160c081013582169160e08201359161010001351661105a565b6101b56004803603602081101561054657600080fd5b50356001600160a01b0316611124565b6101d1611144565b6101f56004803603604081101561057457600080fd5b506001600160a01b038135169060200135611153565b6101b5600480360360208110156105a057600080fd5b50356001600160a01b03166111b2565b6101d161120a565b6101f5600480360360408110156105ce57600080fd5b5080359060200135611219565b6101d161126c565b6101b5600480360360208110156105f957600080fd5b50356001600160a01b031661127b565b6101f5611290565b6101d1611296565b6102ab6004803603604081101561062f57600080fd5b810190602081018135600160201b81111561064957600080fd5b82018360208201111561065b57600080fd5b803590602001918460208302840111600160201b8311171561067c57600080fd5b919390929091602081019035600160201b81111561069957600080fd5b8201836020820111156106ab57600080fd5b803590602001918460208302840111600160201b831117156106cc57600080fd5b5090925090506112a5565b6102ab600480360360208110156106ed57600080fd5b50356001600160a01b031661145d565b6101b56004803603602081101561071357600080fd5b50356001600160a01b0316611544565b6001600160a01b038082166000818152609a6020908152604080832054815161237f60e41b81526004810195909552905192941692620237f09260248083019392829003018186803b15801561077857600080fd5b505afa15801561078c573d6000803e3d6000fd5b505050506040513d60208110156107a257600080fd5b505192915050565b60a2546000906001600160a01b0316156107cf5760a2546001600160a01b03166107e5565b73c44f82b07ab3e691f826951a6e335e1bc1bb0b515b905090565b60a15481565b60985481565b6001600160a01b038083166000818152609a602090815260408083205481516313f6321b60e01b81526004810195909552602485018790529051929416926313f6321b9260448083019392829003018186803b15801561085557600080fd5b505afa158015610869573d6000803e3d6000fd5b505050506040513d602081101561087f57600080fd5b50519392505050565b610890611559565b6065546001600160a01b039081169116146108e0576040805162461bcd60e51b8152602060048201819052602482015260008051602061180e833981519152604482015290519081900360640190fd5b60005b828110156109b7578160a360008686858181106108fc57fe5b905060200201356001600160a01b03166001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff02191690831515021790555061094b611559565b6001600160a01b03167f61433d4e523c3b3b1020dd4975cb6dcc29989b8b26e15491e3413f1b6db7f21885858481811061098157fe5b60408051602092830294909401356001600160a01b031684528715159184019190915280519283900301919050a26001016108e3565b50505050565b6109c5611559565b6065546001600160a01b03908116911614610a15576040805162461bcd60e51b8152602060048201819052602482015260008051602061180e833981519152604482015290519081900360640190fd5b609f548288011115610a585760405162461bcd60e51b815260040180806020018281038252604b8152602001806117c3604b913960600191505060405180910390fd5b609789905560988890556099879055609b80546001600160a01b03199081166001600160a01b0389811691909117909255609c80548216888416179055609d80548216878416179055609e8054821686841617905560a184905560a28054909116918316919091179055610aca611559565b609754609854609954609b54609c54609d54609e5460a15460a25460408051998a5260208a0198909852888801969096526001600160a01b039485166060890152928416608088015290831660a0870152821660c086015260e085015290811661010084015290519216917f24a73e803ecc107262a36972e594f211bc58b179b41949d9d9482bed2d34f1e3918190036101200190a2505050505050505050565b610b73611559565b6065546001600160a01b03908116911614610bc3576040805162461bcd60e51b8152602060048201819052602482015260008051602061180e833981519152604482015290519081900360640190fd5b6103e88110610c035760405162461bcd60e51b815260040180806020018281038252604081526020018061187c6040913960400191505060405180910390fd5b609f819055610c10611559565b6001600160a01b03167fc875e8f88dddf010c26a5c4f0cd2ab3e2366959b9a01f58403e6030c35a41d61609f546040518082815260200191505060405180910390a250565b610c5d611559565b6065546001600160a01b03908116911614610cad576040805162461bcd60e51b8152602060048201819052602482015260008051602061180e833981519152604482015290519081900360640190fd5b60005b828110156109b7578160a06000868685818110610cc957fe5b905060200201356001600160a01b03166001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff021916908315150217905550838382818110610d1c57fe5b905060200201356001600160a01b03166001600160a01b0316610d3d611559565b60408051851515815290516001600160a01b0392909216917fdfad9b83c215ff1a36483cf1688e5aeae2ac60f1c3f62f5229641234748f13b79181900360200190a3600101610cb0565b610d8f611559565b6065546001600160a01b03908116911614610ddf576040805162461bcd60e51b8152602060048201819052602482015260008051602061180e833981519152604482015290519081900360640190fd5b60005b828110156109b7578160a46000868685818110610dfb57fe5b905060200201356001600160a01b03166001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff021916908315150217905550838382818110610e4e57fe5b905060200201356001600160a01b03166001600160a01b0316610e6f611559565b60408051851515815290516001600160a01b0392909216917fff43936d4228b51ffc0bc1c7b235c55e3ca6228c134c850cb9b4ac59274a84989181900360200190a3600101610de2565b609f5481565b60a36020526000908152604090205460ff1681565b60995481565b609a602052600090815260409020546001600160a01b031681565b6001600160a01b038083166000818152609a602090815260408083205481516327b4a3b560e11b8152600481019590955260248501879052905192941692634f69476a9260448083019392829003018186803b15801561085557600080fd5b60a2546001600160a01b031681565b610f6b611559565b6065546001600160a01b03908116911614610fbb576040805162461bcd60e51b8152602060048201819052602482015260008051602061180e833981519152604482015290519081900360640190fd5b6065546040516000916001600160a01b03169060008051602061182e833981519152908390a3606580546001600160a01b0319169055565b6065546001600160a01b031690565b6001600160a01b038082166000818152609a602090815260408083205481516324617dbb60e21b81526004810195909552905192941692639185f6ec9260248083019392829003018186803b15801561077857600080fd5b600054610100900460ff1680611073575061107361155d565b80611081575060005460ff16155b6110bc5760405162461bcd60e51b815260040180806020018281038252602e81526020018061184e602e913960400191505060405180910390fd5b600054610100900460ff161580156110e7576000805460ff1961ff0019909116610100171660011790555b6110ef611563565b6101f4609f556111068a8a8a8a8a8a8a8a8a6109bd565b8015611118576000805461ff00191690555b50505050505050505050565b6001600160a01b039081166000908152609a602052604090205416151590565b609b546001600160a01b031681565b6001600160a01b038083166000818152609a6020908152604080832054815163ad58e57360e01b815260048101959095526024850187905290519294169263ad58e5739260448083019392829003018186803b15801561085557600080fd5b6001600160a01b038082166000818152609a60209081526040808320548151638bdc44d160e01b81526004810195909552905192941692638bdc44d19260248083019392829003018186803b15801561077857600080fd5b609e546001600160a01b031681565b609b546040805163c6dfa13f60e01b8152600481018590526024810184905290516000926001600160a01b03169163c6dfa13f916044808301926020929190829003018186803b15801561085557600080fd5b609d546001600160a01b031681565b60a46020526000908152604090205460ff1681565b60975481565b609c546001600160a01b031681565b6112ad611559565b6065546001600160a01b039081169116146112fd576040805162461bcd60e51b8152602060048201819052602482015260008051602061180e833981519152604482015290519081900360640190fd5b82811461133b5760405162461bcd60e51b81526004018080602001828103825260388152602001806118bc6038913960400191505060405180910390fd5b60005b838110156114565782828281811061135257fe5b905060200201356001600160a01b0316609a600087878581811061137257fe5b905060200201356001600160a01b03166001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b031602179055506113ce611559565b6001600160a01b03167f571fe0f3ae1ce4553242e24bd2bdcf3fcfec0f6fdb48d018bd91357d605f291d86868481811061140457fe5b905060200201356001600160a01b031685858581811061142057fe5b604080516001600160a01b03958616815260209283029490940135909416908301525081519081900390910190a260010161133e565b5050505050565b611465611559565b6065546001600160a01b039081169116146114b5576040805162461bcd60e51b8152602060048201819052602482015260008051602061180e833981519152604482015290519081900360640190fd5b6001600160a01b0381166114fa5760405162461bcd60e51b815260040180806020018281038252602681526020018061179d6026913960400191505060405180910390fd5b6065546040516001600160a01b0380841692169060008051602061182e83398151915290600090a3606580546001600160a01b0319166001600160a01b0392909216919091179055565b60a06020526000908152604090205460ff1681565b3390565b303b1590565b600054610100900460ff168061157c575061157c61155d565b8061158a575060005460ff16155b6115c55760405162461bcd60e51b815260040180806020018281038252602e81526020018061184e602e913960400191505060405180910390fd5b600054610100900460ff161580156115f0576000805460ff1961ff0019909116610100171660011790555b6115f8611615565b6116006116b5565b8015611612576000805461ff00191690555b50565b600054610100900460ff168061162e575061162e61155d565b8061163c575060005460ff16155b6116775760405162461bcd60e51b815260040180806020018281038252602e81526020018061184e602e913960400191505060405180910390fd5b600054610100900460ff16158015611600576000805460ff1961ff0019909116610100171660011790558015611612576000805461ff001916905550565b600054610100900460ff16806116ce57506116ce61155d565b806116dc575060005460ff16155b6117175760405162461bcd60e51b815260040180806020018281038252602e81526020018061184e602e913960400191505060405180910390fd5b600054610100900460ff16158015611742576000805460ff1961ff0019909116610100171660011790555b600061174c611559565b606580546001600160a01b0319166001600160a01b0383169081179091556040519192509060009060008051602061182e833981519152908290a3508015611612576000805461ff00191690555056fe4f776e61626c653a206e6577206f776e657220697320746865207a65726f2061646472657373436f6e666967757261626c65496e7465726573745661756c74436f6e6669673a3a736574506172616d733a3a206b696c6c20627073206578636565646564206d6178206b696c6c206270734f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65728be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0436f6e747261637420696e7374616e63652068617320616c7265616479206265656e20696e697469616c697a6564436f6e666967757261626c65496e7465726573745661756c74436f6e6669673a3a7365744d61784b696c6c4270733a3a20626164205f6d61784b696c6c427073436f6e666967757261626c65496e7465726573745661756c74436f6e6669673a3a736574576f726b6572733a3a20626164206c656e677468a2646970667358221220a408eec0a638c5d2533c4b3dae7225d5180f726f7e34a25a4b2df7fa2ef7589964736f6c63430006060033", + "abi": [{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":false,"internalType":"address","name":"addStrat","type":"address"},{"indexed":false,"internalType":"bool","name":"ok","type":"bool"}],"name":"SetApprovedAddStrategy","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":false,"internalType":"uint256","name":"maxKillBps","type":"uint256"}],"name":"SetMaxKillBps","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":false,"internalType":"uint256","name":"minDebtSize","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"reservePoolBps","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"killBps","type":"uint256"},{"indexed":false,"internalType":"address","name":"interestModel","type":"address"},{"indexed":false,"internalType":"address","name":"wrappedNative","type":"address"},{"indexed":false,"internalType":"address","name":"wNativeRelayer","type":"address"},{"indexed":false,"internalType":"address","name":"fairLaunch","type":"address"},{"indexed":false,"internalType":"uint256","name":"killTreasuryBps","type":"uint256"},{"indexed":false,"internalType":"address","name":"treasury","type":"address"}],"name":"SetParams","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"addr","type":"address"},{"indexed":false,"internalType":"bool","name":"ok","type":"bool"}],"name":"SetWhitelistedCaller","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"addr","type":"address"},{"indexed":false,"internalType":"bool","name":"ok","type":"bool"}],"name":"SetWhitelistedLiquidator","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":false,"internalType":"address","name":"worker","type":"address"},{"indexed":false,"internalType":"address","name":"workerConfig","type":"address"}],"name":"SetWorkers","type":"event"},{"inputs":[{"internalType":"address","name":"worker","type":"address"}],"name":"acceptDebt","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"approvedAddStrategies","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFairLaunchAddr","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"debt","type":"uint256"},{"internalType":"uint256","name":"floating","type":"uint256"}],"name":"getInterestRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getKillBps","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getKillTreasuryBps","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getReservePoolBps","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTreasuryAddr","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getWNativeRelayer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getWrappedNativeAddr","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_minDebtSize","type":"uint256"},{"internalType":"uint256","name":"_reservePoolBps","type":"uint256"},{"internalType":"uint256","name":"_killBps","type":"uint256"},{"internalType":"contract InterestModel","name":"_interestModel","type":"address"},{"internalType":"address","name":"_getWrappedNativeAddr","type":"address"},{"internalType":"address","name":"_getWNativeRelayer","type":"address"},{"internalType":"address","name":"_getFairLaunchAddr","type":"address"},{"internalType":"uint256","name":"_getKillTreasuryBps","type":"uint256"},{"internalType":"address","name":"_treasury","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"interestModel","outputs":[{"internalType":"contract InterestModel","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"worker","type":"address"}],"name":"isWorker","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"worker","type":"address"}],"name":"isWorkerReserveConsistent","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"worker","type":"address"}],"name":"isWorkerStable","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"worker","type":"address"},{"internalType":"uint256","name":"debt","type":"uint256"}],"name":"killFactor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxKillBps","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minDebtSize","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"worker","type":"address"},{"internalType":"uint256","name":"debt","type":"uint256"}],"name":"rawKillFactor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"addStrats","type":"address[]"},{"internalType":"bool","name":"ok","type":"bool"}],"name":"setApprovedAddStrategy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxKillBps","type":"uint256"}],"name":"setMaxKillBps","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_minDebtSize","type":"uint256"},{"internalType":"uint256","name":"_reservePoolBps","type":"uint256"},{"internalType":"uint256","name":"_killBps","type":"uint256"},{"internalType":"contract InterestModel","name":"_interestModel","type":"address"},{"internalType":"address","name":"_getWrappedNativeAddr","type":"address"},{"internalType":"address","name":"_getWNativeRelayer","type":"address"},{"internalType":"address","name":"_getFairLaunchAddr","type":"address"},{"internalType":"uint256","name":"_getKillTreasuryBps","type":"uint256"},{"internalType":"address","name":"_treasury","type":"address"}],"name":"setParams","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"callers","type":"address[]"},{"internalType":"bool","name":"ok","type":"bool"}],"name":"setWhitelistedCallers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"callers","type":"address[]"},{"internalType":"bool","name":"ok","type":"bool"}],"name":"setWhitelistedLiquidators","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"addrs","type":"address[]"},{"internalType":"contract IWorkerConfig[]","name":"configs","type":"address[]"}],"name":"setWorkers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"treasury","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"whitelistedCallers","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"whitelistedLiquidators","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"worker","type":"address"},{"internalType":"uint256","name":"debt","type":"uint256"}],"name":"workFactor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"workers","outputs":[{"internalType":"contract IWorkerConfig","name":"","type":"address"}],"stateMutability":"view","type":"function"}] +} diff --git a/assets/bsc/AlpacaFairLaunch.json b/assets/bsc/AlpacaFairLaunch.json new file mode 100644 index 00000000..3e611891 --- /dev/null +++ b/assets/bsc/AlpacaFairLaunch.json @@ -0,0 +1,4 @@ +{ + "bytecode": "608060405234801561001057600080fd5b50604051612457380380612457833981810160405260c081101561003357600080fd5b508051602082015160408301516060840151608085015160a0909501519394929391929091600061006b6001600160e01b0361010616565b600080546001600160a01b0319166001600160a01b0383169081178255604051929350917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a35060006004819055600955600180546001600160a01b039788166001600160a01b0319918216179091556002805496909716951694909417909455600391909155600692909255600555600a5561010a565b3390565b61233e806101196000396000f3fe608060405234801561001057600080fd5b506004361061016a5760003560e01c8063081e3eda1461016f5780630efe6a8b146101895780631526fe27146101bd57806317caf6f11461020f5780631aed65531461021757806320f33d591461021f57806346ca6bea1461022757806348cd4cb1146102525780634c8f70fd1461025a57806351eb05a6146102775780635312ea8e14610294578063630b5ba1146102b1578063715018a6146102b95780637abceffd146102c15780638da5cb5b146102f55780638dbb1e3a1461031957806393f1a40b1461033c57806394443b731461039757806394faab23146103c3578063a8b973a1146103cb578063b03df69d146103d3578063b5c5f6721461040d578063cbdec1fc1461043f578063cc6dbc2714610447578063d477f05f14610473578063d49e77cd14610499578063ddc63262146104a1578063e4c5ff46146104be578063f2fde38b146104ea578063fa5be8f814610510575b600080fd5b610177610539565b60408051918252519081900360200190f35b6101bb6004803603606081101561019f57600080fd5b506001600160a01b03813516906020810135906040013561053f565b005b6101da600480360360208110156101d357600080fd5b5035610738565b604080516001600160a01b03909616865260208601949094528484019290925260608401526080830152519081900360a00190f35b610177610780565b610177610786565b61017761078c565b6101bb6004803603606081101561023d57600080fd5b50803590602081013590604001351515610792565b610177610873565b6101bb6004803603602081101561027057600080fd5b5035610879565b6101bb6004803603602081101561028d57600080fd5b50356108e0565b6101bb600480360360208110156102aa57600080fd5b5035610cfe565b6101bb610d9f565b6101bb610dc2565b6101bb600480360360608110156102d757600080fd5b508035906001600160a01b0360208201351690604001351515610e5c565b6102fd6110bb565b604080516001600160a01b039092168252519081900360200190f35b6101776004803603604081101561032f57600080fd5b50803590602001356110ca565b6103686004803603604081101561035257600080fd5b50803590602001356001600160a01b0316611148565b604080519485526020850193909352838301919091526001600160a01b03166060830152519081900360800190f35b610177600480360360408110156103ad57600080fd5b50803590602001356001600160a01b0316611183565b6102fd6112f9565b610177611308565b6103f9600480360360208110156103e957600080fd5b50356001600160a01b031661130e565b604080519115158252519081900360200190f35b6101bb6004803603606081101561042357600080fd5b506001600160a01b038135169060208101359060400135611374565b610177611384565b6101bb6004803603604081101561045d57600080fd5b506001600160a01b03813516906020013561138a565b6101bb6004803603602081101561048957600080fd5b50356001600160a01b03166113ba565b6102fd611427565b6101bb600480360360208110156104b757600080fd5b5035611436565b6101bb600480360360408110156104d457600080fd5b506001600160a01b0381351690602001356114d1565b6101bb6004803603602081101561050057600080fd5b50356001600160a01b03166115a4565b6101bb6004803603606081101561052657600080fd5b5080359060208101359060400135611694565b60075490565b60006007838154811061054e57fe5b600091825260208083208684526008825260408085206001600160a01b03808b168752935290932060038101546005909302909301935016156105d65760038101546001600160a01b031633146105d6576040805162461bcd60e51b81526020600482015260076024820152663130b21039b7b360c91b604482015290519081900360640190fd5b81546001600160a01b0316610630576040805162461bcd60e51b815260206004820152601b60248201527a19195c1bdcda5d0e881b9bdd081858d8d95c1d0819195c1bdcda5d602a1b604482015290519081900360640190fd5b610639846108e0565b80541561064a5761064a85856117ab565b60038101546001600160a01b0316610671576003810180546001600160a01b031916331790555b815461068e906001600160a01b031633308663ffffffff611a0316565b80546106a0908463ffffffff611a6316565b80825560038301546106cf9164e8d4a51000916106c3919063ffffffff611abb16565b9063ffffffff611b1416565b6001820155600482015481546106f59164e8d4a51000916106c39163ffffffff611abb16565b6002820155604080518481529051859133917f90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a159181900360200190a35050505050565b6007818154811061074557fe5b6000918252602090912060059091020180546001820154600283015460038401546004909401546001600160a01b0390931694509092909185565b60095481565b60055481565b60035481565b61079a611b78565b6001600160a01b03166107ab6110bb565b6001600160a01b0316146107f4576040805162461bcd60e51b8152602060048201819052602482015260008051602061229f833981519152604482015290519081900360640190fd5b801561080257610802610d9f565b610845826108396007868154811061081657fe5b906000526020600020906005020160010154600954611b7c90919063ffffffff16565b9063ffffffff611a6316565b600981905550816007848154811061085957fe5b906000526020600020906005020160010181905550505050565b600a5481565b610881611b78565b6001600160a01b03166108926110bb565b6001600160a01b0316146108db576040805162461bcd60e51b8152602060048201819052602482015260008051602061229f833981519152604482015290519081900360640190fd5b600355565b6000600782815481106108ef57fe5b90600052602060002090600502019050806002015443116109105750610cfb565b8054604080516370a0823160e01b815230600482015290516000926001600160a01b0316916370a08231916024808301926020929190829003018186803b15801561095a57600080fd5b505afa15801561096e573d6000803e3d6000fd5b505050506040513d602081101561098457600080fd5b505190508061099a575043600290910155610cfb565b60006109aa8360020154436110ca565b905060006109dd6009546106c386600101546109d160035487611abb90919063ffffffff16565b9063ffffffff611abb16565b6001546002549192506001600160a01b03908116916340c10f199116610a0a84600a63ffffffff611b1416565b6040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050600060405180830381600087803b158015610a5957600080fd5b505af1158015610a6d573d6000803e3d6000fd5b5050600154604080516340c10f1960e01b81523060048201526024810186905290516001600160a01b0390921693506340c10f19925060448082019260009290919082900301818387803b158015610ac457600080fd5b505af1158015610ad8573d6000803e3d6000fd5b50505050610b0c610afb846106c364e8d4a5100085611abb90919063ffffffff16565b60038601549063ffffffff611a6316565b60038501556005544311610bc6576001546002546006546001600160a01b039283169263282d3fdf921690610b5490612710906106c3906109d188600a63ffffffff611b1416565b6040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050600060405180830381600087803b158015610ba357600080fd5b505af1158015610bb7573d6000803e3d6000fd5b50505060038501546004860155505b60055443118015610bdc57506005548460020154105b15610ced576000610c166009546106c387600101546109d16003546109d16004546109d18d60020154600554611b7c90919063ffffffff16565b6001546002546006549293506001600160a01b039182169263282d3fdf9290911690610c4f90612710906106c3906109d188600a611b14565b6040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050600060405180830381600087803b158015610c9e57600080fd5b505af1158015610cb2573d6000803e3d6000fd5b50505050610ce6610cd5856106c364e8d4a5100085611abb90919063ffffffff16565b60048701549063ffffffff611a6316565b6004860155505b438460020181905550505050505b50565b600060078281548110610d0d57fe5b60009182526020808320858452600882526040808520338087529352909320805460059093029093018054909450610d58926001600160a01b0391909116919063ffffffff611bd916565b80546040805191825251849133917fbb757047c2b5f3974fe26b7c10f732e7bce710b0952a71082702781e62ae05959181900360200190a360008082556001909101555050565b60075460005b81811015610dbe57610db6816108e0565b600101610da5565b5050565b610dca611b78565b6001600160a01b0316610ddb6110bb565b6001600160a01b031614610e24576040805162461bcd60e51b8152602060048201819052602482015260008051602061229f833981519152604482015290519081900360640190fd5b600080546040516001600160a01b03909116906000805160206122bf833981519152908390a3600080546001600160a01b0319169055565b610e64611b78565b6001600160a01b0316610e756110bb565b6001600160a01b031614610ebe576040805162461bcd60e51b8152602060048201819052602482015260008051602061229f833981519152604482015290519081900360640190fd5b8015610ecc57610ecc610d9f565b6001600160a01b038216610f22576040805162461bcd60e51b815260206004820152601860248201527730b2321d103737ba1039ba30b5b2aa37b5b2b71030b2323960411b604482015290519081900360640190fd5b610f2b8261130e565b15610f73576040805162461bcd60e51b815260206004820152601360248201527206164643a207374616b65546f6b656e2064757606c1b604482015290519081900360640190fd5b6000600a544311610f8657600a54610f88565b435b600954909150610f9e908563ffffffff611a6316565b6009556040805160a0810182526001600160a01b039485168152602081019586529081019182526000606082018181526080830182815260078054600181018255935292517fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c688600590930292830180546001600160a01b031916919097161790955594517fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c68986015590517fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c68a85015591517fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c68b84015550517fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c68c90910155565b6000546001600160a01b031690565b600060055482116110f3576004546110ec906109d1848663ffffffff611b7c16565b9050611142565b600554831061110c576110ec828463ffffffff611b7c16565b61113f61112460055484611b7c90919063ffffffff16565b6108396004546109d187600554611b7c90919063ffffffff16565b90505b92915050565b60086020908152600092835260408084209091529082529020805460018201546002830154600390930154919290916001600160a01b031684565b6000806007848154811061119357fe5b600091825260208083208784526008825260408085206001600160a01b0389811687529084528186206005959095029092016003810154815483516370a0823160e01b815230600482015293519298509596909590949316926370a082319260248082019391829003018186803b15801561120d57600080fd5b505afa158015611221573d6000803e3d6000fd5b505050506040513d602081101561123757600080fd5b505160028501549091504311801561124e57508015155b156112ba5760006112638560020154436110ca565b9050600061128a6009546106c388600101546109d160035487611abb90919063ffffffff16565b90506112b56112a8846106c38464e8d4a5100063ffffffff611abb16565b859063ffffffff611a6316565b935050505b6112ee83600101546112e264e8d4a510006106c3868860000154611abb90919063ffffffff16565b9063ffffffff611b7c16565b979650505050505050565b6001546001600160a01b031681565b60045481565b600754600090815b8181101561136857836001600160a01b03166007828154811061133557fe5b60009182526020909120600590910201546001600160a01b031614156113605760019250505061136f565b600101611316565b5060009150505b919050565b61137f838383611c2b565b505050565b60065481565b60008181526008602090815260408083206001600160a01b0386168452909152902054610dbe9083908390611c2b565b6002546001600160a01b03163314611405576040805162461bcd60e51b81526020600482015260096024820152686465763a207775743f60b81b604482015290519081900360640190fd5b600280546001600160a01b0319166001600160a01b0392909216919091179055565b6002546001600160a01b031681565b60006007828154811061144557fe5b60009182526020808320858452600882526040808520338652909252922060059091029091019150611476836108e0565b61148033846117ab565b600382015481546114a19164e8d4a51000916106c39163ffffffff611abb16565b6001820155600482015481546114c79164e8d4a51000916106c39163ffffffff611abb16565b6002909101555050565b6114d9611b78565b6001600160a01b03166114ea6110bb565b6001600160a01b031614611533576040805162461bcd60e51b8152602060048201819052602482015260008051602061229f833981519152604482015290519081900360640190fd5b60015460408051637262ffa360e11b81526001600160a01b038581166004830152602482018590529151919092169163e4c5ff4691604480830192600092919082900301818387803b15801561158857600080fd5b505af115801561159c573d6000803e3d6000fd5b505050505050565b6115ac611b78565b6001600160a01b03166115bd6110bb565b6001600160a01b031614611606576040805162461bcd60e51b8152602060048201819052602482015260008051602061229f833981519152604482015290519081900360640190fd5b6001600160a01b03811661164b5760405162461bcd60e51b81526004018080602001828103825260268152602001806122326026913960400191505060405180910390fd5b600080546040516001600160a01b03808516939216916000805160206122bf83398151915291a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b61169c611b78565b6001600160a01b03166116ad6110bb565b6001600160a01b0316146116f6576040805162461bcd60e51b8152602060048201819052602482015260008051602061229f833981519152604482015290519081900360640190fd5b438211611748576040805162461bcd60e51b815260206004820152601b60248201527a736574426f6e75733a2062616420626f6e7573456e64426c6f636b60281b604482015290519081900360640190fd5b6001831161179d576040805162461bcd60e51b815260206004820152601d60248201527f736574426f6e75733a2062616420626f6e75734d756c7469706c696572000000604482015290519081900360640190fd5b600492909255600555600655565b6000600782815481106117ba57fe5b600091825260208083208584526008825260408085206001600160a01b03891686529092529220805460059092029092019250611833576040805162461bcd60e51b81526020600482015260126024820152711b9bdd1a1a5b99c81d1bc81a185c9d995cdd60721b604482015290519081900360640190fd5b600061186182600101546112e264e8d4a510006106c387600301548760000154611abb90919063ffffffff16565b600154604080516370a0823160e01b815230600482015290519293506001600160a01b03909116916370a0823191602480820192602092909190829003018186803b1580156118af57600080fd5b505afa1580156118c3573d6000803e3d6000fd5b505050506040513d60208110156118d957600080fd5b5051811115611927576040805162461bcd60e51b8152602060048201526015602482015274777466206e6f7420656e6f75676820616c7061636160581b604482015290519081900360640190fd5b600061195583600201546112e264e8d4a510006106c388600401548860000154611abb90919063ffffffff16565b90506119618683611ddc565b6001546006546001600160a01b039091169063282d3fdf90889061199490612710906106c390879063ffffffff611abb16565b6040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b0316815260200182815260200192505050600060405180830381600087803b1580156119e357600080fd5b505af11580156119f7573d6000803e3d6000fd5b50505050505050505050565b604080516001600160a01b0380861660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b179052611a5d908590611f6c565b50505050565b60008282018381101561113f576040805162461bcd60e51b815260206004820152601b60248201527a536166654d6174683a206164646974696f6e206f766572666c6f7760281b604482015290519081900360640190fd5b600082611aca57506000611142565b82820282848281611ad757fe5b041461113f5760405162461bcd60e51b815260040180806020018281038252602181526020018061227e6021913960400191505060405180910390fd5b6000808211611b67576040805162461bcd60e51b815260206004820152601a602482015279536166654d6174683a206469766973696f6e206279207a65726f60301b604482015290519081900360640190fd5b818381611b7057fe5b049392505050565b3390565b600082821115611bd3576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b17905261137f908490611f6c565b600060078381548110611c3a57fe5b600091825260208083208684526008825260408085206001600160a01b03808b1687529352909320600381015460059093029093019350163314611cb3576040805162461bcd60e51b815260206004820152600b60248201526a37b7363c90333ab73232b960a91b604482015290519081900360640190fd5b8054831115611cfe576040805162461bcd60e51b81526020600482015260126024820152711dda5d1a191c985dce881b9bdd0819dbdbd960721b604482015290519081900360640190fd5b611d07846108e0565b611d1185856117ab565b8054611d23908463ffffffff611b7c16565b8082556003830154611d469164e8d4a51000916106c3919063ffffffff611abb16565b600182015560048201548154611d6c9164e8d4a51000916106c39163ffffffff611abb16565b600282015581546001600160a01b031615611d9d578154611d9d906001600160a01b0316338563ffffffff611bd916565b80546040805191825251859133917ff279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b5689181900360200190a35050505050565b600154604080516370a0823160e01b815230600482015290516000926001600160a01b0316916370a08231916024808301926020929190829003018186803b158015611e2757600080fd5b505afa158015611e3b573d6000803e3d6000fd5b505050506040513d6020811015611e5157600080fd5b5051905080821115611ee5576001546040805163a9059cbb60e01b81526001600160a01b038681166004830152602482018590529151919092169163a9059cbb9160448083019260209291908290030181600087803b158015611eb357600080fd5b505af1158015611ec7573d6000803e3d6000fd5b505050506040513d6020811015611edd57600080fd5b5061137f9050565b6001546040805163a9059cbb60e01b81526001600160a01b038681166004830152602482018690529151919092169163a9059cbb9160448083019260209291908290030181600087803b158015611f3b57600080fd5b505af1158015611f4f573d6000803e3d6000fd5b505050506040513d6020811015611f6557600080fd5b5050505050565b6060611fc1826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661201d9092919063ffffffff16565b80519091501561137f57808060200190516020811015611fe057600080fd5b505161137f5760405162461bcd60e51b815260040180806020018281038252602a8152602001806122df602a913960400191505060405180910390fd5b606061202c8484600085612036565b90505b9392505050565b6060824710156120775760405162461bcd60e51b81526004018080602001828103825260268152602001806122586026913960400191505060405180910390fd5b61208085612187565b6120d1576040805162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015290519081900360640190fd5b60006060866001600160a01b031685876040518082805190602001908083835b602083106121105780518252601f1990920191602091820191016120f1565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d8060008114612172576040519150601f19603f3d011682016040523d82523d6000602084013e612177565b606091505b50915091506112ee82828661218d565b3b151590565b6060831561219c57508161202f565b8251156121ac5782518084602001fd5b8160405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156121f65781810151838201526020016121de565b50505050905090810190601f1680156122235780820380516001836020036101000a031916815260200191505b509250505060405180910390fdfe4f776e61626c653a206e6577206f776e657220697320746865207a65726f2061646472657373416464726573733a20696e73756666696369656e742062616c616e636520666f722063616c6c536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f774f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65728be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05361666545524332303a204552433230206f7065726174696f6e20646964206e6f742073756363656564a2646970667358221220deaba612b3b2639dc3a6dc11103eea812808bfa54c86cafc6abdce84d70aa1e264736f6c63430006060033", + "abi": [{"inputs":[{"internalType":"contract AlpacaToken","name":"_alpaca","type":"address"},{"internalType":"address","name":"_devaddr","type":"address"},{"internalType":"uint256","name":"_alpacaPerBlock","type":"uint256"},{"internalType":"uint256","name":"_startBlock","type":"uint256"},{"internalType":"uint256","name":"_bonusLockupBps","type":"uint256"},{"internalType":"uint256","name":"_bonusEndBlock","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"EmergencyWithdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[{"internalType":"uint256","name":"_allocPoint","type":"uint256"},{"internalType":"address","name":"_stakeToken","type":"address"},{"internalType":"bool","name":"_withUpdate","type":"bool"}],"name":"addPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"alpaca","outputs":[{"internalType":"contract AlpacaToken","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"alpacaPerBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bonusEndBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bonusLockUpBps","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bonusMultiplier","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_for","type":"address"},{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"devaddr","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"}],"name":"emergencyWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_lastRewardBlock","type":"uint256"},{"internalType":"uint256","name":"_currentBlock","type":"uint256"}],"name":"getMultiplier","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"}],"name":"harvest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_stakeToken","type":"address"}],"name":"isDuplicatedPool","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"manualMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"massUpdatePools","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"address","name":"_user","type":"address"}],"name":"pendingAlpaca","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"poolInfo","outputs":[{"internalType":"address","name":"stakeToken","type":"address"},{"internalType":"uint256","name":"allocPoint","type":"uint256"},{"internalType":"uint256","name":"lastRewardBlock","type":"uint256"},{"internalType":"uint256","name":"accAlpacaPerShare","type":"uint256"},{"internalType":"uint256","name":"accAlpacaPerShareTilBonusEnd","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poolLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_alpacaPerBlock","type":"uint256"}],"name":"setAlpacaPerBlock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_bonusMultiplier","type":"uint256"},{"internalType":"uint256","name":"_bonusEndBlock","type":"uint256"},{"internalType":"uint256","name":"_bonusLockUpBps","type":"uint256"}],"name":"setBonus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_devaddr","type":"address"}],"name":"setDev","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"uint256","name":"_allocPoint","type":"uint256"},{"internalType":"bool","name":"_withUpdate","type":"bool"}],"name":"setPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"startBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalAllocPoint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"}],"name":"updatePool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"userInfo","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"rewardDebt","type":"uint256"},{"internalType":"uint256","name":"bonusDebt","type":"uint256"},{"internalType":"address","name":"fundedBy","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_for","type":"address"},{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_for","type":"address"},{"internalType":"uint256","name":"_pid","type":"uint256"}],"name":"withdrawAll","outputs":[],"stateMutability":"nonpayable","type":"function"}] +} diff --git a/assets/bsc/AlpacaToken.json b/assets/bsc/AlpacaToken.json new file mode 100644 index 00000000..b59ee146 --- /dev/null +++ b/assets/bsc/AlpacaToken.json @@ -0,0 +1,4 @@ +{ + "bytecode": "60806040526a9b828c6bde7e823c0000006006556a069e10de76676d08000000600a556000600b553480156200003457600080fd5b506040516200323b3803806200323b833981810160405260408110156200005a57600080fd5b508051602091820151604080518082018252600b81526a20b63830b1b0aa37b5b2b760a91b81860190815282518084019093526006835265414c5041434160d01b958301959095528051939492939092620000b99160039190620009a8565b508051620000cf906004906020840190620009a8565b50506005805460ff19166012179055506000620000f46001600160e01b03620001d016565b60058054610100600160a81b0319166101006001600160a01b03841690810291909117909155604051919250906000907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a3508181116200018a5760405162461bcd60e51b8152600401808060200182810382526023815260200180620032186023913960400191505060405180910390fd5b6200019f60126001600160e01b03620001d516565b60088290556009819055620001c8336934f086f3b33b684000006001600160e01b03620001eb16565b505062000a4a565b335b90565b6005805460ff191660ff92909216919091179055565b620001fe6001600160e01b03620001d016565b6001600160a01b03166200021a6001600160e01b03620002d816565b6001600160a01b03161462000265576040805162461bcd60e51b81526020600482018190526024820152600080516020620031c2833981519152604482015290519081900360640190fd5b600a54600b541115620002bf576040805162461bcd60e51b815260206004820152601360248201527f6d696e74206c696d697420657863656564656400000000000000000000000000604482015290519081900360640190fd5b620002d482826001600160e01b03620002ec16565b5050565b60055461010090046001600160a01b031690565b620002ff6001600160e01b03620001d016565b6001600160a01b03166200031b6001600160e01b03620002d816565b6001600160a01b03161462000366576040805162461bcd60e51b81526020600482018190526024820152600080516020620031c2833981519152604482015290519081900360640190fd5b620003796001600160e01b036200042d16565b620003a582620003916001600160e01b036200043316565b6200043960201b62001ddc1790919060201c565b1115620003e8576040805162461bcd60e51b815260206004820152600c60248201526b18d85c08195e18d95959195960a21b604482015290519081900360640190fd5b620003fd82826001600160e01b036200049b16565b6001600160a01b038083166000908152600e6020526040812054620002d49216836001600160e01b03620005b316565b60065490565b60025490565b60008282018381101562000494576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b9392505050565b6001600160a01b038216620004f7576040805162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015290519081900360640190fd5b6200050e600083836001600160e01b036200073216565b6200052a816002546200043960201b62001ddc1790919060201c565b6002556001600160a01b038216600090815260208181526040909120546200055d91839062001ddc62000439821b17901c565b6001600160a01b0383166000818152602081815260408083209490945583518581529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35050565b816001600160a01b0316836001600160a01b031614158015620005d65750600081115b1562000732576001600160a01b0383161562000687576001600160a01b03831660009081526010602052604081205463ffffffff1690816200061a5760006200064c565b6001600160a01b0385166000908152600f6020908152604080832063ffffffff60001987011684529091529020600101545b905060006200066a84836200073760201b62001ad61790919060201c565b905062000683868484846001600160e01b036200079516565b5050505b6001600160a01b0382161562000732576001600160a01b03821660009081526010602052604081205463ffffffff169081620006c5576000620006f7565b6001600160a01b0384166000908152600f6020908152604080832063ffffffff60001987011684529091529020600101545b905060006200071584836200043960201b62001ddc1790919060201c565b90506200072e858484846001600160e01b036200079516565b5050505b505050565b6000828211156200078f576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b6000620007c543604051806060016040528060368152602001620031e2603691396001600160e01b036200090916565b905060008463ffffffff161180156200080f57506001600160a01b0385166000908152600f6020908152604080832063ffffffff6000198901811685529252909120548282169116145b156200084e576001600160a01b0385166000908152600f6020908152604080832063ffffffff60001989011684529091529020600101829055620008bf565b60408051808201825263ffffffff808416825260208083018681526001600160a01b038a166000818152600f84528681208b8616825284528681209551865490861663ffffffff19918216178755925160019687015590815260109092529390208054928801909116919092161790555b604080518481526020810184905281516001600160a01b038816927fdec2bacdd2f05b59de34da9b523dff8be42e5e38e818c82fdb0bae774387a724928290030190a25050505050565b6000816401000000008410620009a05760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015620009645781810151838201526020016200094a565b50505050905090810190601f168015620009925780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b509192915050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10620009eb57805160ff191683800117855562000a1b565b8280016001018555821562000a1b579182015b8281111562000a1b578251825591602001919060010190620009fe565b5062000a2992915062000a2d565b5090565b620001d291905b8082111562000a29576000815560010162000a34565b6127688062000a5a6000396000f3fe608060405234801561001057600080fd5b50600436106101ee5760003560e01c806306fdde03146101f3578063095ea7b31461027057806318160ddd146102b0578063202b1760146102ca57806320606b70146102f057806323b872dd146102f8578063282d3fdf1461032e578063313ce5671461035c578063355274ea1461037a57806339509351146103825780633a1aae35146103ae57806340c10f19146103b65780634b0ee02a146103e2578063587cde1e146104085780635a46d3b51461044a5780635c19a95c146104705780636fcfff451461049657806370a08231146104d5578063715018a6146104fb578063782d6fe1146105035780637ecebe001461052f5780637ee416151461055557806389a2867c1461055d5780638da5cb5b1461058357806395d89b411461058b5780639dc29fac14610593578063a3a7e7f3146105bf578063a457c2d7146105e5578063a69df4b514610611578063a9059cbb14610619578063b4b5ea5714610645578063c3cda5201461066b578063ce4079ef146106b2578063d68afa39146106ba578063dd62ed3e146106dd578063e4c5ff461461070b578063e6b2fb4a14610737578063e7a324dc1461073f578063f1127ed814610747578063f2fde38b14610799578063f85b84a4146107bf578063fd3d27b8146107c7575b600080fd5b6101fb6107cf565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561023557818101518382015260200161021d565b50505050905090810190601f1680156102625780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61029c6004803603604081101561028657600080fd5b506001600160a01b038135169060200135610865565b604080519115158252519081900360200190f35b6102b8610883565b60408051918252519081900360200190f35b6102b8600480360360208110156102e057600080fd5b50356001600160a01b0316610889565b6102b8610967565b61029c6004803603606081101561030e57600080fd5b506001600160a01b03813581169160208101359091169060400135610982565b61035a6004803603604081101561034457600080fd5b506001600160a01b038135169060200135610a0f565b005b610364610bfd565b6040805160ff9092168252519081900360200190f35b6102b8610c06565b61029c6004803603604081101561039857600080fd5b506001600160a01b038135169060200135610c0c565b6102b8610c60565b61035a600480360360408110156103cc57600080fd5b506001600160a01b038135169060200135610c66565b6102b8600480360360208110156103f857600080fd5b50356001600160a01b0316610d5d565b61042e6004803603602081101561041e57600080fd5b50356001600160a01b0316610d90565b604080516001600160a01b039092168252519081900360200190f35b6102b86004803603602081101561046057600080fd5b50356001600160a01b0316610dae565b61035a6004803603602081101561048657600080fd5b50356001600160a01b0316610dc9565b6104bc600480360360208110156104ac57600080fd5b50356001600160a01b0316610dd6565b6040805163ffffffff9092168252519081900360200190f35b6102b8600480360360208110156104eb57600080fd5b50356001600160a01b0316610dee565b61035a610e09565b6102b86004803603604081101561051957600080fd5b506001600160a01b038135169060200135610ea9565b6102b86004803603602081101561054557600080fd5b50356001600160a01b03166110b1565b6102b86110c3565b6102b86004803603602081101561057357600080fd5b50356001600160a01b03166110c9565b61042e6110e4565b6101fb6110f8565b61035a600480360360408110156105a957600080fd5b506001600160a01b038135169060200135611159565b61035a600480360360208110156105d557600080fd5b50356001600160a01b03166111c5565b61029c600480360360408110156105fb57600080fd5b506001600160a01b0381351690602001356112b9565b61035a611327565b61029c6004803603604081101561062f57600080fd5b506001600160a01b0381351690602001356113eb565b6102b86004803603602081101561065b57600080fd5b50356001600160a01b03166113ff565b61035a600480360360c081101561068157600080fd5b506001600160a01b038135169060208101359060408101359060ff6060820135169060808101359060a00135611463565b6102b86116d9565b61035a600480360360408110156106d057600080fd5b50803590602001356116df565b6102b8600480360360408110156106f357600080fd5b506001600160a01b038135811691602001351661178a565b61035a6004803603604081101561072157600080fd5b506001600160a01b0381351690602001356117b5565b6102b8611870565b6102b8611876565b6107796004803603604081101561075d57600080fd5b5080356001600160a01b0316906020013563ffffffff16611891565b6040805163ffffffff909316835260208301919091528051918290030190f35b61035a600480360360208110156107af57600080fd5b50356001600160a01b03166118be565b6102b86119ba565b6102b86119c0565b60038054604080516020601f600260001961010060018816150201909516949094049384018190048102820181019092528281526060939092909183018282801561085b5780601f106108305761010080835404028352916020019161085b565b820191906000526020600020905b81548152906001019060200180831161083e57829003601f168201915b5050505050905090565b60006108796108726119e6565b84846119ea565b5060015b92915050565b60025490565b600060085443101561089d57506000610962565b60095443106108c557506001600160a01b0381166000908152600c6020526040902054610962565b6001600160a01b0382166000908152600d60205260408120546108ef90439063ffffffff611ad616565b6001600160a01b0384166000908152600d6020526040812054600954929350909161091f9163ffffffff611ad616565b6001600160a01b0385166000908152600c602052604090205490915061095d908290610951908563ffffffff611b3316565b9063ffffffff611b8c16565b925050505b919050565b6040518060436124fd82396043019050604051809103902081565b600061098f848484611bf0565b610a058461099b6119e6565b610a0085604051806060016040528060288152602001612561602891396001600160a01b038a166000908152600160205260408120906109d96119e6565b6001600160a01b03168152602081019190915260400160002054919063ffffffff611d4516565b6119ea565b5060019392505050565b610a176119e6565b6001600160a01b0316610a286110e4565b6001600160a01b031614610a71576040805162461bcd60e51b81526020600482018190526024820152600080516020612589833981519152604482015290519081900360640190fd5b6001600160a01b038216610ac4576040805162461bcd60e51b81526020600482015260156024820152746e6f206c6f636b20746f206164647265737328302960581b604482015290519081900360640190fd5b610acd82610dee565b811115610b18576040805162461bcd60e51b81526020600482015260146024820152736e6f206c6f636b206f7665722062616c616e636560601b604482015290519081900360640190fd5b610b23823083611bf0565b6001600160a01b0382166000908152600c6020526040902054610b4c908263ffffffff611ddc16565b6001600160a01b0383166000908152600c6020526040902055600754610b78908263ffffffff611ddc16565b6007556008546001600160a01b0383166000908152600d60205260409020541015610bba576008546001600160a01b0383166000908152600d60205260409020555b6040805182815290516001600160a01b038416917f625fed9875dada8643f2418b838ae0bc78d9a148a18eee4ee1979ff0f3f5d427919081900360200190a25050565b60055460ff1690565b60065490565b6000610879610c196119e6565b84610a008560016000610c2a6119e6565b6001600160a01b03908116825260208083019390935260409182016000908120918c16815292529020549063ffffffff611ddc16565b60075490565b610c6e6119e6565b6001600160a01b0316610c7f6110e4565b6001600160a01b031614610cc8576040805162461bcd60e51b81526020600482018190526024820152600080516020612589833981519152604482015290519081900360640190fd5b610cd0610c06565b610ce882610cdc610883565b9063ffffffff611ddc16565b1115610d2a576040805162461bcd60e51b815260206004820152600c60248201526b18d85c08195e18d95959195960a21b604482015290519081900360640190fd5b610d348282611e34565b6001600160a01b038083166000908152600e6020526040812054610d59921683611f1e565b5050565b600061087d610d6b83610dee565b6001600160a01b0384166000908152600c60205260409020549063ffffffff611ddc16565b6001600160a01b039081166000908152600e60205260409020541690565b6001600160a01b03166000908152600c602052604090205490565b610dd3338261206c565b50565b60106020526000908152604090205463ffffffff1681565b6001600160a01b031660009081526020819052604090205490565b610e116119e6565b6001600160a01b0316610e226110e4565b6001600160a01b031614610e6b576040805162461bcd60e51b81526020600482018190526024820152600080516020612589833981519152604482015290519081900360640190fd5b60055460405160009161010090046001600160a01b0316906000805160206125a9833981519152908390a360058054610100600160a81b0319169055565b6000438210610ee95760405162461bcd60e51b815260040180806020018281038252602981526020018061241a6029913960400191505060405180910390fd5b6001600160a01b03831660009081526010602052604090205463ffffffff1680610f1757600091505061087d565b6001600160a01b0384166000908152600f6020908152604080832063ffffffff600019860181168552925290912054168310610f86576001600160a01b0384166000908152600f602090815260408083206000199490940163ffffffff1683529290522060010154905061087d565b6001600160a01b0384166000908152600f6020908152604080832083805290915290205463ffffffff16831015610fc157600091505061087d565b600060001982015b8163ffffffff168163ffffffff16111561107a57600282820363ffffffff16048103610ff36123bd565b506001600160a01b0387166000908152600f6020908152604080832063ffffffff8086168552908352928190208151808301909252805490931680825260019093015491810191909152908714156110555760200151945061087d9350505050565b805163ffffffff1687111561106c57819350611073565b6001820392505b5050610fc9565b506001600160a01b0385166000908152600f6020908152604080832063ffffffff9094168352929052206001015491505092915050565b60116020526000908152604090205481565b60085481565b6001600160a01b03166000908152600d602052604090205490565b60055461010090046001600160a01b031690565b60048054604080516020601f600260001961010060018816150201909516949094049384018190048102820181019092528281526060939092909183018282801561085b5780601f106108305761010080835404028352916020019161085b565b6111616119e6565b6001600160a01b03166111726110e4565b6001600160a01b0316146111bb576040805162461bcd60e51b81526020600482018190526024820152600080516020612589833981519152604482015290519081900360640190fd5b610d598282612101565b336000908152600c6020526040808220546001600160a01b03841683529120546111f49163ffffffff611ddc16565b6001600160a01b0382166000908152600c6020908152604080832093909355600854600d909152919020541015611242576008546001600160a01b0382166000908152600d60205260409020555b336000908152600d6020526040808220546001600160a01b0384168352912054101561128957336000908152600d6020526040808220546001600160a01b03841683529120555b336000818152600c60209081526040808320839055600d909152812055610dd390826112b482610dee565b611bf0565b60006108796112c66119e6565b84610a00856040518060600160405280602581526020016126eb60259139600160006112f06119e6565b6001600160a01b03908116825260208083019390935260409182016000908120918d1681529252902054919063ffffffff611d4516565b336000908152600c602052604090205461137c576040805162461bcd60e51b81526020600482015260116024820152706e6f206c6f636b656420414c504143417360781b604482015290519081900360640190fd5b600061138733610889565b9050611394303383611bf0565b336000908152600c60205260409020546113b4908263ffffffff611ad616565b336000908152600c6020908152604080832093909355600d9052204390556007546113e5908263ffffffff611ad616565b60075550565b60006108796113f86119e6565b8484611bf0565b6001600160a01b03811660009081526010602052604081205463ffffffff168061142a57600061145c565b6001600160a01b0383166000908152600f6020908152604080832063ffffffff60001986011684529091529020600101545b9392505050565b600060405180806124fd60439139604301905060405180910390206114866107cf565b805190602001206114956121f7565b3060405160200180858152602001848152602001838152602001826001600160a01b03166001600160a01b03168152602001945050505050604051602081830303815290604052805190602001209050600060405180806126b1603a91396040805191829003603a0182206020808401919091526001600160a01b038c1683830152606083018b905260808084018b90528251808503909101815260a08401835280519082012061190160f01b60c085015260c2840187905260e2808501829052835180860390910181526101028501808552815191840191909120600091829052610122860180865281905260ff8c1661014287015261016286018b905261018286018a9052935191965092945091926001926101a28083019392601f198301929081900390910190855afa1580156115d3573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166116255760405162461bcd60e51b815260040180806020018281038252602881526020018061262f6028913960400191505060405180910390fd5b6001600160a01b038116600090815260116020526040902080546001810190915589146116835760405162461bcd60e51b81526004018080602001828103825260248152602001806124b36024913960400191505060405180910390fd5b874211156116c25760405162461bcd60e51b815260040180806020018281038252602881526020018061248b6028913960400191505060405180910390fd5b6116cc818b61206c565b505050505b505050505050565b60095481565b6116e76119e6565b6001600160a01b03166116f86110e4565b6001600160a01b031614611741576040805162461bcd60e51b81526020600482018190526024820152600080516020612589833981519152604482015290519081900360640190fd5b81811161177f5760405162461bcd60e51b81526004018080602001828103825260238152602001806127106023913960400191505060405180910390fd5b600891909155600955565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b6117bd6119e6565b6001600160a01b03166117ce6110e4565b6001600160a01b031614611817576040805162461bcd60e51b81526020600482018190526024820152600080516020612589833981519152604482015290519081900360640190fd5b600a54600b541115611866576040805162461bcd60e51b81526020600482015260136024820152721b5a5b9d081b1a5b5a5d08195e18d959591959606a1b604482015290519081900360640190fd5b610d598282610c66565b600b5481565b60405180603a6126b18239603a019050604051809103902081565b600f6020908152600092835260408084209091529082529020805460019091015463ffffffff9091169082565b6118c66119e6565b6001600160a01b03166118d76110e4565b6001600160a01b031614611920576040805162461bcd60e51b81526020600482018190526024820152600080516020612589833981519152604482015290519081900360640190fd5b6001600160a01b0381166119655760405162461bcd60e51b81526004018080602001828103825260268152602001806124436026913960400191505060405180910390fd5b6005546040516001600160a01b0380841692610100900416906000805160206125a983398151915290600090a3600580546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b600a5481565b60006119e16119cd610c60565b6119d5610883565b9063ffffffff611ad616565b905090565b3390565b6001600160a01b038316611a2f5760405162461bcd60e51b81526004018080602001828103825260248152602001806126576024913960400191505060405180910390fd5b6001600160a01b038216611a745760405162461bcd60e51b81526004018080602001828103825260228152602001806124696022913960400191505060405180910390fd5b6001600160a01b03808416600081815260016020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b600082821115611b2d576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b600082611b425750600061087d565b82820282848281611b4f57fe5b041461145c5760405162461bcd60e51b81526004018080602001828103825260218152602001806125406021913960400191505060405180910390fd5b6000808211611bdf576040805162461bcd60e51b815260206004820152601a602482015279536166654d6174683a206469766973696f6e206279207a65726f60301b604482015290519081900360640190fd5b818381611be857fe5b049392505050565b6001600160a01b038316611c355760405162461bcd60e51b815260040180806020018281038252602581526020018061260a6025913960400191505060405180910390fd5b6001600160a01b038216611c7a5760405162461bcd60e51b81526004018080602001828103825260238152602001806123d56023913960400191505060405180910390fd5b611c85838383612067565b611cc8816040518060600160405280602681526020016124d7602691396001600160a01b038616600090815260208190526040902054919063ffffffff611d4516565b6001600160a01b038085166000908152602081905260408082209390935590841681522054611cfd908263ffffffff611ddc16565b6001600160a01b038084166000818152602081815260409182902094909455805185815290519193928716926000805160206125c983398151915292918290030190a3505050565b60008184841115611dd45760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015611d99578181015183820152602001611d81565b50505050905090810190601f168015611dc65780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b60008282018381101561145c576040805162461bcd60e51b815260206004820152601b60248201527a536166654d6174683a206164646974696f6e206f766572666c6f7760281b604482015290519081900360640190fd5b6001600160a01b038216611e8f576040805162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015290519081900360640190fd5b611e9b60008383612067565b600254611eae908263ffffffff611ddc16565b6002556001600160a01b038216600090815260208190526040902054611eda908263ffffffff611ddc16565b6001600160a01b0383166000818152602081815260408083209490945583518581529351929391926000805160206125c98339815191529281900390910190a35050565b816001600160a01b0316836001600160a01b031614158015611f405750600081115b15612067576001600160a01b03831615611fd8576001600160a01b03831660009081526010602052604081205463ffffffff169081611f80576000611fb2565b6001600160a01b0385166000908152600f6020908152604080832063ffffffff60001987011684529091529020600101545b90506000611fc6828563ffffffff611ad616565b9050611fd4868484846121fb565b5050505b6001600160a01b03821615612067576001600160a01b03821660009081526010602052604081205463ffffffff169081612013576000612045565b6001600160a01b0384166000908152600f6020908152604080832063ffffffff60001987011684529091529020600101545b90506000612059828563ffffffff611ddc16565b90506116d1858484846121fb565b505050565b6001600160a01b038083166000908152600e60205260408120549091169061209384610dee565b6001600160a01b038581166000818152600e602052604080822080546001600160a01b031916898616908117909155905194955093928616927f3134e8a2e6d97e929a7e54011ea5485d7d196dd5f0ba4d4ef95803e8e3fc257f9190a46120fb828483611f1e565b50505050565b6001600160a01b0382166121465760405162461bcd60e51b81526004018080602001828103825260218152602001806125e96021913960400191505060405180910390fd5b61215282600083612067565b612195816040518060600160405280602281526020016123f8602291396001600160a01b038516600090815260208190526040902054919063ffffffff611d4516565b6001600160a01b0383166000908152602081905260409020556002546121c1908263ffffffff611ad616565b6002556040805182815290516000916001600160a01b038516916000805160206125c98339815191529181900360200190a35050565b4690565b600061221f4360405180606001604052806036815260200161267b60369139612360565b905060008463ffffffff1611801561226857506001600160a01b0385166000908152600f6020908152604080832063ffffffff6000198901811685529252909120548282169116145b156122a5576001600160a01b0385166000908152600f6020908152604080832063ffffffff60001989011684529091529020600101829055612316565b60408051808201825263ffffffff808416825260208083018681526001600160a01b038a166000818152600f84528681208b8616825284528681209551865490861663ffffffff19918216178755925160019687015590815260109092529390208054928801909116919092161790555b604080518481526020810184905281516001600160a01b038816927fdec2bacdd2f05b59de34da9b523dff8be42e5e38e818c82fdb0bae774387a724928290030190a25050505050565b600081600160201b84106123b55760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315611d99578181015183820152602001611d81565b509192915050565b60408051808201909152600080825260208201529056fe45524332303a207472616e7366657220746f20746865207a65726f206164647265737345524332303a206275726e20616d6f756e7420657863656564732062616c616e6365414c504143413a3a6765745072696f72566f7465733a206e6f74207965742064657465726d696e65644f776e61626c653a206e6577206f776e657220697320746865207a65726f206164647265737345524332303a20617070726f766520746f20746865207a65726f2061646472657373414c504143413a3a64656c656761746542795369673a207369676e61747572652065787069726564414c504143413a3a64656c656761746542795369673a20696e76616c6964206e6f6e636545524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e6365454950373132446f6d61696e28737472696e67206e616d652c75696e7432353620636861696e49642c6164647265737320766572696679696e67436f6e747261637429536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f7745524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e63654f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65728be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef45524332303a206275726e2066726f6d20746865207a65726f206164647265737345524332303a207472616e736665722066726f6d20746865207a65726f2061646472657373414c504143413a3a64656c656761746542795369673a20696e76616c6964207369676e617475726545524332303a20617070726f76652066726f6d20746865207a65726f2061646472657373414c504143413a3a5f7772697465436865636b706f696e743a20626c6f636b206e756d6265722065786365656473203332206269747344656c65676174696f6e28616464726573732064656c6567617465652c75696e74323536206e6f6e63652c75696e74323536206578706972792945524332303a2064656372656173656420616c6c6f77616e63652062656c6f77207a65726f656e6452656c65617365426c6f636b203c20737461727452656c65617365426c6f636ba2646970667358221220d14cba8cfdfc68cd304b4f3aa05e1d3557635990fa63d029452b55e718c3117764736f6c634300060600334f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572414c504143413a3a5f7772697465436865636b706f696e743a20626c6f636b206e756d62657220657863656564732033322062697473656e6452656c65617365426c6f636b203c20737461727452656c65617365426c6f636b", + "abi": [{"inputs":[{"internalType":"uint256","name":"_startReleaseBlock","type":"uint256"},{"internalType":"uint256","name":"_endReleaseBlock","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"delegator","type":"address"},{"indexed":true,"internalType":"address","name":"fromDelegate","type":"address"},{"indexed":true,"internalType":"address","name":"toDelegate","type":"address"}],"name":"DelegateChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"delegate","type":"address"},{"indexed":false,"internalType":"uint256","name":"previousBalance","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newBalance","type":"uint256"}],"name":"DelegateVotesChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Lock","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"DELEGATION_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DOMAIN_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"canUnlockAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint32","name":"","type":"uint32"}],"name":"checkpoints","outputs":[{"internalType":"uint32","name":"fromBlock","type":"uint32"},{"internalType":"uint256","name":"votes","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"delegatee","type":"address"}],"name":"delegate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"delegatee","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":"delegateBySig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"delegator","type":"address"}],"name":"delegates","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"endReleaseBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getCurrentVotes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"name":"getPriorVotes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"lastUnlockBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"lock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"lockOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"manualMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"manualMintLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"manualMinted","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"numCheckpoints","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_startReleaseBlock","type":"uint256"},{"internalType":"uint256","name":"_endReleaseBlock","type":"uint256"}],"name":"setReleaseBlock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"startReleaseBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"totalBalanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalLock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"}],"name":"transferAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unlock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unlockedSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}] +} diff --git a/assets/bsc/AlpacaTripleSlopeModel.json b/assets/bsc/AlpacaTripleSlopeModel.json new file mode 100644 index 00000000..1b360c47 --- /dev/null +++ b/assets/bsc/AlpacaTripleSlopeModel.json @@ -0,0 +1,4 @@ +{ + "bytecode": "608060405234801561001057600080fd5b50610457806100206000396000f3fe608060405234801561001057600080fd5b506004361061006d5760003560e01c806304d0d147146100725780630e0857781461008c578063810c6aa814610094578063aa183d9a1461009c578063c6dfa13f146100a4578063cc3c29f9146100c7578063fbf3cb691461008c575b600080fd5b61007a6100cf565b60408051918252519081900360200190f35b61007a6100dc565b61007a6100e8565b61007a6100f5565b61007a600480360360408110156100ba57600080fd5b5080359060200135610101565b61007a61027a565b680340aad21b3b70000081565b6702c68af0bb14000081565b68056bc75e2d6310000081565b6714d1120d7b16000081565b60008215801561010f575081155b1561011c57506000610274565b600061012e848463ffffffff61028716565b9050600061015b8261014f8768056bc75e2d6310000063ffffffff6102e616565b9063ffffffff61033f16565b9050680340aad21b3b7000008110156101a9576301e13380610198680340aad21b3b70000061014f846702c68af0bb14000063ffffffff6102e616565b8161019f57fe5b0492505050610274565b6804e1003b28d92800008110156101cd576301e133806702c68af0bb14000061019f565b68056bc75e2d63100000811015610261576301e1338061025061020868056bc75e2d631000006804e1003b28d928000063ffffffff6103a316565b61014f61022b6714d1120d7b1600006702c68af0bb14000063ffffffff6103a316565b610244866804e1003b28d928000063ffffffff6103a316565b9063ffffffff6102e616565b6702c68af0bb140000018161019f57fe5b6301e133806714d1120d7b16000061019f565b92915050565b6804e1003b28d928000081565b6000828201838110156102df576040805162461bcd60e51b815260206004820152601b60248201527a536166654d6174683a206164646974696f6e206f766572666c6f7760281b604482015290519081900360640190fd5b9392505050565b6000826102f557506000610274565b8282028284828161030257fe5b04146102df5760405162461bcd60e51b81526004018080602001828103825260218152602001806104016021913960400191505060405180910390fd5b6000808211610392576040805162461bcd60e51b815260206004820152601a602482015279536166654d6174683a206469766973696f6e206279207a65726f60301b604482015290519081900360640190fd5b81838161039b57fe5b049392505050565b6000828211156103fa576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b5090039056fe536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77a2646970667358221220281d5584d0b750745667a0521be2cbaad0246dbb9dd4be9fd396b4df27ce2c0764736f6c63430006060033", + "abi": [{"inputs":[],"name":"CEIL_SLOPE_1","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CEIL_SLOPE_2","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CEIL_SLOPE_3","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_INTEREST_SLOPE_1","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_INTEREST_SLOPE_2","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_INTEREST_SLOPE_3","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"debt","type":"uint256"},{"internalType":"uint256","name":"floating","type":"uint256"}],"name":"getInterestRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"}] +} diff --git a/assets/bsc/AlpacaVault.json b/assets/bsc/AlpacaVault.json new file mode 100644 index 00000000..ba954af9 --- /dev/null +++ b/assets/bsc/AlpacaVault.json @@ -0,0 +1,4 @@ +{ + "bytecode": "608060405234801561001057600080fd5b50615a3680620000216000396000f3fe6080604052600436106101f05760003560e01c80630266f044146101fc57806306fdde0314610223578063095ea7b3146102ad5780630a355d7d146102fa57806318160ddd1461030f578063185025ef146103245780631c58ce14146103555780631c8249051461039057806323b872dd146103a55780632e1a7d4d146103e85780632fc11c0f14610412578063313ce5671461043c5780633950935114610467578063494666b6146104a0578063626be567146104d95780636b6216ad146104ee5780636cc919c81461051857806370a082311461054b578063715018a61461057e57806376c46b7b1461059357806379502c55146105a857806381a47ba9146105bd57806389097a6a146105d25780638da5cb5b14610615578063947e81a21461062a57806395d89b411461065457806399fbab88146106695780639ffe7973146106bd578063a457c2d7146106d2578063a9059cbb1461070b578063b6b55f2514610744578063c310964114610761578063c9a4bb3f146107e4578063d29a0025146107f9578063d72ef77114610823578063d7ac71ff146108b9578063dd62ed3e146108ce578063e0a2b5a014610909578063ea7d530f146109ff578063f2fde38b14610a29578063f60290e414610a5c578063f8d8989814610a86578063fc0c546a14610a9b576101f7565b366101f757005b600080fd5b34801561020857600080fd5b50610211610ab0565b60408051918252519081900360200190f35b34801561022f57600080fd5b50610238610ab7565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561027257818101518382015260200161025a565b50505050905090810190601f16801561029f5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3480156102b957600080fd5b506102e6600480360360408110156102d057600080fd5b506001600160a01b038135169060200135610b4e565b604080519115158252519081900360200190f35b34801561030657600080fd5b50610211610b6c565b34801561031b57600080fd5b50610211610b73565b34801561033057600080fd5b50610339610b79565b604080516001600160a01b039092168252519081900360200190f35b34801561036157600080fd5b5061038e6004803603604081101561037857600080fd5b506001600160a01b038135169060200135610b88565b005b34801561039c57600080fd5b50610211610c6f565b3480156103b157600080fd5b506102e6600480360360608110156103c857600080fd5b506001600160a01b03813581169160208101359091169060400135610c76565b3480156103f457600080fd5b5061038e6004803603602081101561040b57600080fd5b5035610d03565b34801561041e57600080fd5b506102116004803603602081101561043557600080fd5b5035610ee7565b34801561044857600080fd5b5061045161100e565b6040805160ff9092168252519081900360200190f35b34801561047357600080fd5b506102e66004803603604081101561048a57600080fd5b506001600160a01b038135169060200135611017565b3480156104ac57600080fd5b5061038e600480360360408110156104c357600080fd5b506001600160a01b03813516906020013561106b565b3480156104e557600080fd5b50610211611198565b3480156104fa57600080fd5b5061038e6004803603602081101561051157600080fd5b50356111d7565b34801561052457600080fd5b5061038e6004803603602081101561053b57600080fd5b50356001600160a01b031661124a565b34801561055757600080fd5b506102116004803603602081101561056e57600080fd5b50356001600160a01b03166112c5565b34801561058a57600080fd5b5061038e6112e0565b34801561059f57600080fd5b50610211611370565b3480156105b457600080fd5b50610339611377565b3480156105c957600080fd5b50610211611387565b3480156105de57600080fd5b506105fc600480360360208110156105f557600080fd5b503561138e565b6040805192835260208301919091528051918290030190f35b34801561062157600080fd5b5061033961142c565b34801561063657600080fd5b5061038e6004803603602081101561064d57600080fd5b503561143b565b34801561066057600080fd5b5061023861151b565b34801561067557600080fd5b506106936004803603602081101561068c57600080fd5b503561157c565b604080516001600160a01b0394851681529290931660208301528183015290519081900360600190f35b3480156106c957600080fd5b506102116115ab565b3480156106de57600080fd5b506102e6600480360360408110156106f557600080fd5b506001600160a01b0381351690602001356115b2565b34801561071757600080fd5b506102e66004803603604081101561072e57600080fd5b506001600160a01b038135169060200135611620565b61038e6004803603602081101561075a57600080fd5b5035611634565b61038e6004803603608081101561077757600080fd5b813591602081013591604082013515159190810190608081016060820135600160201b8111156107a657600080fd5b8201836020820111156107b857600080fd5b803590602001918460018302840111600160201b831117156107d957600080fd5b50909250905061194a565b3480156107f057600080fd5b50610211612755565b34801561080557600080fd5b5061038e6004803603602081101561081c57600080fd5b503561275b565b61038e600480360360c081101561083957600080fd5b8135916001600160a01b03602082013516916040820135916060810135916080820135919081019060c0810160a0820135600160201b81111561087b57600080fd5b82018360208201111561088d57600080fd5b803590602001918460018302840111600160201b831117156108ae57600080fd5b509092509050612e32565b3480156108c557600080fd5b50610211613b03565b3480156108da57600080fd5b50610211600480360360408110156108f157600080fd5b506001600160a01b0381358116916020013516613b09565b34801561091557600080fd5b5061038e600480360360c081101561092c57600080fd5b6001600160a01b038235811692602081013590911691810190606081016040820135600160201b81111561095f57600080fd5b82018360208201111561097157600080fd5b803590602001918460018302840111600160201b8311171561099257600080fd5b919390929091602081019035600160201b8111156109af57600080fd5b8201836020820111156109c157600080fd5b803590602001918460018302840111600160201b831117156109e257600080fd5b9193509150803560ff1690602001356001600160a01b0316613b34565b348015610a0b57600080fd5b5061021160048036036020811015610a2257600080fd5b5035613d1d565b348015610a3557600080fd5b5061038e60048036036020811015610a4c57600080fd5b50356001600160a01b0316613d4f565b348015610a6857600080fd5b5061021160048036036020811015610a7f57600080fd5b5035613e36565b348015610a9257600080fd5b50610339613e68565b348015610aa757600080fd5b50610339613e77565b6101075481565b60688054604080516020601f6002600019610100600188161502019095169490940493840181900481028201810190925282815260609390929091830182828015610b435780601f10610b1857610100808354040283529160200191610b43565b820191906000526020600020905b815481529060010190602001808311610b2657829003601f168201915b505050505090505b90565b6000610b62610b5b613e86565b8484613e8a565b5060015b92915050565b6101055481565b60675490565b60fd546001600160a01b031681565b610b90613e86565b60c9546001600160a01b03908116911614610be0576040805162461bcd60e51b815260206004820181905260248201526000805160206158e4833981519152604482015290519081900360640190fd5b60975460ff16610c25576040805162461bcd60e51b815260206004820152601f60248201526000805160206157cb833981519152604482015290519081900360640190fd5b6097805460ff1916905561010754610c43908263ffffffff613f7616565b6101075560fe54610c5e906001600160a01b03168383613fbf565b50506097805460ff19166001179055565b6101025481565b6000610c83848484614119565b610cf984610c8f613e86565b610cf4856040518060600160405280602881526020016158bc602891396001600160a01b038a16600090815260666020526040812090610ccd613e86565b6001600160a01b03168152602081019190915260400160002054919063ffffffff61427016565b613e8a565b5060019392505050565b600061010654421115610df7576000610d1b82610ee7565b90506000610dbc612710610db061010060009054906101000a90046001600160a01b03166001600160a01b03166309956f666040518163ffffffff1660e01b815260040160206040518083038186803b158015610d7757600080fd5b505afa158015610d8b573d6000803e3d6000fd5b505050506040513d6020811015610da157600080fd5b5051859063ffffffff61430716565b9063ffffffff61436016565b61010754909150610dd3908263ffffffff61439f16565b6101075561010554610deb908363ffffffff61439f16565b61010555505042610106555b60975460ff16610e3c576040805162461bcd60e51b815260206004820152601f60248201526000805160206157cb833981519152604482015290519081900360640190fd5b6097805460ff191690556000610e6b610e53610b73565b610db0610e5e611198565b869063ffffffff61430716565b9050610e7733846143f7565b610e8133826144ed565b67016345785d8a0000610e92610b73565b11610ed5576040805162461bcd60e51b815260206004820152600e60248201526d6e6f2074696e792073686172657360901b604482015290519081900360640190fd5b50506097805460ff1916600117905550565b600061010654421115611005576000610f0c6101065442613f7690919063ffffffff16565b60fe54909150600090610f39908590610f2d906001600160a01b0316614705565b9063ffffffff613f7616565b61010054610105546040805163c6dfa13f60e01b8152600481019290925260248201849052519293506000926001600160a01b039092169163c6dfa13f91604480820192602092909190829003018186803b158015610f9757600080fd5b505afa158015610fab573d6000803e3d6000fd5b505050506040513d6020811015610fc157600080fd5b505161010554909150610ffb90670de0b6b3a764000090610db0908690610fef90869063ffffffff61430716565b9063ffffffff61430716565b9350505050611009565b5060005b919050565b606a5460ff1690565b6000610b62611024613e86565b84610cf48560666000611035613e86565b6001600160a01b03908116825260208083019390935260409182016000908120918c16815292529020549063ffffffff61439f16565b60001960fc5414156110c1576040805162461bcd60e51b815260206004820152601a6024820152796e6f742077697468696e20657865637574696f6e2073636f706560301b604482015290519081900360640190fd5b60fd546001600160a01b03163314611118576040805162461bcd60e51b81526020600482015260156024820152746e6f742066726f6d2074686520737472617465677960581b604482015290519081900360640190fd5b600160fb541461115e576040805162461bcd60e51b815260206004820152600c60248201526b696e2065786563206c6f636b60a01b604482015290519081900360640190fd5b600260fb5560fc546000908152610101602052604090206001015461118f9083906001600160a01b03163384614781565b5050600160fb55565b60006111d261010754610f2d610105546111c660fe60009054906101000a90046001600160a01b0316614705565b9063ffffffff61439f16565b905090565b6111df613e86565b60c9546001600160a01b0390811691161461122f576040805162461bcd60e51b815260206004820181905260248201526000805160206158e4833981519152604482015290519081900360640190fd5b61010754611243908263ffffffff613f7616565b6101075550565b611252613e86565b60c9546001600160a01b039081169116146112a2576040805162461bcd60e51b815260206004820181905260248201526000805160206158e4833981519152604482015290519081900360640190fd5b61010080546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b031660009081526065602052604090205490565b6112e8613e86565b60c9546001600160a01b03908116911614611338576040805162461bcd60e51b815260206004820181905260248201526000805160206158e4833981519152604482015290519081900360640190fd5b60c9546040516000916001600160a01b031690600080516020615904833981519152908390a360c980546001600160a01b0319169055565b6101045481565b610100546001600160a01b031681565b6101035481565b600081815261010160209081526040808320805482516303c1db6b60e51b8152600481018790529251859492936001600160a01b039092169263783b6d609260248082019391829003018186803b1580156113e857600080fd5b505afa1580156113fc573d6000803e3d6000fd5b505050506040513d602081101561141257600080fd5b5051600282015461142290613d1d565b9250925050915091565b60c9546001600160a01b031690565b611443613e86565b60c9546001600160a01b03908116911614611493576040805162461bcd60e51b815260206004820181905260248201526000805160206158e4833981519152604482015290519081900360640190fd5b60ff54610100546040805163bfbbd53f60e01b81529051611515936001600160a01b0390811693169163bfbbd53f916004808301926020929190829003018186803b1580156114e157600080fd5b505afa1580156114f5573d6000803e3d6000fd5b505050506040513d602081101561150b57600080fd5b50516000196148e8565b61010355565b60698054604080516020601f6002600019610100600188161502019095169490940493840181900481028201810190925282815260609390929091830182828015610b435780601f10610b1857610100808354040283529160200191610b43565b610101602052600090815260409020805460018201546002909201546001600160a01b03918216929091169083565b6101065481565b6000610b626115bf613e86565b84610cf4856040518060600160405280602581526020016159dc60259139606660006115e9613e86565b6001600160a01b03908116825260208083019390935260409182016000908120918d1681529252902054919063ffffffff61427016565b6000610b6261162d613e86565b8484614119565b80341561182c5761010060009054906101000a90046001600160a01b03166001600160a01b031663ef3bac5e6040518163ffffffff1660e01b815260040160206040518083038186803b15801561168a57600080fd5b505afa15801561169e573d6000803e3d6000fd5b505050506040513d60208110156116b457600080fd5b505160fe546001600160a01b03908116911614611706576040805162461bcd60e51b81526020600482015260186024820152600080516020615855833981519152604482015290519081900360640190fd5b34811461174f576040805162461bcd60e51b815260206004820152601260248201527176616c756520213d206d73672e76616c756560701b604482015290519081900360640190fd5b61010060009054906101000a90046001600160a01b03166001600160a01b031663ef3bac5e6040518163ffffffff1660e01b815260040160206040518083038186803b15801561179e57600080fd5b505afa1580156117b2573d6000803e3d6000fd5b505050506040513d60208110156117c857600080fd5b505160408051630d0e30db60e41b815290516001600160a01b039092169163d0e30db0913491600480830192600092919082900301818588803b15801561180e57600080fd5b505af1158015611822573d6000803e3d6000fd5b5050505050611844565b60fe54611844906001600160a01b0316333084614781565b81610106544211156118f257600061185b82610ee7565b905060006118b7612710610db061010060009054906101000a90046001600160a01b03166001600160a01b03166309956f666040518163ffffffff1660e01b815260040160206040518083038186803b158015610d7757600080fd5b610107549091506118ce908263ffffffff61439f16565b61010755610105546118e6908363ffffffff61439f16565b61010555505042610106555b60975460ff16611937576040805162461bcd60e51b815260206004820152601f60248201526000805160206157cb833981519152604482015290519081900360640190fd5b6097805460ff19169055610ed583614a3a565b610100546040805160016236831760e01b0319815233600482015290516001600160a01b039092169163ffc97ce9916024808201926020929091908290030181600087803b15801561199b57600080fd5b505af11580156119af573d6000803e3d6000fd5b505050506040513d60208110156119c557600080fd5b5051611a0957333214611a09576040805162461bcd60e51b81526020600482015260076024820152666e6f7420656f6160c81b604482015290519081900360640190fd5b833415611c015761010060009054906101000a90046001600160a01b03166001600160a01b031663ef3bac5e6040518163ffffffff1660e01b815260040160206040518083038186803b158015611a5f57600080fd5b505afa158015611a73573d6000803e3d6000fd5b505050506040513d6020811015611a8957600080fd5b505160fe546001600160a01b03908116911614611adb576040805162461bcd60e51b81526020600482015260186024820152600080516020615855833981519152604482015290519081900360640190fd5b348114611b24576040805162461bcd60e51b815260206004820152601260248201527176616c756520213d206d73672e76616c756560701b604482015290519081900360640190fd5b61010060009054906101000a90046001600160a01b03166001600160a01b031663ef3bac5e6040518163ffffffff1660e01b815260040160206040518083038186803b158015611b7357600080fd5b505afa158015611b87573d6000803e3d6000fd5b505050506040513d6020811015611b9d57600080fd5b505160408051630d0e30db60e41b815290516001600160a01b039092169163d0e30db0913491600480830192600092919082900301818588803b158015611be357600080fd5b505af1158015611bf7573d6000803e3d6000fd5b5050505050611c19565b60fe54611c19906001600160a01b0316333084614781565b8461010654421115611cc7576000611c3082610ee7565b90506000611c8c612710610db061010060009054906101000a90046001600160a01b03166001600160a01b03166309956f666040518163ffffffff1660e01b815260040160206040518083038186803b158015610d7757600080fd5b61010754909150611ca3908263ffffffff61439f16565b6101075561010554611cbb908363ffffffff61439f16565b61010555505042610106555b60975460ff16611d0c576040805162461bcd60e51b815260206004820152601f60248201526000805160206157cb833981519152604482015290519081900360640190fd5b6097805460ff19169055610103546000191415611d61576040805162461bcd60e51b815260206004820152600e60248201526d1c1bdbdb1259081b9bdd081cd95d60921b604482015290519081900360640190fd5b86611d9d576040805162461bcd60e51b815260206004820152600760248201526606e6f20696420360cc1b604482015290519081900360640190fd5b600087815261010160209081526040808320805482516303c1db6b60e51b8152600481018d9052925191946001600160a01b03909116939092849263783b6d6092602480840193919291829003018186803b158015611dfb57600080fd5b505afa158015611e0f573d6000803e3d6000fd5b505050506040513d6020811015611e2557600080fd5b5051610102549091508a10611e73576040805162461bcd60e51b815260206004820152600f60248201526e189859081c1bdcda5d1a5bdb881a59608a1b604482015290519081900360640190fd5b60018301546001600160a01b03163314611ec6576040805162461bcd60e51b815260206004820152600f60248201526e10b837b9b4ba34b7b71037bbb732b960891b604482015290519081900360640190fd5b80611f0b576040805162461bcd60e51b815260206004820152601060248201526f10b0b1ba34bb32903837b9b4ba34b7b760811b604482015290519081900360640190fd5b60fc8a905586866040811015611f2057600080fd5b6001600160a01b038235169190810190604081016020820135600160201b811115611f4a57600080fd5b820183602082011115611f5c57600080fd5b803590602001918460018302840111600160201b83111715611f7d57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092018290525060fd80546001600160a01b0319166001600160a01b039a8b161790819055610100546040805163238d19ed60e01b8152928c166004840152519a169963238d19ed9950602480830199506020985090965090869003019350849250905087803b15801561201b57600080fd5b505af115801561202f573d6000803e3d6000fd5b505050506040513d602081101561204557600080fd5b505161208a576040805162461bcd60e51b815260206004820152600f60248201526e08585c1c1c9bdd9959081cdd1c985d608a1b604482015290519081900360640190fd5b87612150576101005460408051632632c18560e21b81526001600160a01b038581166004830152915191909216916398cb0614916024808301926020929190829003018186803b1580156120dd57600080fd5b505afa1580156120f1573d6000803e3d6000fd5b505050506040513d602081101561210757600080fd5b505161214b576040805162461bcd60e51b815260206004820152600e60248201526d776f726b65722021737461626c6560901b604482015290519081900360640190fd5b612211565b6101005460408051632eda838160e21b81526001600160a01b0385811660048301529151919092169163bb6a0e04916024808301926020929190829003018186803b15801561219e57600080fd5b505afa1580156121b2573d6000803e3d6000fd5b505050506040513d60208110156121c857600080fd5b5051612211576040805162461bcd60e51b81526020600482015260136024820152721c995cd95c9d99480858dbdb9cda5cdd195b9d606a1b604482015290519081900360640190fd5b60006122208460020154613d1d565b60fe54909150600090612241908c90610f2d906001600160a01b0316614705565b60fe5490915061225b906001600160a01b0316858d613fbf565b836001600160a01b03166348db8cc48d33858d8d6040518663ffffffff1660e01b815260040180868152602001856001600160a01b03166001600160a01b03168152602001848152602001806020018281038252848482818152602001925080828437600081840152601f19601f8201169050808301925050509650505050505050600060405180830381600087803b1580156122f757600080fd5b505af115801561230b573d6000803e3d6000fd5b505050506000846001600160a01b031663783b6d608e6040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561235557600080fd5b505afa158015612369573d6000803e3d6000fd5b505050506040513d602081101561237f57600080fd5b505160fe549091506000906123a2908490610f2d906001600160a01b0316614705565b90508b61246a576101005460408051632632c18560e21b81526001600160a01b038981166004830152915191909216916398cb0614916024808301926020929190829003018186803b1580156123f757600080fd5b505afa15801561240b573d6000803e3d6000fd5b505050506040513d602081101561242157600080fd5b5051612465576040805162461bcd60e51b815260206004820152600e60248201526d776f726b65722021737461626c6560901b604482015290519081900360640190fd5b61252b565b6101005460408051632eda838160e21b81526001600160a01b0389811660048301529151919092169163bb6a0e04916024808301926020929190829003018186803b1580156124b857600080fd5b505afa1580156124cc573d6000803e3d6000fd5b505050506040513d60208110156124e257600080fd5b505161252b576040805162461bcd60e51b81526020600482015260136024820152721c995cd95c9d99480858dbdb9cda5cdd195b9d606a1b604482015290519081900360640190fd5b8015612568576040805162461bcd60e51b815260206004820152600760248201526606261636b2021360cc1b604482015290519081900360640190fd5b8482116125af576040805162461bcd60e51b815260206004820152601060248201526f6865616c74682021696e63726561736560801b604482015290519081900360640190fd5b610100548754604080516327b4a3b560e11b81526001600160a01b0392831660048201526024810188905290516000939290921691634f69476a91604480820192602092909190829003018186803b15801561260a57600080fd5b505afa15801561261e573d6000803e3d6000fd5b505050506040513d602081101561263457600080fd5b5051905061265961264c82606463ffffffff613f7616565b849063ffffffff61430716565b61266b8661271063ffffffff61430716565b11156126be576040805162461bcd60e51b815260206004820152601d60248201527f64656274526174696f203e206b696c6c466163746f72206d617267696e000000604482015290519081900360640190fd5b60001960fc81905550600160fd60006101000a8154816001600160a01b0302191690836001600160a01b031602179055508e7f6a521c8d5be0b99d2893ee4cb5018da4c8fb33011bcc6cc70ad5dc718957bc398f888660405180848152602001838152602001828152602001935050505060405180910390a250506097805460ff1916600117905550505050505050505050505050565b60fb5481565b610100546040805163d9ed3def60e01b815233600482015290516001600160a01b039092169163d9ed3def916024808201926020929091908290030181600087803b1580156127a957600080fd5b505af11580156127bd573d6000803e3d6000fd5b505050506040513d60208110156127d357600080fd5b5051612820576040805162461bcd60e51b815260206004820152601760248201527610bbb434ba32b634b9ba32b2103634b8bab4b230ba37b960491b604482015290519081900360640190fd5b6000610106544211156128cf57600061283882610ee7565b90506000612894612710610db061010060009054906101000a90046001600160a01b03166001600160a01b03166309956f666040518163ffffffff1660e01b815260040160206040518083038186803b158015610d7757600080fd5b610107549091506128ab908263ffffffff61439f16565b61010755610105546128c3908363ffffffff61439f16565b61010555505042610106555b60975460ff16612914576040805162461bcd60e51b815260206004820152601f60248201526000805160206157cb833981519152604482015290519081900360640190fd5b6097805460ff19169055610103546000191415612969576040805162461bcd60e51b815260206004820152600e60248201526d1c1bdbdb1259081b9bdd081cd95d60921b604482015290519081900360640190fd5b60008281526101016020526040902060028101546129b8576040805162461bcd60e51b81526020600482015260076024820152661b9bc81919589d60ca1b604482015290519081900360640190fd5b6129c183614acd565b60006129cc84614ce4565b8254604080516303c1db6b60e51b81526004810188905290519293506000926001600160a01b039092169163783b6d6091602480820192602092909190829003018186803b158015612a1d57600080fd5b505afa158015612a31573d6000803e3d6000fd5b505050506040513d6020811015612a4757600080fd5b5051610100548454604080516313f6321b60e01b81526001600160a01b03928316600482015260248101879052905193945060009391909216916313f6321b916044808301926020929190829003018186803b158015612aa657600080fd5b505afa158015612aba573d6000803e3d6000fd5b505050506040513d6020811015612ad057600080fd5b50519050612ae68361271063ffffffff61430716565b612af6838363ffffffff61430716565b10612b3a576040805162461bcd60e51b815260206004820152600f60248201526e63616e2774206c697175696461746560881b604482015290519081900360640190fd5b60fe54600090612b52906001600160a01b0316614705565b8554604080516301057c4960e61b8152600481018b905290519293506001600160a01b039091169163415f12409160248082019260009290919082900301818387803b158015612ba157600080fd5b505af1158015612bb5573d6000803e3d6000fd5b505060fe5460009250612bd791508390610f2d906001600160a01b0316614705565b90506000612c33612710610db061010060009054906101000a90046001600160a01b03166001600160a01b03166328ae433e6040518163ffffffff1660e01b815260040160206040518083038186803b158015610d7757600080fd5b90506000612cc8612710610db061010060009054906101000a90046001600160a01b03166001600160a01b03166304df1f5e6040518163ffffffff1660e01b815260040160206040518083038186803b158015612c8f57600080fd5b505afa158015612ca3573d6000803e3d6000fd5b505050506040513d6020811015612cb957600080fd5b5051869063ffffffff61430716565b90506000612cdc838363ffffffff61439f16565b90506000612cf0858363ffffffff613f7616565b90508315612d0257612d0233856144ed565b8215612d8157610100546040805163044d6d6f60e01b81529051612d81926001600160a01b03169163044d6d6f916004808301926020929190829003018186803b158015612d4f57600080fd5b505afa158015612d63573d6000803e3d6000fd5b505050506040513d6020811015612d7957600080fd5b5051846144ed565b6000898211612d91576000612d95565b8982035b90508015612db55760018b0154612db5906001600160a01b0316826144ed565b60018b0154604080516001600160a01b03929092168252602082018b90528181018c905260608201859052608082018390525133918f917f1f645d83d1940a1cb59e44eda10b9611d98402a975eef915b67160f46ee349e39181900360a00190a350506097805460ff191660011790555050505050505050505050565b610100546040805160016236831760e01b0319815233600482015290516001600160a01b039092169163ffc97ce9916024808201926020929091908290030181600087803b158015612e8357600080fd5b505af1158015612e97573d6000803e3d6000fd5b505050506040513d6020811015612ead57600080fd5b5051612ef157333214612ef1576040805162461bcd60e51b81526020600482015260076024820152666e6f7420656f6160c81b604482015290519081900360640190fd5b8434156130e95761010060009054906101000a90046001600160a01b03166001600160a01b031663ef3bac5e6040518163ffffffff1660e01b815260040160206040518083038186803b158015612f4757600080fd5b505afa158015612f5b573d6000803e3d6000fd5b505050506040513d6020811015612f7157600080fd5b505160fe546001600160a01b03908116911614612fc3576040805162461bcd60e51b81526020600482015260186024820152600080516020615855833981519152604482015290519081900360640190fd5b34811461300c576040805162461bcd60e51b815260206004820152601260248201527176616c756520213d206d73672e76616c756560701b604482015290519081900360640190fd5b61010060009054906101000a90046001600160a01b03166001600160a01b031663ef3bac5e6040518163ffffffff1660e01b815260040160206040518083038186803b15801561305b57600080fd5b505afa15801561306f573d6000803e3d6000fd5b505050506040513d602081101561308557600080fd5b505160408051630d0e30db60e41b815290516001600160a01b039092169163d0e30db0913491600480830192600092919082900301818588803b1580156130cb57600080fd5b505af11580156130df573d6000803e3d6000fd5b5050505050613101565b60fe54613101906001600160a01b0316333084614781565b85610106544211156131af57600061311882610ee7565b90506000613174612710610db061010060009054906101000a90046001600160a01b03166001600160a01b03166309956f666040518163ffffffff1660e01b815260040160206040518083038186803b158015610d7757600080fd5b6101075490915061318b908263ffffffff61439f16565b61010755610105546131a3908363ffffffff61439f16565b61010555505042610106555b60975460ff166131f4576040805162461bcd60e51b815260206004820152601f60248201526000805160206157cb833981519152604482015290519081900360640190fd5b6097805460ff19169055610103546000191415613249576040805162461bcd60e51b815260206004820152600e60248201526d1c1bdbdb1259081b9bdd081cd95d60921b604482015290519081900360640190fd5b60008961329c57506101028054600180820190925560008181526101016020526040902080546001600160a01b038c166001600160a01b03199182161782559281018054909316331790925599506133ab565b50600089815261010160205260409020610102548a106132f5576040805162461bcd60e51b815260206004820152600f60248201526e189859081c1bdcda5d1a5bdb881a59608a1b604482015290519081900360640190fd5b80546001600160a01b038a811691161461334c576040805162461bcd60e51b81526020600482015260136024820152723130b2103837b9b4ba34b7b7103bb7b935b2b960691b604482015290519081900360640190fd5b60018101546001600160a01b031633146133a2576040805162461bcd60e51b81526020600482015260126024820152713737ba103837b9b4ba34b7b71037bbb732b960711b604482015290519081900360640190fd5b6133ab8a614acd565b6040805188815290518b917f73c4ef442856bea52a6b34a83f35484ee65828010254ec27766c5a8c13db6c84919081900360200190a260fc8a9055848460408110156133f657600080fd5b6001600160a01b038235169190810190604081016020820135600160201b81111561342057600080fd5b82018360208201111561343257600080fd5b803590602001918460018302840111600160201b8311171561345357600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505091929192905050508191505060fd60008291906101000a8154816001600160a01b0302191690836001600160a01b031602179055505061010060009054906101000a90046001600160a01b03166001600160a01b031663aa1566458a6040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b15801561353a57600080fd5b505afa15801561354e573d6000803e3d6000fd5b505050506040513d602081101561356457600080fd5b50516135a6576040805162461bcd60e51b815260206004820152600c60248201526b3737ba1030903bb7b935b2b960a11b604482015290519081900360640190fd5b8615806136265750610100546040805161237f60e41b81526001600160a01b038c8116600483015291519190921691620237f0916024808301926020929190829003018186803b1580156135f957600080fd5b505afa15801561360d573d6000803e3d6000fd5b505050506040513d602081101561362357600080fd5b50515b613675576040805162461bcd60e51b815260206004820152601b60248201527a1ddbdc9ad95c881b9bdd081858d8d95c1d081b5bdc99481919589d602a1b604482015290519081900360640190fd5b6000613684886111c68d614ce4565b90506000806136998b8b63ffffffff61439f16565b60fe549091506136b1906001600160a01b0316614705565b811115613705576040805162461bcd60e51b815260206004820152601f60248201527f696e73756666696369656e742066756e647320696e20746865207661756c7400604482015290519081900360640190fd5b60fe54600090613723908390610f2d906001600160a01b0316614705565b60fe5490915061373d906001600160a01b03168e84613fbf565b8c6001600160a01b03166348db8cc48f33878d8d6040518663ffffffff1660e01b815260040180868152602001856001600160a01b03166001600160a01b03168152602001848152602001806020018281038252848482818152602001925080828437600081840152601f19601f8201169050808301925050509650505050505050600060405180830381600087803b1580156137d957600080fd5b505af11580156137ed573d6000803e3d6000fd5b505060fe5461380c9250839150610f2d906001600160a01b0316614705565b92505050600061382583613820848c614d8e565b614d8e565b9050613837838263ffffffff613f7616565b92508215613aad5761010060009054906101000a90046001600160a01b03166001600160a01b031663e1ed42866040518163ffffffff1660e01b815260040160206040518083038186803b15801561388e57600080fd5b505afa1580156138a2573d6000803e3d6000fd5b505050506040513d60208110156138b857600080fd5b5051831015613904576040805162461bcd60e51b8152602060048201526013602482015272746f6f20736d616c6c20646562742073697a6560681b604482015290519081900360640190fd5b60008c6001600160a01b031663783b6d608f6040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561394a57600080fd5b505afa15801561395e573d6000803e3d6000fd5b505050506040513d602081101561397457600080fd5b81019080805190602001909291905050509050600061010060009054906101000a90046001600160a01b03166001600160a01b031663ad58e5738f876040518363ffffffff1660e01b815260040180836001600160a01b03166001600160a01b031681526020018281526020019250505060206040518083038186803b1580156139fd57600080fd5b505afa158015613a11573d6000803e3d6000fd5b505050506040513d6020811015613a2757600080fd5b50519050613a3d8561271063ffffffff61430716565b613a4d838363ffffffff61430716565b1015613a92576040805162461bcd60e51b815260206004820152600f60248201526e3130b2103bb7b935903330b1ba37b960891b604482015290519081900360640190fd5b613a9c8f86614da4565b613aaa8f8760020154614e46565b50505b60001960fc5560fd80546001600160a01b031916600117905580821115613ae757613ae733613ae2848463ffffffff613f7616565b6144ed565b50506097805460ff191660011790555050505050505050505050565b60fc5481565b6001600160a01b03918216600090815260666020908152604080832093909416825291909152205490565b600054610100900460ff1680613b4d5750613b4d614f9e565b80613b5b575060005460ff16155b613b965760405162461bcd60e51b815260040180806020018281038252602e815260200180615924602e913960400191505060405180910390fd5b600054610100900460ff16158015613bc1576000805460ff1961ff0019909116610100171660011790555b613bc9614fa4565b613bd1615055565b613c4487878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8b0181900481028201810190925289815292508991508890819084018382808284376000920191909152506150ea92505050565b613c4d8361519f565b60016101025561010080546001600160a01b03808c166001600160a01b03199283161792839055426101065560fe80548c83169084161790556000196101035560ff8054868316931692909217918290556040805163bfbbd53f60e01b81529051613ce094938316939092169163bfbbd53f91600481810192602092909190829003018186803b1580156114e157600080fd5b600160fb81905560001960fc5560fd80546001600160a01b03191690911790558015613d12576000805461ff00191690555b505050505050505050565b60006101045460001415613d32575080611009565b610b6661010454610db0610105548561430790919063ffffffff16565b613d57613e86565b60c9546001600160a01b03908116911614613da7576040805162461bcd60e51b815260206004820181905260248201526000805160206158e4833981519152604482015290519081900360640190fd5b6001600160a01b038116613dec5760405162461bcd60e51b815260040180806020018281038252602681526020018061580d6026913960400191505060405180910390fd5b60c9546040516001600160a01b0380841692169060008051602061590483398151915290600090a360c980546001600160a01b0319166001600160a01b0392909216919091179055565b60006101045460001415613e4b575080611009565b610b6661010554610db0610104548561430790919063ffffffff16565b60ff546001600160a01b031681565b60fe546001600160a01b031681565b3390565b6001600160a01b038316613ecf5760405162461bcd60e51b81526004018080602001828103825260248152602001806159b86024913960400191505060405180910390fd5b6001600160a01b038216613f145760405162461bcd60e51b81526004018080602001828103825260228152602001806158336022913960400191505060405180910390fd5b6001600160a01b03808416600081815260666020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b6000613fb883836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250614270565b9392505050565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b178152925182516000946060949389169392918291908083835b6020831061403c5780518252601f19909201916020918201910161401d565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d806000811461409e576040519150601f19603f3d011682016040523d82523d6000602084013e6140a3565b606091505b50915091508180156140d15750805115806140d157508080602001905160208110156140ce57600080fd5b50515b614112576040805162461bcd60e51b815260206004820152600d60248201526c10b9b0b332aa3930b739b332b960991b604482015290519081900360640190fd5b5050505050565b6001600160a01b03831661415e5760405162461bcd60e51b81526004018080602001828103825260258152602001806159936025913960400191505060405180910390fd5b6001600160a01b0382166141a35760405162461bcd60e51b81526004018080602001828103825260238152602001806157a86023913960400191505060405180910390fd5b6141ae838383614ac8565b6141f181604051806060016040528060268152602001615875602691396001600160a01b038616600090815260656020526040902054919063ffffffff61427016565b6001600160a01b038085166000908152606560205260408082209390935590841681522054614226908263ffffffff61439f16565b6001600160a01b03808416600081815260656020908152604091829020949094558051858152905191939287169260008051602061595283398151915292918290030190a3505050565b600081848411156142ff5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156142c45781810151838201526020016142ac565b50505050905090810190601f1680156142f15780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b60008261431657506000610b66565b8282028284828161432357fe5b0414613fb85760405162461bcd60e51b815260040180806020018281038252602181526020018061589b6021913960400191505060405180910390fd5b6000613fb883836040518060400160405280601a815260200179536166654d6174683a206469766973696f6e206279207a65726f60301b8152506151b5565b600082820183811015613fb8576040805162461bcd60e51b815260206004820152601b60248201527a536166654d6174683a206164646974696f6e206f766572666c6f7760281b604482015290519081900360640190fd5b6001600160a01b03821661443c5760405162461bcd60e51b81526004018080602001828103825260218152602001806159726021913960400191505060405180910390fd5b61444882600083614ac8565b61448b816040518060600160405280602281526020016157eb602291396001600160a01b038516600090815260656020526040902054919063ffffffff61427016565b6001600160a01b0383166000908152606560205260409020556067546144b7908263ffffffff613f7616565b6067556040805182815290516000916001600160a01b038516916000805160206159528339815191529181900360200190a35050565b61010060009054906101000a90046001600160a01b03166001600160a01b031663ef3bac5e6040518163ffffffff1660e01b815260040160206040518083038186803b15801561453c57600080fd5b505afa158015614550573d6000803e3d6000fd5b505050506040513d602081101561456657600080fd5b505160fe546001600160a01b03908116911614156146ea5760fe546101005460408051631a2f07f560e31b815290516145fe936001600160a01b0390811693169163d1783fa8916004808301926020929190829003018186803b1580156145cc57600080fd5b505afa1580156145e0573d6000803e3d6000fd5b505050506040513d60208110156145f657600080fd5b505183613fbf565b61010060009054906101000a90046001600160a01b03166001600160a01b031663d1783fa86040518163ffffffff1660e01b815260040160206040518083038186803b15801561464d57600080fd5b505afa158015614661573d6000803e3d6000fd5b505050506040513d602081101561467757600080fd5b505160408051632e1a7d4d60e01b81526004810184905290516001600160a01b0390921691632e1a7d4d9160248082019260009290919082900301818387803b1580156146c357600080fd5b505af11580156146d7573d6000803e3d6000fd5b505050506146e5828261521a565b614701565b60fe54614701906001600160a01b03168383613fbf565b5050565b604080516370a0823160e01b815230600482015290516000916001600160a01b038416916370a0823191602480820192602092909190829003018186803b15801561474f57600080fd5b505afa158015614763573d6000803e3d6000fd5b505050506040513d602081101561477957600080fd5b505192915050565b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b17815292518251600094606094938a169392918291908083835b602083106148065780518252601f1990920191602091820191016147e7565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114614868576040519150601f19603f3d011682016040523d82523d6000602084013e61486d565b606091505b509150915081801561489b57508051158061489b575080806020019051602081101561489857600080fd5b50515b6148e0576040805162461bcd60e51b815260206004820152601160248201527021736166655472616e7366657246726f6d60781b604482015290519081900360640190fd5b505050505050565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663095ea7b360e01b178152925182516000946060949389169392918291908083835b602083106149655780518252601f199092019160209182019101614946565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d80600081146149c7576040519150601f19603f3d011682016040523d82523d6000602084013e6149cc565b606091505b50915091508180156149fa5750805115806149fa57508080602001905160208110156149f757600080fd5b50515b614112576040805162461bcd60e51b815260206004820152600c60248201526b2173616665417070726f766560a01b604482015290519081900360640190fd5b6000614a4882610f2d611198565b905060008115614a6657614a6182610db0610e5e610b73565b614a68565b825b9050614a743382615316565b67016345785d8a0000614a85610b73565b11614ac8576040805162461bcd60e51b815260206004820152600e60248201526d6e6f2074696e792073686172657360901b604482015290519081900360640190fd5b505050565b6000818152610101602052604090206002015415614ce157610100546040805163bfbbd53f60e01b815290516000926001600160a01b03169163bfbbd53f916004808301926020929190829003018186803b158015614b2b57600080fd5b505afa158015614b3f573d6000803e3d6000fd5b505050506040513d6020811015614b5557600080fd5b50516000838152610101602090815260409182902060018101546101035460029092015484516001600160a01b0392831660248201526044810193909352606480840191909152845180840390910181526084909201845291810180516001600160e01b0316635ae2fb3960e11b178152925181519290941693909290918291908083835b60208310614bf95780518252601f199092019160209182019101614bda565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114614c5b576040519150601f19603f3d011682016040523d82523d6000602084013e614c60565b606091505b5050905080156147015760ff5460008381526101016020526040808220600201548151632770a7eb60e21b8152306004820152602481019190915290516001600160a01b0390931692639dc29fac9260448084019391929182900301818387803b158015614ccd57600080fd5b505af11580156148e0573d6000803e3d6000fd5b50565b60008181526101016020526040812060028101548015614d83576000614d0982613d1d565b6000600285015561010454909150614d27908363ffffffff613f7616565b6101045561010554614d3f908263ffffffff613f7616565b6101055560408051838152905186917fc141cd58846e97354928242dcc7ddd92a6a0ecf03bdb5d3a411d260b9abc3272919081900360200190a29250611009915050565b600092505050611009565b6000818310614d9d5781613fb8565b5090919050565b60008281526101016020526040812090614dbd83613e36565b6002830154909150614dd5908263ffffffff61439f16565b600283015561010454614dee908263ffffffff61439f16565b6101045561010554614e06908463ffffffff61439f16565b6101055560408051828152905185917f43b70d61bab6f8bfcf27c791452876c7da386b19652e19b8f21e8927aa6577ab919081900360200190a250505050565b80156147015760ff54604080516340c10f1960e01b81523060048201526024810184905290516001600160a01b03909216916340c10f199160448082019260009290919082900301818387803b158015614e9f57600080fd5b505af1158015614eb3573d6000803e3d6000fd5b5050505061010060009054906101000a90046001600160a01b03166001600160a01b031663bfbbd53f6040518163ffffffff1660e01b815260040160206040518083038186803b158015614f0657600080fd5b505afa158015614f1a573d6000803e3d6000fd5b505050506040513d6020811015614f3057600080fd5b50516000838152610101602052604080822060010154610103548251630efe6a8b60e01b81526001600160a01b0392831660048201526024810191909152604481018690529151931692630efe6a8b9260648084019391929182900301818387803b158015614ccd57600080fd5b303b1590565b600054610100900460ff1680614fbd5750614fbd614f9e565b80614fcb575060005460ff16155b6150065760405162461bcd60e51b815260040180806020018281038252602e815260200180615924602e913960400191505060405180910390fd5b600054610100900460ff16158015615031576000805460ff1961ff0019909116610100171660011790555b615039615402565b6150416154a2565b8015614ce1576000805461ff001916905550565b600054610100900460ff168061506e575061506e614f9e565b8061507c575060005460ff16155b6150b75760405162461bcd60e51b815260040180806020018281038252602e815260200180615924602e913960400191505060405180910390fd5b600054610100900460ff161580156150e2576000805460ff1961ff0019909116610100171660011790555b615041615589565b600054610100900460ff16806151035750615103614f9e565b80615111575060005460ff16155b61514c5760405162461bcd60e51b815260040180806020018281038252602e815260200180615924602e913960400191505060405180910390fd5b600054610100900460ff16158015615177576000805460ff1961ff0019909116610100171660011790555b61517f615402565b6151898383615637565b8015614ac8576000805461ff0019169055505050565b606a805460ff191660ff92909216919091179055565b600081836152045760405162461bcd60e51b81526020600482018181528351602484015283519092839260449091019190850190808383600083156142c45781810151838201526020016142ac565b50600083858161521057fe5b0495945050505050565b604080516000808252602082019092526001600160a01b0384169083906040518082805190602001908083835b602083106152665780518252601f199092019160209182019101615247565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d80600081146152c8576040519150601f19603f3d011682016040523d82523d6000602084013e6152cd565b606091505b5050905080614ac8576040805162461bcd60e51b815260206004820152601060248201526f042e6c2cccaa8e4c2dce6cccae48aa8960831b604482015290519081900360640190fd5b6001600160a01b038216615371576040805162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015290519081900360640190fd5b61537d60008383614ac8565b606754615390908263ffffffff61439f16565b6067556001600160a01b0382166000908152606560205260409020546153bc908263ffffffff61439f16565b6001600160a01b03831660008181526065602090815260408083209490945583518581529351929391926000805160206159528339815191529281900390910190a35050565b600054610100900460ff168061541b575061541b614f9e565b80615429575060005460ff16155b6154645760405162461bcd60e51b815260040180806020018281038252602e815260200180615924602e913960400191505060405180910390fd5b600054610100900460ff16158015615041576000805460ff1961ff0019909116610100171660011790558015614ce1576000805461ff001916905550565b600054610100900460ff16806154bb57506154bb614f9e565b806154c9575060005460ff16155b6155045760405162461bcd60e51b815260040180806020018281038252602e815260200180615924602e913960400191505060405180910390fd5b600054610100900460ff1615801561552f576000805460ff1961ff0019909116610100171660011790555b6000615539613e86565b60c980546001600160a01b0319166001600160a01b03831690811790915560405191925090600090600080516020615904833981519152908290a3508015614ce1576000805461ff001916905550565b600054610100900460ff16806155a257506155a2614f9e565b806155b0575060005460ff16155b6155eb5760405162461bcd60e51b815260040180806020018281038252602e815260200180615924602e913960400191505060405180910390fd5b600054610100900460ff16158015615616576000805460ff1961ff0019909116610100171660011790555b6097805460ff191660011790558015614ce1576000805461ff001916905550565b600054610100900460ff16806156505750615650614f9e565b8061565e575060005460ff16155b6156995760405162461bcd60e51b815260040180806020018281038252602e815260200180615924602e913960400191505060405180910390fd5b600054610100900460ff161580156156c4576000805460ff1961ff0019909116610100171660011790555b82516156d790606890602086019061570f565b5081516156eb90606990602085019061570f565b50606a805460ff191660121790558015614ac8576000805461ff0019169055505050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061575057805160ff191683800117855561577d565b8280016001018555821561577d579182015b8281111561577d578251825591602001919060010190615762565b5061578992915061578d565b5090565b610b4b91905b80821115615789576000815560010161579356fe45524332303a207472616e7366657220746f20746865207a65726f20616464726573735265656e7472616e637947756172643a207265656e7472616e742063616c6c0045524332303a206275726e20616d6f756e7420657863656564732062616c616e63654f776e61626c653a206e6577206f776e657220697320746865207a65726f206164647265737345524332303a20617070726f766520746f20746865207a65726f206164647265737362617365546f6b656e206973206e6f7420774e6174697665000000000000000045524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e6365536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f7745524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e63654f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65728be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0436f6e747261637420696e7374616e63652068617320616c7265616479206265656e20696e697469616c697a6564ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef45524332303a206275726e2066726f6d20746865207a65726f206164647265737345524332303a207472616e736665722066726f6d20746865207a65726f206164647265737345524332303a20617070726f76652066726f6d20746865207a65726f206164647265737345524332303a2064656372656173656420616c6c6f77616e63652062656c6f77207a65726fa26469706673582212206d6caa6394d5b6ee0de7a8affd3545456a2e846535f20c9ded9bafa5edd0c42a64736f6c63430006060033", + "abi": [{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"healthBefore","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"healthAfter","type":"uint256"}],"name":"AddCollateral","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"debtShare","type":"uint256"}],"name":"AddDebt","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"killer","type":"address"},{"indexed":false,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"posVal","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"debt","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"prize","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"left","type":"uint256"}],"name":"Kill","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"debtShare","type":"uint256"}],"name":"RemoveDebt","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"loan","type":"uint256"}],"name":"Work","type":"event"},{"inputs":[],"name":"POSITION_ID","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STRATEGY","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_IN_EXEC_LOCK","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bool","name":"goRogue","type":"bool"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"addCollateral","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"config","outputs":[{"internalType":"contract IVaultConfig","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"debtShare","type":"uint256"}],"name":"debtShareToVal","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"debtToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"debtVal","type":"uint256"}],"name":"debtValToShare","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountToken","type":"uint256"}],"name":"deposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"fairLaunchPoolId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IVaultConfig","name":"_config","type":"address"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"uint8","name":"_decimals","type":"uint8"},{"internalType":"address","name":"_debtToken","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"kill","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lastAccrueTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextPositionID","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"pendingInterest","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"positionInfo","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"positions","outputs":[{"internalType":"address","name":"worker","type":"address"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"debtShare","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"reduceReserve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"targetedToken","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"requestFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"reservePool","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_poolId","type":"uint256"}],"name":"setFairLaunchPoolId","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"token","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IVaultConfig","name":"_config","type":"address"}],"name":"updateConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"vaultDebtShare","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vaultDebtVal","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"share","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"withdrawReserve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"worker","type":"address"},{"internalType":"uint256","name":"principalAmount","type":"uint256"},{"internalType":"uint256","name":"borrowAmount","type":"uint256"},{"internalType":"uint256","name":"maxReturn","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"work","outputs":[],"stateMutability":"payable","type":"function"},{"stateMutability":"payable","type":"receive"}] +} From 7f040cc29b77ef2b79760c5aa47abd042e53401c Mon Sep 17 00:00:00 2001 From: Poli Paul Date: Fri, 15 Oct 2021 12:26:38 +0200 Subject: [PATCH 33/33] Add Alpaca Router --- contracts/interfaces/IAlpacaFairLaunch.sol | 41 ++ contracts/interfaces/IAlpacaVault.sol | 19 + .../implementations/AlpacaRouter.sol | 200 +++++++ test/helpers/builders.js | 7 + .../implementations/AlpacaRouter.unit.js | 535 ++++++++++++++++++ 5 files changed, 802 insertions(+) create mode 100644 contracts/interfaces/IAlpacaFairLaunch.sol create mode 100644 contracts/interfaces/IAlpacaVault.sol create mode 100644 contracts/powerindex-router/implementations/AlpacaRouter.sol create mode 100644 test/router/implementations/AlpacaRouter.unit.js diff --git a/contracts/interfaces/IAlpacaFairLaunch.sol b/contracts/interfaces/IAlpacaFairLaunch.sol new file mode 100644 index 00000000..799a0cdc --- /dev/null +++ b/contracts/interfaces/IAlpacaFairLaunch.sol @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.6.12; + +interface IAlpacaFairLaunch { + function poolLength() external view returns (uint256); + + function addPool( + uint256 _allocPoint, + address _stakeToken, + bool _withUpdate + ) external; + + function setPool( + uint256 _pid, + uint256 _allocPoint, + bool _withUpdate + ) external; + + function pendingAlpaca(uint256 _pid, address _user) external view returns (uint256); + + function userInfo(uint256 _pid, address _user) external view returns (uint256 amount, uint256 rewardDebt); + + function updatePool(uint256 _pid) external; + + function deposit( + address _for, + uint256 _pid, + uint256 _amount + ) external; + + function withdraw( + address _for, + uint256 _pid, + uint256 _amount + ) external; + + function withdrawAll(address _for, uint256 _pid) external; + + function harvest(uint256 _pid) external; +} diff --git a/contracts/interfaces/IAlpacaVault.sol b/contracts/interfaces/IAlpacaVault.sol new file mode 100644 index 00000000..7c1a16f8 --- /dev/null +++ b/contracts/interfaces/IAlpacaVault.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.6.12; + +interface IAlpacaVault { + /// @dev Return the total ERC20 entitled to the token holders. Be careful of unaccrued interests. + function totalToken() external view returns (uint256); + + /// @dev Add more ERC20 to the bank. Hope to get some good returns. + function deposit(uint256 amountToken) external payable; + + /// @dev Withdraw ERC20 from the bank by burning the share tokens. + function withdraw(uint256 share) external; + + /// @dev Request funds from user through Vault + function requestFunds(address targetedToken, uint256 amount) external; + + function token() external view returns (address); +} diff --git a/contracts/powerindex-router/implementations/AlpacaRouter.sol b/contracts/powerindex-router/implementations/AlpacaRouter.sol new file mode 100644 index 00000000..6f59590d --- /dev/null +++ b/contracts/powerindex-router/implementations/AlpacaRouter.sol @@ -0,0 +1,200 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.6.12; +pragma experimental ABIEncoderV2; + +import "../../interfaces/IAlpacaFairLaunch.sol"; +import "../PowerIndexBasicRouter.sol"; +import "../../interfaces/IAlpacaVault.sol"; + +/** + * + */ +contract AlpacaRouter is PowerIndexBasicRouter { + uint256 internal immutable MASTER_CHEF_PID; + + event Stake(address indexed sender, uint256 amount, uint256 ibAlpacaAmount, uint256 rewardReceived); + event Redeem(address indexed sender, uint256 amount, uint256 ibAlpacaAmount, uint256 rewardReceived); + event IgnoreDueMissingStaking(); + event AutoClaimRewards(address indexed sender, uint256 alpacaRewards); + event ClaimRewards( + address indexed sender, + uint256 calculatedAlpacaReward, + uint256 calculatedIbAlpacaReward, + uint256 actualAlpacaEarned + ); + event DistributeRewards( + address indexed sender, + uint256 alpacaReward, + uint256 pvpReward, + uint256 poolRewardsUnderlying, + uint256 poolRewardsPi, + address[] pools + ); + + struct AlpacaConfig { + address ibALPACA; + address ALPACA; + uint256 masterChefPid; + } + + IERC20 internal immutable ALPACA; + address internal immutable ibALPACA; + + constructor( + address _piToken, + BasicConfig memory _basicConfig, + AlpacaConfig memory _alpacaConfig + ) public PowerIndexBasicRouter(_piToken, _basicConfig) { + ALPACA = IERC20(_alpacaConfig.ALPACA); + ibALPACA = _alpacaConfig.ibALPACA; + MASTER_CHEF_PID = _alpacaConfig.masterChefPid; + } + + /** + * @notice Claims the rewards earned by providing liquidity to ibALPACA vault. + * @dev Does NOT claim FairLaunch rewards. + * @dev getPendingRewards returns the actual rewards since there was withdraw(0) call earlier + * which triggered interest accrual. + */ + function _claimRewards(ReserveStatus) internal override { + uint256 pendingInterestRewardAlpaca = getPendingRewards(); + uint256 pendingInterestRewardIbAlpaca = alpaca2IbAlpaca(pendingInterestRewardAlpaca); + + require(pendingInterestRewardAlpaca > 0, "NOTHING_TO_CLAIM_IB"); + + // #1. Redeem ibALPACA diff. There is no reward distributed since it had been already distributed + // after stake/redeem action. + _callStaking( + IAlpacaFairLaunch.withdraw.selector, + abi.encode(address(piToken), MASTER_CHEF_PID, pendingInterestRewardIbAlpaca) + ); + + // #2. Unwrap alpaca diff + uint256 alpacaBefore = ALPACA.balanceOf(address(piToken)); + piToken.callExternal(ibALPACA, IAlpacaVault.withdraw.selector, abi.encode(pendingInterestRewardIbAlpaca), 0); + uint256 alpacaEarned = ALPACA.balanceOf(address(piToken)).sub(alpacaBefore); + + require(alpacaEarned > 0, "NOTHING_EARNED"); + + emit ClaimRewards(msg.sender, pendingInterestRewardAlpaca, pendingInterestRewardIbAlpaca, alpacaEarned); + } + + function _distributeRewards() internal override { + uint256 pendingReward = ALPACA.balanceOf(address(this)); + require(pendingReward > 0, "NO_PENDING_REWARD"); + + // Step #1. Distribute pvpReward + (uint256 pvpReward, uint256 poolRewardsUnderlying) = _distributeRewardToPvp(pendingReward, ALPACA); + require(poolRewardsUnderlying > 0, "NO_POOL_REWARDS_UNDERLYING"); + + // Step #2. Wrap ALPACA into piALPACA + ALPACA.approve(address(piToken), poolRewardsUnderlying); + piToken.deposit(poolRewardsUnderlying); + + // Step #3. Distribute piALPACA over the pools + (uint256 poolRewardsPi, address[] memory pools) = _distributePiRemainderToPools(piToken); + + emit DistributeRewards(msg.sender, pendingReward, pvpReward, poolRewardsUnderlying, poolRewardsPi, pools); + } + + /*** OWNER METHODS ***/ + + function stake(uint256 _amount) external onlyOwner { + _stake(_amount); + } + + function redeem(uint256 _amount) external onlyOwner { + _redeem(_amount); + } + + /*** POKE FUNCTION ***/ + + function _rebalancePoke(ReserveStatus reserveStatus, uint256 diff) internal override { + require(staking != address(0), "STACKING_IS_NULL"); + + if (reserveStatus == ReserveStatus.SHORTAGE) { + _redeem(diff); + } else if (reserveStatus == ReserveStatus.EXCESS) { + _stake(diff); + } + } + + /*** VIEWERS ***/ + + /** + * @notice Returns the amount pending rewards earned by providing liquidity to ibALPACA vault. + * @dev Does not includes the rewards minted by FairLaunch contract as they are distributed + * and moved to this router contact on each stake/redeem actions. + * @return The amount of pending rewards available for claim in ALPACA + */ + function getPendingRewards() public view returns (uint256) { + // return alpacaAtPiToken + getUnderlyingStaked - piToken.totalSupply() + return ALPACA.balanceOf(address(piToken)).add(_getUnderlyingStaked()).sub(piToken.totalSupply()); + } + + // WARNING: Unaccrued interest; Deposit will result in different rate + function alpaca2IbAlpaca(uint256 _alpacaAmount) public view returns (uint256) { + uint256 totalToken = IAlpacaVault(ibALPACA).totalToken(); + return totalToken == 0 ? _alpacaAmount : _alpacaAmount.mul(IERC20(ibALPACA).totalSupply()).div(totalToken); + } + + function ibAlpaca2Alpaca(uint256 _ibAlpacaAmount) public view returns (uint256) { + uint256 totalToken = IAlpacaVault(ibALPACA).totalToken(); + return _ibAlpacaAmount.mul(totalToken).div(IERC20(ibALPACA).totalSupply()); + } + + /*** INTERNALS ***/ + + function _getUnderlyingStaked() internal view override returns (uint256) { + if (staking == address(0)) { + return 0; + } + (uint256 ibAlpacaStaked, ) = IAlpacaFairLaunch(staking).userInfo(MASTER_CHEF_PID, address(piToken)); + return ibAlpaca2Alpaca(ibAlpacaStaked); + } + + function _stake(uint256 _amount) internal { + require(_amount > 0, "CANT_STAKE_0"); + + // Step #1. Mint ibALPACA + uint256 ibAlpacaBefore = IERC20(ibALPACA).balanceOf(address(piToken)); + piToken.approveUnderlying(ibALPACA, _amount); + piToken.callExternal(ibALPACA, IAlpacaVault.deposit.selector, abi.encode(_amount), 0); + uint256 ibAlpacaWrapped = IERC20(ibALPACA).balanceOf(address(piToken)).sub(ibAlpacaBefore); + + require(ibAlpacaWrapped > 0, "CANT_STAKE_0_IB"); + + uint256 alpacaBefore = ALPACA.balanceOf(address(piToken)); + + // Step #2. Stake ibALPACA + piToken.callExternal(ibALPACA, IERC20.approve.selector, abi.encode(staking, ibAlpacaWrapped), 0); + _callStaking(IAlpacaFairLaunch.deposit.selector, abi.encode(piToken, MASTER_CHEF_PID, ibAlpacaWrapped)); + + uint256 receivedReward = ALPACA.balanceOf(address(piToken)).sub(alpacaBefore); + _safeTransfer(ALPACA, address(this), receivedReward); + + emit AutoClaimRewards(msg.sender, receivedReward); + emit Stake(msg.sender, _amount, ibAlpacaWrapped, receivedReward); + } + + function _redeem(uint256 _alpacaAmount) internal { + require(_alpacaAmount > 0, "CANT_REDEEM_0"); + + // Accrue interest + IAlpacaVault(ibALPACA).withdraw(0); + + uint256 ibAlpacaAmount = alpaca2IbAlpaca(_alpacaAmount); + require(_alpacaAmount > 0, "CANT_REDEEM_0_IB"); + + uint256 alpacaBefore = ALPACA.balanceOf(address(piToken)); + _callStaking(IAlpacaFairLaunch.withdraw.selector, abi.encode(address(piToken), MASTER_CHEF_PID, ibAlpacaAmount)); + uint256 receivedReward = ALPACA.balanceOf(address(piToken)).sub(alpacaBefore); + _safeTransfer(ALPACA, address(this), receivedReward); + + piToken.callExternal(ibALPACA, IAlpacaVault.withdraw.selector, abi.encode(ibAlpacaAmount), 0); + + emit AutoClaimRewards(msg.sender, receivedReward); + emit Redeem(msg.sender, _alpacaAmount, ibAlpacaAmount, receivedReward); + } +} diff --git a/test/helpers/builders.js b/test/helpers/builders.js index 5b909e2b..25ca0343 100644 --- a/test/helpers/builders.js +++ b/test/helpers/builders.js @@ -51,6 +51,7 @@ function buildBakeryChefRouterConfig(token) { return { token }; } +// MASTER CHEF function buildMasterChefRouterConfig(token, masterChefPid) { return { token, masterChefPid }; } @@ -60,6 +61,11 @@ function buildAutoRouterConfig(AUTO) { return { AUTO }; } +// ALPACA +function buildAlpacaRouterConfig(ALPACA, ibALPACA, masterChefPid) { + return { ALPACA, ibALPACA, masterChefPid }; +} + // VENUS function buildVenusRouterConfig(troller, xvs) { return { troller, xvs }; @@ -150,6 +156,7 @@ module.exports = { buildBakeryChefRouterConfig, buildMasterChefRouterConfig, buildAutoRouterConfig, + buildAlpacaRouterConfig, buildVenusRouterConfig, buildAaveAssetConfigInput, buildBasicRouterArgs, diff --git a/test/router/implementations/AlpacaRouter.unit.js b/test/router/implementations/AlpacaRouter.unit.js new file mode 100644 index 00000000..093d8c68 --- /dev/null +++ b/test/router/implementations/AlpacaRouter.unit.js @@ -0,0 +1,535 @@ +const { time, constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { ether, artifactFromBytecode, latestBlockNumber } = require('../../helpers'); +const { buildBasicRouterConfig, buildAlpacaRouterConfig } = require('../../helpers/builders'); +const assert = require('chai').assert; +const AlpacaRouter = artifacts.require('AlpacaRouter'); +const WrappedPiErc20 = artifacts.require('WrappedPiErc20'); +const MockERC20 = artifacts.require('MockERC20'); +const PoolRestrictions = artifacts.require('PoolRestrictions'); +const MockGeneralMasterChef = artifacts.require('MockGeneralMasterChef'); +const MockGulpingBPool = artifacts.require('MockGulpingBPool'); +const MockPoke = artifacts.require('MockPoke'); + +const FairLaunch = artifactFromBytecode('bsc/AlpacaFairLaunch'); +const AlpacaVault = artifactFromBytecode('bsc/AlpacaVault'); +const AlpacaToken = artifactFromBytecode('bsc/AlpacaToken'); +const AlpacaTripleSlopeModel = artifactFromBytecode('bsc/AlpacaTripleSlopeModel'); +const AlpacaConfigurableInterestVaultConfig = artifactFromBytecode('bsc/AlpacaConfigurableInterestVaultConfig'); + +AlpacaRouter.numberFormat = 'String'; +WrappedPiErc20.numberFormat = 'String'; +MockERC20.numberFormat = 'String'; + +const { web3 } = WrappedPiErc20; + +const REPORTER_ID = 42; + +describe('Alpaca Tests', () => { + let deployer, bob, alice, piGov, stub, pvp, pool1, pool2, alpacaTreasury; + + before(async function() { + [deployer, bob, alice, piGov, stub, pvp, pool1, pool2, alpacaTreasury] = await web3.eth.getAccounts(); + }); + + let alpaca, debtToken, ibALPACA, vaultConfig, fairLaunch, poolRestrictions, piAlpaca, alpacaRouter, poke; + + beforeEach(async function() { + // bsc: 0xadcfbf2e8470493060fbe0a0afac66d2cb028e9c + const tripleSlopeModel = await AlpacaTripleSlopeModel.new(); + + // bsc: 0x8f0528ce5ef7b51152a59745befdd91d97091d2f + let currentBlock = (await time.latestBlock()).toNumber(); + alpaca = await AlpacaToken.new(currentBlock - 1, currentBlock); + + // bsc: 0x11362ea137a799298306123eea014b7809a9db40 (impl: 0x036664394715d255895f600861fe882a167dbf57) + debtToken = await MockERC20.new('AlpacaTokenDebt', 'ALPACADebt', 18, ether(10000000000)); + + // bsc: 0xa625ab01b08ce023b2a342dbb12a16f2c8489a8f + fairLaunch = await FairLaunch.new( + alpaca.address, + // devaddr + deployer, + // alpacaPerBlock + ether(20), + // startBlock + await latestBlockNumber(), + 0, + 0, + ); + + // bsc: 0x8f8ed54901b90c89c5817b7f67a425c0e6091284 (impl: 0xc2f7c637702b9131cb58dcbf49a119b77d994ed3) + vaultConfig = await AlpacaConfigurableInterestVaultConfig.new(); + await vaultConfig.initialize( + // _minDebtSize + ether(50), + // _reservePoolBps + 1900, + // _killBps + 100, + // _interestModel + tripleSlopeModel.address, + // _getWrappedNativeAddr + constants.ZERO_ADDRESS, + // _getWNativeRelayer + constants.ZERO_ADDRESS, + // _getFairLaunchAddr + fairLaunch.address, + // _getKillTreasuryBps + 400, + // _treasury + alpacaTreasury, + ); + + // bsc: 0xf1be8ecc990cbcb90e166b71e368299f0116d421 (impl: 0xcc7830c29fa5fdf0e289562470672285290e3a20) + ibALPACA = await AlpacaVault.new(); + await ibALPACA.initialize( + // vaultConfig, + vaultConfig.address, + // token + alpaca.address, + // name + 'Interest Bearing ALPACA ', + // symbol + 'ibALPACA', + // decimals + 18, + // debtToken + debtToken.address, + ); + + poolRestrictions = await PoolRestrictions.new(); + piAlpaca = await WrappedPiErc20.new(alpaca.address, stub, 'Wrapped ALPACA', 'piALPACA'); + + poke = await MockPoke.new(true); + alpacaRouter = await AlpacaRouter.new( + piAlpaca.address, + buildBasicRouterConfig( + poolRestrictions.address, + poke.address, + constants.ZERO_ADDRESS, + fairLaunch.address, + ether('0.2'), + ether('0.02'), + ether('0.3'), + '0', + pvp, + ether('0.15'), + [pool1, pool2], + ), + buildAlpacaRouterConfig(alpaca.address, ibALPACA.address, 0), + ); + + await piAlpaca.changeRouter(alpacaRouter.address, { from: stub }); + await fairLaunch.addPool(350, ibALPACA.address, true); + await alpacaRouter.transferOwnership(piGov); + + // setting up rewards + await alpaca.approve(ibALPACA.address, ether(100)); + await ibALPACA.deposit(ether(100)); + await alpaca.transfer(ibALPACA.address, ether(100)); + await alpaca.transferOwnership(fairLaunch.address); + + assert.equal(await alpacaRouter.owner(), piGov); + }); + + describe('owner methods', async () => { + beforeEach(async () => { + await alpacaRouter.transferOwnership(piGov, { from: piGov }); + }); + + describe('stake()/redeem()', () => { + beforeEach(async () => { + await alpaca.transfer(alice, ether('10000')); + await alpaca.approve(piAlpaca.address, ether('10000'), { from: alice }); + await piAlpaca.deposit(ether('10000'), { from: alice }); + assert.equal(await ibALPACA.balanceOf(fairLaunch.address), ether(0)); + + await alpacaRouter.pokeFromReporter(REPORTER_ID, false, '0x'); + + assert.equal(await alpaca.balanceOf(piAlpaca.address), ether(2000)); + assert.equal(await ibALPACA.balanceOf(fairLaunch.address), ether(4000)); + assert.equal((await fairLaunch.userInfo(0, piAlpaca.address)).amount, ether(4000)); + }); + + describe('stake()', () => { + it('should allow the owner staking any amount of reserve tokens', async () => { + const res = await alpacaRouter.stake(ether(2000), { from: piGov }); + expectEvent(res, 'Stake', { + sender: piGov, + amount: ether(2000), + }); + assert.equal(await alpaca.balanceOf(piAlpaca.address), ether(0)); + assert.equal(await ibALPACA.balanceOf(fairLaunch.address), ether(5000)); + const userInfo = await fairLaunch.userInfo(0, piAlpaca.address); + assert.equal(userInfo.amount, ether(5000)); + }); + + it('should deny non-owner staking any amount of reserve tokens', async () => { + await expectRevert(alpacaRouter.stake(ether(1), { from: alice }), 'Ownable: caller is not the owner'); + }); + }); + + describe('redeem()', () => { + it('should allow the owner redeeming any amount of reserve tokens', async () => { + const res = await alpacaRouter.redeem(ether(3000), { from: piGov }); + expectEvent(res, 'Redeem', { + sender: piGov, + amount: ether(3000), + ibAlpacaAmount: ether(1500), + rewardReceived: ether(20), + }); + assert.equal(await alpaca.balanceOf(piAlpaca.address), ether(5000)); + assert.equal(await ibALPACA.balanceOf(fairLaunch.address), ether(2500)); + assert.equal((await fairLaunch.userInfo(0, piAlpaca.address)).amount, ether(2500)); + }); + + it('should deny non-owner staking any amount of reserve tokens', async () => { + await expectRevert(alpacaRouter.redeem(ether(1), { from: alice }), 'Ownable: caller is not the owner'); + }); + }); + }); + + describe('setRewardPools()', () => { + it('should allow the owner setting a new reward pool', async () => { + const res = await alpacaRouter.setRewardPools([alice, bob], { from: piGov }); + expectEvent(res, 'SetRewardPools', { + len: '2', + rewardPools: [alice, bob], + }); + }); + + it('should deny setting an empty reward pool', async () => { + await expectRevert(alpacaRouter.setRewardPools([], { from: piGov }), 'AT_LEAST_ONE_EXPECTED'); + }); + + it('should deny non-owner setting a new reward pool', async () => { + await expectRevert( + alpacaRouter.setRewardPools([alice, bob], { from: alice }), + 'Ownable: caller is not the owner', + ); + }); + }); + + describe('setPvpFee()', () => { + it('should allow the owner setting a new pvpFee', async () => { + const res = await alpacaRouter.setPvpFee(ether('0.1'), { from: piGov }); + expectEvent(res, 'SetPvpFee', { + pvpFee: ether('0.1'), + }); + }); + + it('should deny setting a fee greater or equal 100%', async () => { + await expectRevert(alpacaRouter.setPvpFee(ether('1'), { from: piGov }), 'PVP_FEE_OVER_THE_LIMIT'); + }); + + it('should deny non-owner setting a new pvpFee', async () => { + await expectRevert(alpacaRouter.setPvpFee(ether('0'), { from: alice }), 'Ownable: caller is not the owner'); + }); + }); + }); + + describe('reserve management', () => { + beforeEach(async () => { + // alice + await alpaca.transfer(alice, ether('20000')); + await alpaca.approve(piAlpaca.address, ether('10000'), { from: alice }); + await piAlpaca.deposit(ether('10000'), { from: alice }); + + // bob + await alpaca.transfer(bob, ether('42000')); + + await alpaca.approve(ibALPACA.address, ether('42000'), { from: bob }); + await ibALPACA.deposit(ether('42000'), { from: bob }); + assert.equal(await alpaca.balanceOf(ibALPACA.address), ether(42200)); + assert.equal(await ibALPACA.balanceOf(bob), ether(21000)); + + await ibALPACA.approve(fairLaunch.address, ether(21000), { from: bob }); + await fairLaunch.deposit(bob, 0, ether(21000), { from: bob }); + assert.equal(await alpaca.balanceOf(fairLaunch.address), ether(0)); + assert.equal(await ibALPACA.balanceOf(fairLaunch.address), ether(21000)); + + await alpacaRouter.pokeFromReporter(REPORTER_ID, false, '0x'); + + assert.equal(await alpaca.balanceOf(fairLaunch.address), ether(20)); + assert.equal(await alpaca.balanceOf(piAlpaca.address), ether(2000)); + assert.equal(await alpaca.balanceOf(ibALPACA.address), ether(50200)); + assert.equal(await ibALPACA.balanceOf(fairLaunch.address), ether(25000)); + }); + + it('should increase reserve on deposit', async () => { + assert.equal(await piAlpaca.balanceOf(alice), ether(10000)); + await alpaca.approve(piAlpaca.address, ether(1000), { from: alice }); + await piAlpaca.deposit(ether(1000), { from: alice }); + await alpacaRouter.pokeFromReporter(REPORTER_ID, false, '0x'); + + assert.equal(await piAlpaca.balanceOf(alice), ether(11000)); + assert.equal(await alpaca.balanceOf(fairLaunch.address), ether('70.4')); + assert.equal(await alpaca.balanceOf(piAlpaca.address), ether(2200)); + assert.equal(await alpaca.balanceOf(ibALPACA.address), ether(51000)); + assert.equal(await ibALPACA.balanceOf(fairLaunch.address), ether(25400)); + assert.equal(await alpacaRouter.getUnderlyingStaked(), ether(8800)); + assert.equal((await fairLaunch.userInfo(0, piAlpaca.address)).amount, ether(4400)); + }); + + it('should decrease reserve on withdrawal', async () => { + assert.equal(await piAlpaca.balanceOf(alice), ether(10000)); + + await piAlpaca.withdraw(ether(1000), { from: alice }); + await alpacaRouter.pokeFromReporter(REPORTER_ID, false, '0x'); + + assert.equal(await piAlpaca.balanceOf(alice), ether(9000)); + assert.equal(await alpaca.balanceOf(fairLaunch.address), ether('53.6')); + assert.equal(await alpaca.balanceOf(piAlpaca.address), ether(1800)); + assert.equal(await alpaca.balanceOf(ibALPACA.address), ether(49400)); + assert.equal(await alpacaRouter.getUnderlyingStaked(), ether(7200)); + assert.equal((await fairLaunch.userInfo(0, piAlpaca.address)).amount, ether(3600)); + assert.equal(await ibALPACA.balanceOf(fairLaunch.address), ether(24600)); + }); + + it('should ignore rebalancing if the staking address is 0', async () => { + await alpacaRouter.redeem(ether(8000), { from: piGov }); + await alpacaRouter.setVotingAndStaking(fairLaunch.address, constants.ZERO_ADDRESS, { from: piGov }); + + assert.equal(await alpaca.balanceOf(fairLaunch.address), ether('36.8')); + assert.equal(await alpaca.balanceOf(piAlpaca.address), ether(10000)); + assert.equal(await piAlpaca.balanceOf(alice), ether(10000)); + assert.equal(await piAlpaca.totalSupply(), ether(10000)); + await piAlpaca.withdraw(ether(1000), { from: alice }); + assert.equal(await ibALPACA.balanceOf(fairLaunch.address), ether(21000)); + await expectRevert(alpacaRouter.pokeFromReporter(REPORTER_ID, false, '0x'), 'STAKING_IS_NULL'); + }); + + describe('when interval enabled', () => { + beforeEach(async () => { + await alpacaRouter.setReserveConfig(ether('0.2'), ether('0.02'), ether('0.3'), time.duration.hours(1), { + from: piGov, + }); + await poke.setMinMaxReportIntervals(time.duration.hours(1), time.duration.hours(2), { from: piGov }); + }); + + it('should DO rebalance by pokeFromReporter if the rebalancing interval has passed', async () => { + await time.increase(time.duration.minutes(61)); + + await alpaca.approve(piAlpaca.address, ether(1000), { from: alice }); + await piAlpaca.deposit(ether(1000), { from: alice }); + await expectRevert(alpacaRouter.pokeFromSlasher(0, false, '0x'), 'MAX_INTERVAL_NOT_REACHED'); + }); + + it('should DO rebalance by pokeFromSlasher if the rebalancing interval has passed', async () => { + await time.increase(time.duration.minutes(121)); + + await alpaca.approve(piAlpaca.address, ether(1000), { from: alice }); + await piAlpaca.deposit(ether(1000), { from: alice }); + await alpacaRouter.pokeFromSlasher(0, false, '0x'); + + assert.equal(await alpaca.balanceOf(fairLaunch.address), ether('120.8')); + assert.equal((await fairLaunch.userInfo(0, piAlpaca.address)).amount, ether(4400)); + assert.equal(await alpaca.balanceOf(piAlpaca.address), ether(2200)); + }); + + it('should DO rebalance on withdrawal if the rebalancing interval has passed', async () => { + await time.increase(time.duration.minutes(61)); + + await piAlpaca.withdraw(ether(1000), { from: alice }); + await alpacaRouter.pokeFromReporter(REPORTER_ID, false, '0x'); + + assert.equal(await alpaca.balanceOf(fairLaunch.address), ether(104)); + assert.equal((await fairLaunch.userInfo(0, piAlpaca.address)).amount, ether(3600)); + assert.equal(await alpaca.balanceOf(piAlpaca.address), ether(1800)); + }); + + it('should NOT rebalance by pokeFromReporter if the rebalancing interval has passed', async () => { + await time.increase(time.duration.minutes(50)); + + await alpaca.approve(piAlpaca.address, ether(1000), { from: alice }); + await piAlpaca.deposit(ether(1000), { from: alice }); + await expectRevert(alpacaRouter.pokeFromReporter(0, false, '0x'), 'MIN_INTERVAL_NOT_REACHED'); + await expectRevert(alpacaRouter.pokeFromSlasher(0, false, '0x'), 'MAX_INTERVAL_NOT_REACHED'); + }); + + it('should NOT rebalance by pokeFromSlasher if the rebalancing interval has passed', async () => { + await time.increase(time.duration.minutes(70)); + + await alpaca.approve(piAlpaca.address, ether(1000), { from: alice }); + await piAlpaca.deposit(ether(1000), { from: alice }); + await expectRevert(alpacaRouter.pokeFromSlasher(0, false, '0x'), 'MAX_INTERVAL_NOT_REACHED'); + }); + }); + + describe('on poke', async () => { + it('should do nothing when nothing has changed', async () => { + await alpacaRouter.pokeFromReporter(REPORTER_ID, false, '0x'); + + assert.equal(await alpaca.balanceOf(fairLaunch.address), ether(20)); + assert.equal(await alpaca.balanceOf(ibALPACA.address), ether(50200)); + assert.equal(await ibALPACA.balanceOf(fairLaunch.address), ether(25000)); + assert.equal((await fairLaunch.userInfo(0, piAlpaca.address)).amount, ether(4000)); + assert.equal(await alpaca.balanceOf(piAlpaca.address), ether(2000)); + }); + + it('should increase reserve if required', async () => { + await alpaca.transfer(piAlpaca.address, ether(1000), { from: alice }); + + assert.equal(await alpaca.balanceOf(fairLaunch.address), ether(20)); + assert.equal(await alpaca.balanceOf(ibALPACA.address), ether(50200)); + assert.equal(await ibALPACA.balanceOf(fairLaunch.address), ether(25000)); + assert.equal((await fairLaunch.userInfo(0, piAlpaca.address)).amount, ether(4000)); + assert.equal(await alpaca.balanceOf(piAlpaca.address), ether(3000)); + + await alpacaRouter.pokeFromReporter(REPORTER_ID, false, '0x'); + + assert.equal(await alpaca.balanceOf(ibALPACA.address), ether(51000)); + assert.equal(await ibALPACA.balanceOf(fairLaunch.address), ether(25400)); + assert.equal((await fairLaunch.userInfo(0, piAlpaca.address)).amount, ether(4400)); + assert.equal(await alpaca.balanceOf(piAlpaca.address), ether(2200)); + }); + }); + + it('should stake all the underlying tokens with 0 RR', async () => { + await alpacaRouter.setReserveConfig(ether(0), ether(0), ether(1), 0, { from: piGov }); + + await alpacaRouter.pokeFromReporter(REPORTER_ID, false, '0x'); + assert.equal(await ibALPACA.balanceOf(fairLaunch.address), ether(26000)); + assert.equal(await alpaca.balanceOf(piAlpaca.address), ether(0)); + }); + + it('should keep all the underlying tokens on piToken with 1 RR', async () => { + await alpacaRouter.setReserveConfig(ether(1), ether(0), ether(1), 0, { from: piGov }); + + await alpacaRouter.pokeFromReporter(REPORTER_ID, false, '0x'); + assert.equal(await ibALPACA.balanceOf(fairLaunch.address), ether(21000)); + assert.equal(await alpaca.balanceOf(piAlpaca.address), ether(10000)); + }); + }); + + describe('reward distribution', async () => { + let poolA, poolB, poolC, poolD; + + beforeEach(async function() { + poolA = await MockGulpingBPool.new(); + poolB = await MockGulpingBPool.new(); + poolC = await MockGulpingBPool.new(); + poolD = await MockGulpingBPool.new(); + await alpacaRouter.setRewardPools([poolA.address, poolB.address, poolC.address], { from: piGov }); + + await poolRestrictions.setVotingAllowedForSenders(fairLaunch.address, [alice], [true]); + + await alpaca.transfer(alice, ether('10000')); + await alpaca.approve(piAlpaca.address, ether('10000'), { from: alice }); + await piAlpaca.deposit(ether('10000'), { from: alice }); + + await alpacaRouter.pokeFromReporter(REPORTER_ID, false, '0x'); + + assert.equal(await piAlpaca.totalSupply(), ether(10000)); + assert.equal(await piAlpaca.balanceOf(alice), ether(10000)); + + await piAlpaca.transfer(poolA.address, 10, { from: alice }); + await piAlpaca.transfer(poolB.address, 20, { from: alice }); + }); + + it('should allow distribute the accrued rewards', async () => { + // Staked: 8000alpaca/4000ibAlpaca; Reserve: 2000alpaca + + await alpaca.transfer(ibALPACA.address, ether(16400)); + + assert.equal(await ibALPACA.balanceOf(piAlpaca.address), ether(0)); + assert.equal(await ibALPACA.balanceOf(fairLaunch.address), ether(4000)); + + assert.equal((await fairLaunch.userInfo(0, piAlpaca.address)).amount, ether(4000)); + + assert.equal(await alpaca.balanceOf(piAlpaca.address), ether(2000)); + // 8000 from piToken; 100 from the initial depositor; 100 as initial reward + assert.equal(await alpaca.balanceOf(ibALPACA.address), ether(24600)); + assert.equal(await alpacaRouter.getUnderlyingStaked(), ether(24000)); + assert.equal(await alpacaRouter.getPendingRewards(), ether(16000)); + + let res = await alpacaRouter.pokeFromReporter(REPORTER_ID, true, '0x', { from: bob }); + + expectEvent(res, 'ClaimRewards', { + sender: bob, + calculatedAlpacaReward: ether(16000), + calculatedIbAlpacaReward: ether('2666.666666666666666666'), + actualAlpacaEarned: ether('15999.999999999999999996'), + }); + + expectEvent(res, 'AutoClaimRewards', { + sender: bob, + alpacaRewards: ether(80), + }); + + expectEvent(res, 'DistributeRewards', { + sender: bob, + alpacaReward: ether(80), + pvpReward: ether('12'), + poolRewardsUnderlying: ether(68), + poolRewardsPi: ether('26.153846153846153846'), + pools: [poolA.address, poolB.address, poolC.address], + }); + + assert.equal(await alpaca.balanceOf(piAlpaca.address), ether('21267.999999999999999994')); + assert.equal(await alpaca.balanceOf(alpacaRouter.address), '0'); + + assert.isTrue(parseInt(res.logs[5].args.poolRewardsUnderlying) > 1); + assert.isTrue(parseInt(res.logs[5].args.poolRewardsPi.length) > 1); + + await expectEvent.inTransaction(res.tx, poolA, 'Gulp'); + await expectEvent.inTransaction(res.tx, poolB, 'Gulp'); + await expectEvent.notEmitted.inTransaction(res.tx, poolC, 'Gulp'); + await expectEvent.notEmitted.inTransaction(res.tx, poolD, 'Gulp'); + + assert.equal(res.logs.length, 6); + assert.equal(res.logs[3].args.pool, poolA.address); + assert.equal(res.logs[3].args.amount, ether('8.717948717948717948')); + assert.equal(res.logs[4].args.pool, poolB.address); + assert.equal(res.logs[4].args.amount, ether('17.435897435897435897')); + + assert.equal(await piAlpaca.balanceOf(poolA.address), ether('8.717948717948717958')); + assert.equal(await piAlpaca.balanceOf(poolB.address), ether('17.435897435897435917')); + assert.equal(await piAlpaca.balanceOf(poolC.address), '0'); + assert.equal(await piAlpaca.balanceOf(poolD.address), '0'); + + assert.equal(await alpaca.balanceOf(alpacaRouter.address), '0'); + assert.equal(await alpaca.balanceOf(alpacaRouter.address), '0'); + }); + + // TODO: implement + it.skip('should revert poke if there is nothing released', async () => { + const dishonestChef = await MockGeneralMasterChef.new(alpaca.address); + await alpacaRouter.setReserveConfig(ether(1), 0, { from: piGov }); + await alpacaRouter.pokeFromReporter(REPORTER_ID, false, '0x'); + await alpacaRouter.setVotingAndStaking(constants.ZERO_ADDRESS, dishonestChef.address, { from: piGov }); + await alpacaRouter.setReserveConfig(ether('0.2'), 0, { from: piGov }); + + // there are still some rewards from rebalancing pokes + await alpacaRouter.pokeFromReporter(REPORTER_ID, true, '0x'); + + // and now there are no rewards + await expectRevert(alpacaRouter.pokeFromReporter(REPORTER_ID, true, '0x'), 'NO_PENDING_REWARD'); + }); + + // TODO: implement + it.skip('should revert distributing rewards when missing reward pools config', async () => { + poke = await MockPoke.new(true); + const router = await AlpacaRouter.new( + piAlpaca.address, + buildBasicRouterConfig( + poolRestrictions.address, + poke.address, + fairLaunch.address, + fairLaunch.address, + ether('0.2'), + ether('0.02'), + '0', + pvp, + ether('0.2'), + [], + ), + buildAlpacaRouterConfig(alpaca.address, ibALPACA.address, 0), + ); + await alpacaRouter.migrateToNewRouter(piAlpaca.address, router.address, [], { from: piGov }); + await alpaca.transfer(fairLaunch.address, ether(2000)); + await time.increase(1); + await expectRevert(router.pokeFromReporter(REPORTER_ID, true, '0x'), 'MISSING_REWARD_POOLS'); + }); + }); +});