Forkchoice Ethereum Mainnet

Address Contract Partially Verified

Address 0x47cE21BF9a4dC3CE3645C18c38A00D9DAc0Db136
Balance 0.018146 ETH ($35.99)
Nonce 1
Code Size 15803 bytes
Indexed Transactions 0
External Etherscan · Sourcify

Contract Bytecode

15803 bytes
0x6080604052600436106102085760003560e01c8063a969b18611610118578063c92d7169116100a0578063de37b7a11161006f578063de37b7a114610608578063dec3655414610637578063e25208e314610657578063f0359d1b14610677578063f2fde38b1461068c57610263565b8063c92d716914610588578063d172d3a3146105a8578063d2f31c39146105c8578063d4b94901146105e857610263565b8063b8a4aeaf116100e7578063b8a4aeaf14610509578063ba2d373c14610529578063c08da7a11461053e578063c5e6e35714610553578063c5f0a58f1461057357610263565b8063a969b1861461047c578063b0cd498b1461049c578063b384abef146104bc578063b3e9ba27146104dc57610263565b80634edd0d671161019b5780638769e3241161016a5780638769e324146103e75780638da5cb5b146104075780639d21ce9c1461041c5780639e3853ec1461043c5780639faf1d511461045c57610263565b80634edd0d6714610388578063715018a61461039d5780637ee1506d146103b2578063811c7fe2146103d257610263565b806335f8aa9b116101d757806335f8aa9b1461030f578063413f92c01461032457806341682744146103515780634d8f51051461037357610263565b8063026625851461026857806309f67b3a1461028857806322b143fb146102be57806329f6ff41146102e057610263565b3661026357336000908152600560205260409020546001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee146102615760405162461bcd60e51b8152600401610258906136b4565b60405180910390fd5b005b600080fd5b34801561027457600080fd5b50610261610283366004613478565b6106ac565b34801561029457600080fd5b506102a86102a33660046131e0565b610901565b6040516102b59190613630565b60405180910390f35b3480156102ca57600080fd5b506102d3610916565b6040516102b591906135c0565b3480156102ec57600080fd5b506103006102fb366004613478565b610ae4565b6040516102b593929190613c93565b34801561031b57600080fd5b50610261610b17565b34801561033057600080fd5b5061034461033f3660046131e0565b610bfd565b6040516102b5919061356f565b34801561035d57600080fd5b50610366610c18565b6040516102b59190613c7c565b34801561037f57600080fd5b50610344610c3c565b34801561039457600080fd5b50610366610c60565b3480156103a957600080fd5b50610261610c66565b3480156103be57600080fd5b506102616103cd3660046132bb565b610ce5565b3480156103de57600080fd5b50610344610e10565b3480156103f357600080fd5b50610261610402366004613402565b610e34565b34801561041357600080fd5b506103446111fa565b34801561042857600080fd5b50610261610437366004613478565b611209565b34801561044857600080fd5b506103666104573660046132f3565b61139b565b34801561046857600080fd5b50610261610477366004613478565b61154d565b34801561048857600080fd5b506102616104973660046133d0565b6117c4565b3480156104a857600080fd5b506103446104b7366004613478565b611828565b3480156104c857600080fd5b506102616104d7366004613502565b61184f565b3480156104e857600080fd5b506104fc6104f7366004613478565b611900565b6040516102b59190613c59565b34801561051557600080fd5b506102d3610524366004613334565b611964565b34801561053557600080fd5b50610366611979565b34801561054a57600080fd5b5061036661199d565b34801561055f57600080fd5b506102d361056e3660046131e0565b6119a3565b34801561057f57600080fd5b506104fc611a65565b34801561059457600080fd5b506102a86105a33660046134cc565b611b11565b3480156105b457600080fd5b506102616105c3366004613249565b611b37565b3480156105d457600080fd5b506102616105e33660046131e0565b611b47565b3480156105f457600080fd5b506102616106033660046131fc565b611d53565b34801561061457600080fd5b506106286106233660046134a8565b611db8565b6040516102b59392919061363b565b34801561064357600080fd5b506103666106523660046134a8565b611de6565b34801561066357600080fd5b506102d3610672366004613368565b611f8f565b34801561068357600080fd5b50610344612007565b34801561069857600080fd5b506102616106a73660046131e0565b61202b565b6106b46120e1565b6000546001600160a01b039081169116146106e15760405162461bcd60e51b815260040161025890613b00565b600081116107015760405162461bcd60e51b815260040161025890613a6a565b6040516323b872dd60e01b81526001600160a01b037f000000000000000000000000dd974d5c2e2928dea5f71b9825b8b646686bd20016906323b872dd9061075190339030908690600401613583565b602060405180830381600087803b15801561076b57600080fd5b505af115801561077f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107a39190613458565b6107bf5760405162461bcd60e51b815260040161025890613b35565b60405163095ea7b360e01b81526001600160a01b037f000000000000000000000000dd974d5c2e2928dea5f71b9825b8b646686bd200169063095ea7b39061082d907f000000000000000000000000ecf0bdb7b3f349abfd68c3563678124c5e8aaea39085906004016135a7565b602060405180830381600087803b15801561084757600080fd5b505af115801561085b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061087f9190613458565b5060405163b6b55f2560e01b81526001600160a01b037f000000000000000000000000ecf0bdb7b3f349abfd68c3563678124c5e8aaea3169063b6b55f25906108cc908490600401613c7c565b600060405180830381600087803b1580156108e657600080fd5b505af11580156108fa573d6000803e3d6000fd5b5050505050565b60066020526000908152604090205460ff1681565b606060007f00000000000000000000000049bdd8854481005bba4acebabf6e06cd5f6312e96001600160a01b0316634408d2ba6040518163ffffffff1660e01b815260040160206040518083038186803b15801561097357600080fd5b505afa158015610987573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109ab9190613490565b905060006109df827f000000000000000000000000000000000000000000000000000000000000000363ffffffff6120e516565b90506060816001600160401b03811180156109f957600080fd5b50604051908082528060200260200182016040528015610a23578160200160208202803683370190505b50905060007f00000000000000000000000000000000000000000000000000000000000000035b84811015610a765780838381518110610a5f57fe5b602090810291909101015260019182019101610a4a565b50610adb826004805480602002602001604051908101604052809291908181526020018280548015610ad157602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610ab3575b5050505050612127565b94505050505090565b60038181548110610af157fe5b600091825260209091206003909102018054600182015460029092015490925060ff1683565b60038054600091906000198101908110610b2d57fe5b9060005260206000209060030201905060007f00000000000000000000000049bdd8854481005bba4acebabf6e06cd5f6312e96001600160a01b0316634408d2ba6040518163ffffffff1660e01b815260040160206040518083038186803b158015610b9857600080fd5b505afa158015610bac573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bd09190613490565b905080826000015411158015610beb5750600282015460ff16155b15610bf957610bf98261233a565b5050565b6005602052600090815260409020546001600160a01b031681565b7f000000000000000000000000000000000000000000000000000000000000000381565b7f00000000000000000000000049bdd8854481005bba4acebabf6e06cd5f6312e981565b60045490565b610c6e6120e1565b6000546001600160a01b03908116911614610c9b5760405162461bcd60e51b815260040161025890613b00565b600080546040516001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080546001600160a01b0319169055565b610ced6120e1565b6000546001600160a01b03908116911614610d1a5760405162461bcd60e51b815260040161025890613b00565b6001600160a01b038216610d405760405162461bcd60e51b81526004016102589061392f565b6001600160a01b038281166000908152600560205260409020541615610d785760405162461bcd60e51b8152600401610258906138aa565b60048054600181019091557f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b0180546001600160a01b038085166001600160a01b03199283168117909355600083815260056020526040808220805487851695169490941793849055519290911692917fff2847fd2ae19fe4c306a71befdc972f378c04028957c133235dd59d325e23669190a35050565b7f000000000000000000000000dd974d5c2e2928dea5f71b9825b8b646686bd20081565b6000825111610e555760405162461bcd60e51b815260040161025890613b6a565b610e5e8261238d565b610e7a5760405162461bcd60e51b815260040161025890613974565b6000815111610e9b5760405162461bcd60e51b815260040161025890613867565b606081516001600160401b0381118015610eb457600080fd5b50604051908082528060200260200182016040528015610ede578160200160208202803683370190505b5090506000805b845181101561114f576000858281518110610efc57fe5b60200260200101519050610f1081846123f5565b9250600060038481548110610f2157fe5b60009182526020909120600390910201600281015490915060ff16610f4957610f498161233a565b6000807f000000000000000000000000ecf0bdb7b3f349abfd68c3563678124c5e8aaea36001600160a01b03166316554d6230866040518363ffffffff1660e01b8152600401610f9a9291906135a7565b60606040518083038186803b158015610fb257600080fd5b505afa158015610fc6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fea9190613523565b50909250905060005b885181101561113e57611004612ff4565b611050868b848151811061101457fe5b602090810291909101810151604080516060810182528a54815260018b01549381019390935260028a015460ff16151590830152908787612490565b90508060400151600014156110655750611136565b61108f8160c001518a848151811061107957fe5b60200260200101516126c990919063ffffffff16565b89838151811061109b57fe5b602002602001018181525050600660008b84815181106110b757fe5b6020908102919091018101516001600160a01b031682528101919091526040016000205460ff16611134576001600660008c85815181106110f457fe5b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff0219169083151502179055505b505b600101610ff3565b505060019093019250610ee5915050565b50600061115a6111fa565b905060005b83518110156111f2576111ea6005600087848151811061117b57fe5b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060009054906101000a90046001600160a01b0316838684815181106111c457fe5b60200260200101516040518060600160405280602a8152602001613d32602a91396126ee565b60010161115f565b505050505050565b6000546001600160a01b031690565b6112116120e1565b6000546001600160a01b0390811691161461123e5760405162461bcd60e51b815260040161025890613b00565b6000811161125e5760405162461bcd60e51b8152600401610258906139f2565b604051632e1a7d4d60e01b81526001600160a01b037f000000000000000000000000ecf0bdb7b3f349abfd68c3563678124c5e8aaea31690632e1a7d4d906112aa908490600401613c7c565b600060405180830381600087803b1580156112c457600080fd5b505af11580156112d8573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000dd974d5c2e2928dea5f71b9825b8b646686bd20016925063a9059cbb915061132a90339085906004016135a7565b602060405180830381600087803b15801561134457600080fd5b505af1158015611358573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061137c9190613458565b6113985760405162461bcd60e51b8152600401610258906137ac565b50565b60008281526002602090815260408083206001600160a01b038516845290915281205460ff166113cd57506000611546565b60008381526001602090815260408083206001600160a01b038089168552908352818420908616845290915290205460ff161561140c57506000611546565b6000807f000000000000000000000000ecf0bdb7b3f349abfd68c3563678124c5e8aaea36001600160a01b03166342ce39cb87876040518363ffffffff1660e01b815260040161145d9291906135a7565b60606040518083038186803b15801561147557600080fd5b505afa158015611489573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114ad9190613523565b925050915081600014156114c657600092505050611546565b6001600160a01b03811630146114e157600092505050611546565b6114e9613043565b5060008581526002602081815260408084206001600160a01b03891685528252928390208351606081018552815460ff161515815260018201549281018390529201549282018390529091611540918591906127b4565b93505050505b9392505050565b6115556120e1565b6000546001600160a01b039081169116146115825760405162461bcd60e51b815260040161025890613b00565b6127108111156115a45760405162461bcd60e51b8152600401610258906138e1565b60007f00000000000000000000000049bdd8854481005bba4acebabf6e06cd5f6312e96001600160a01b0316634408d2ba6040518163ffffffff1660e01b815260040160206040518083038186803b1580156115ff57600080fd5b505afa158015611613573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116379190613490565b9050600061166b827f000000000000000000000000000000000000000000000000000000000000000263ffffffff6126c916565b60038054919250600091600019810190811061168357fe5b9060005260206000209060030201905082816000015411156116ae5781815560018101849055611775565b600281015460ff166116c3576116c38161233a565b60408051606081018252838152602081018681526000928201838152600380546001810182559481905292517fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b9490930293840192909255517fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85c830155517fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85d909101805460ff19169115159190911790555b7f2803ffe778731e96b0cb4ffdea51f618e2dc70ed59841f65fb6a92296b3960686117a783600163ffffffff6120e516565b856040516117b6929190613c85565b60405180910390a150505050565b61139881600480548060200260200160405190810160405280929190818152602001828054801561181e57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611800575b5050505050610e34565b6004818154811061183557fe5b6000918252602090912001546001600160a01b0316905081565b6118576120e1565b6000546001600160a01b039081169116146118845760405162461bcd60e51b815260040161025890613b00565b60405163b384abef60e01b81526001600160a01b037f00000000000000000000000049bdd8854481005bba4acebabf6e06cd5f6312e9169063b384abef906118d29085908590600401613c85565b600060405180830381600087803b1580156118ec57600080fd5b505af11580156111f2573d6000803e3d6000fd5b611908613066565b60036119158360006123f5565b8154811061191f57fe5b60009182526020918290206040805160608101825260039093029091018054835260018101549383019390935260029092015460ff1615159181019190915292915050565b60606119718484846127ca565b949350505050565b7f000000000000000000000000000000000000000000000000000000000000000281565b60035490565b606060007f00000000000000000000000049bdd8854481005bba4acebabf6e06cd5f6312e96001600160a01b0316634408d2ba6040518163ffffffff1660e01b815260040160206040518083038186803b158015611a0057600080fd5b505afa158015611a14573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a389190613490565b9050611546837f0000000000000000000000000000000000000000000000000000000000000003836127ca565b611a6d613066565b60007f00000000000000000000000049bdd8854481005bba4acebabf6e06cd5f6312e96001600160a01b0316634408d2ba6040518163ffffffff1660e01b815260040160206040518083038186803b158015611ac857600080fd5b505afa158015611adc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b009190613490565b9050611b0b81611900565b91505090565b600160209081526000938452604080852082529284528284209052825290205460ff1681565b611b428383836128cb565b505050565b611b4f6120e1565b6000546001600160a01b03908116911614611b7c5760405162461bcd60e51b815260040161025890613b00565b6001600160a01b0381811660009081526005602052604090205416611bb35760405162461bcd60e51b8152600401610258906139bb565b6001600160a01b03811660009081526006602052604090205460ff1615611bec5760405162461bcd60e51b815260040161025890613809565b600480546001600160a01b03831691906000198101908110611c0a57fe5b6000918252602090912001546001600160a01b031614611cd85760005b600454811015611cd657816001600160a01b031660048281548110611c4857fe5b6000918252602090912001546001600160a01b03161415611cce57600480546000198101908110611c7557fe5b600091825260209091200154600480546001600160a01b039092169183908110611c9b57fe5b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550611cd6565b600101611c27565b505b6004805480611ce357fe5b60008281526020808220830160001990810180546001600160a01b031990811690915593019093556001600160a01b03841680825260059093526040808220805490931690925590517fe5b28609ccc5cc2a3e4736068efad3e54a27ff556e326920df4213a66efbf5ab9190a250565b610bf982826004805480602002602001604051908101604052809291908181526020018280548015611dae57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611d90575b50505050506128cb565b6002602081815260009384526040808520909152918352912080546001820154919092015460ff9092169183565b60008281526002602090815260408083206001600160a01b038516845290915281205460ff1615611e1957506000611f89565b60405163133c617560e31b81526000906001600160a01b037f00000000000000000000000049bdd8854481005bba4acebabf6e06cd5f6312e916906399e30ba890611e6a90309088906004016135a7565b60206040518083038186803b158015611e8257600080fd5b505afa158015611e96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611eba9190613490565b905080611ecb576000915050611f89565b6040516394cee7b360e01b81526000906001600160a01b038516906394cee7b390611efa908890600401613c7c565b60206040518083038186803b158015611f1257600080fd5b505afa158015611f26573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f4a9190613490565b905080611f5c57600092505050611f89565b611f84670de0b6b3a7640000611f78838563ffffffff612b9916565b9063ffffffff612bd316565b925050505b92915050565b6060611ffe8585808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152505060408051602080890282810182019093528882529093508892508791829185019084908082843760009201919091525061212792505050565b95945050505050565b7f000000000000000000000000ecf0bdb7b3f349abfd68c3563678124c5e8aaea381565b6120336120e1565b6000546001600160a01b039081169116146120605760405162461bcd60e51b815260040161025890613b00565b6001600160a01b0381166120865760405162461bcd60e51b8152600401610258906136fa565b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b3390565b600061154683836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250612c15565b60608061213f83518551612b9990919063ffffffff16565b6001600160401b038111801561215457600080fd5b5060405190808252806020026020018201604052801561218e57816020015b61217b613089565b8152602001906001900390816121735790505b5090506000805b855181101561229c5760005b85518110156122935760006121dc8884815181106121bb57fe5b60200260200101518884815181106121cf57fe5b6020026020010151611de6565b9050801561228a5760405180608001604052808985815181106121fb57fe5b6020026020010151815260200188848151811061221457fe5b60200260200101516001600160a01b03168152602001828152602001600560008a868151811061224057fe5b6020908102919091018101516001600160a01b0390811683529082019290925260400160002054169052855186908690811061227857fe5b60209081029190910101526001909301925b506001016121a1565b50600101612195565b506060816001600160401b03811180156122b557600080fd5b506040519080825280602002602001820160405280156122ef57816020015b6122dc613089565b8152602001906001900390816122d45790505b50905060005b828110156123305783818151811061230957fe5b602002602001015182828151811061231d57fe5b60209081029190910101526001016122f5565b5095945050505050565b60028101805460ff191660019081179091558154908201546040517f0aaa05fba10caab20c7dfcd757223e489dbd2313a5e1add54bca74aceaf1781992612382929091613c85565b60405180910390a150565b60008060019050600183511115611f895760005b60018451038110156123ee578381600101815181106123bc57fe5b60200260200101518482815181106123d057fe5b6020026020010151106123e657600091506123ee565b6001016123a1565b5092915050565b6000826003838154811061240557fe5b9060005260206000209060030201600001541115612424575080611f89565b60035482905b80821015612484576000612447838301600263ffffffff612bd316565b9050856003828154811061245757fe5b90600052602060002090600302016000015411156124775780915061247e565b8060010192505b5061242a565b60001901949350505050565b612498612ff4565b6001600160a01b0385168082526000906124b3908890611de6565b90508015612330576001600160a01b0380871660009081526005602090815260409182902054831690850152835190516353fa2eb760e01b81529116906353fa2eb7906125069030908b906004016135a7565b602060405180830381600087803b15801561252057600080fd5b505af1158015612534573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125589190613490565b5060408201819052602085015161257e9061271090611f7890849063ffffffff612b9916565b6060830181905260408301516125999163ffffffff6120e516565b60808301526125bc836125b2868263ffffffff6126c916565b84608001516127b4565b60a0830181905260408301516125d79163ffffffff6120e516565b60c083015260408051606081018252600180825260a0850151602080840191825283850188815260008d815260028084528782206001600160a01b038f168352909352959095209351845460ff191690151517845590519183019190915591519101556126426111fa565b6001600160a01b0316866001600160a01b0316887f42d462aded8303289cfe9efdb997119f4921308595d9db5dd7d500236d523d21856020015186604001518a6020015188606001516126a68a606001518b60c001516120e590919063ffffffff16565b6040516126b7959493929190613653565b60405180910390a45095945050505050565b6000828201838110156115465760405162461bcd60e51b815260040161025890613740565b816126f8576127ae565b6001600160a01b03841673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14156127a3576000836001600160a01b0316836040516127369061356c565b60006040518083038185875af1925050503d8060008114612773576040519150601f19603f3d011682016040523d82523d6000602084013e612778565b606091505b5050905080829061279c5760405162461bcd60e51b81526004016102589190613681565b50506127ae565b6127ae848484612c41565b50505050565b600061197183611f78868563ffffffff612b9916565b606060006127ef60016127e3858763ffffffff6120e516565b9063ffffffff6126c916565b90506060816001600160401b038111801561280957600080fd5b50604051908082528060200260200182016040528015612833578160200160208202803683370190505b5090506000855b858111612865578083838151811061284e57fe5b60209081029190910101526001918201910161283a565b50611540878360048054806020026020016040519081016040528092919081815260200182805480156128c157602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116128a3575b5050505050612c97565b60008251116128ec5760405162461bcd60e51b815260040161025890613ba1565b600081511161290d5760405162461bcd60e51b815260040161025890613abd565b606081516001600160401b038111801561292657600080fd5b50604051908082528060200260200182016040528015612950578160200160208202803683370190505b50905060005b8351811015612b0257600084828151811061296d57fe5b6020026020010151905060008090505b8451811015612af85760006129a6888488858151811061299957fe5b602002602001015161139b565b90506000600560008885815181106129ba57fe5b6020908102919091018101516001600160a01b0390811683529082019290925260400160002054169050816129f0575050612af0565b612a008287858151811061107957fe5b868481518110612a0c57fe5b6020908102919091018101919091526000858152600180835260408083206001600160a01b038e16845290935291812089519091908a9087908110612a4d57fe5b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff021916908315150217905550868381518110612a9857fe5b60200260200101516001600160a01b0316896001600160a01b0316857fd2bf01930193426d917e596a306efa79f82bfc800d1edfa31468cf0a2a7454e78486604051612ae59291906135a7565b60405180910390a450505b60010161297d565b5050600101612956565b5060005b81518110156108fa57612b9160056000858481518110612b2257fe5b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060009054906101000a90046001600160a01b031686848481518110612b6b57fe5b60200260200101516040518060600160405280602a8152602001613d5c602a91396126ee565b600101612b06565b600082612ba857506000611f89565b82820282848281612bb557fe5b04146115465760405162461bcd60e51b815260040161025890613a29565b600061154683836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250612e9f565b60008184841115612c395760405162461bcd60e51b81526004016102589190613681565b505050900390565b611b428363a9059cbb60e01b8484604051602401612c609291906135a7565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152612ed6565b606080612caf83518551612b9990919063ffffffff16565b6001600160401b0381118015612cc457600080fd5b50604051908082528060200260200182016040528015612cfe57816020015b612ceb613089565b815260200190600190039081612ce35790505b5090506000805b8551811015612e005760005b8551811015612df7576000612d4089898581518110612d2c57fe5b602002602001015189858151811061299957fe5b90508015612dee576040518060800160405280898581518110612d5f57fe5b60200260200101518152602001888481518110612d7857fe5b60200260200101516001600160a01b03168152602001828152602001600560008a8681518110612da457fe5b6020908102919091018101516001600160a01b03908116835290820192909252604001600020541690528551869086908110612ddc57fe5b60209081029190910101526001909301925b50600101612d11565b50600101612d05565b506060816001600160401b0381118015612e1957600080fd5b50604051908082528060200260200182016040528015612e5357816020015b612e40613089565b815260200190600190039081612e385790505b50905060005b82811015612e9457838181518110612e6d57fe5b6020026020010151828281518110612e8157fe5b6020908102919091010152600101612e59565b509695505050505050565b60008183612ec05760405162461bcd60e51b81526004016102589190613681565b506000838581612ecc57fe5b0495945050505050565b612ee8826001600160a01b0316612fbb565b612f045760405162461bcd60e51b815260040161025890613c22565b60006060836001600160a01b031683604051612f209190613550565b6000604051808303816000865af19150503d8060008114612f5d576040519150601f19603f3d011682016040523d82523d6000602084013e612f62565b606091505b509150915081612f845760405162461bcd60e51b815260040161025890613777565b8051156127ae5780806020019051810190612f9f9190613458565b6127ae5760405162461bcd60e51b815260040161025890613bd8565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590611971575050151592915050565b6040518060e0016040528060006001600160a01b0316815260200160006001600160a01b0316815260200160008152602001600081526020016000815260200160008152602001600081525090565b604051806060016040528060001515815260200160008152602001600081525090565b604051806060016040528060008152602001600081526020016000151581525090565b60405180608001604052806000815260200160006001600160a01b031681526020016000815260200160006001600160a01b031681525090565b60008083601f8401126130d4578182fd5b5081356001600160401b038111156130ea578182fd5b602083019150836020808302850101111561310457600080fd5b9250929050565b600082601f83011261311b578081fd5b813561312e61312982613cd1565b613cab565b81815291506020808301908481018184028601820187101561314f57600080fd5b60005b8481101561317757813561316581613d1c565b84529282019290820190600101613152565b505050505092915050565b600082601f830112613192578081fd5b81356131a061312982613cd1565b8181529150602080830190848101818402860182018710156131c157600080fd5b60005b84811015613177578135845292820192908201906001016131c4565b6000602082840312156131f1578081fd5b813561154681613d1c565b6000806040838503121561320e578081fd5b823561321981613d1c565b915060208301356001600160401b03811115613233578182fd5b61323f85828601613182565b9150509250929050565b60008060006060848603121561325d578081fd5b833561326881613d1c565b925060208401356001600160401b0380821115613283578283fd5b61328f87838801613182565b935060408601359150808211156132a4578283fd5b506132b18682870161310b565b9150509250925092565b600080604083850312156132cd578182fd5b82356132d881613d1c565b915060208301356132e881613d1c565b809150509250929050565b600080600060608486031215613307578283fd5b833561331281613d1c565b925060208401359150604084013561332981613d1c565b809150509250925092565b600080600060608486031215613348578283fd5b833561335381613d1c565b95602085013595506040909401359392505050565b6000806000806040858703121561337d578081fd5b84356001600160401b0380821115613393578283fd5b61339f888389016130c3565b909650945060208701359150808211156133b7578283fd5b506133c4878288016130c3565b95989497509550505050565b6000602082840312156133e1578081fd5b81356001600160401b038111156133f6578182fd5b61197184828501613182565b60008060408385031215613414578182fd5b82356001600160401b038082111561342a578384fd5b61343686838701613182565b9350602085013591508082111561344b578283fd5b5061323f8582860161310b565b600060208284031215613469578081fd5b81518015158114611546578182fd5b600060208284031215613489578081fd5b5035919050565b6000602082840312156134a1578081fd5b5051919050565b600080604083850312156134ba578182fd5b8235915060208301356132e881613d1c565b6000806000606084860312156134e0578081fd5b8335925060208401356134f281613d1c565b9150604084013561332981613d1c565b60008060408385031215613514578182fd5b50508035926020909101359150565b600080600060608486031215613537578081fd5b8351925060208401519150604084015161332981613d1c565b60008251613562818460208701613cf0565b9190910192915050565b90565b6001600160a01b0391909116815260200190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b03929092168252602082015260400190565b602080825282518282018190526000919060409081850190868401855b8281101561362357815180518552868101516001600160a01b039081168887015286820151878701526060918201511690850152608090930192908501906001016135dd565b5091979650505050505050565b901515815260200190565b92151583526020830191909152604082015260600190565b6001600160a01b03959095168552602085019390935260408401919091526060830152608082015260a00190565b60006020825282518060208401526136a0816040850160208701613cf0565b601f01601f19169190910160400192915050565b60208082526026908201527f6f6e6c7920616363657074204554482066726f6d2061204b796265724665654860408201526530b7323632b960d11b606082015260800190565b60208082526026908201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160408201526564647265737360d01b606082015260800190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b6020808252818101527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564604082015260600190565b60208082526037908201527f6d617374657257697468647261773a2063616e206e6f74207472616e7366657260408201527f206b6e6320746f2074686520706f6f6c206d6173746572000000000000000000606082015260800190565b602080825260409082018190527f72656d6f766546656548616e646c65723a2063616e206e6f742072656d6f7665908201527f2046656548616e646c6572207375636365737366756c6c7920636c61696d6564606082015260800190565b60208082526023908201527f63524d61737465723a205f66656548616e646c657247726f75702072657175696040820152621c995960ea1b606082015260800190565b6020808252601c908201527f61646446656548616e646c65723a20616c726561647920616464656400000000604082015260600190565b6020808252602e908201527f636f6d6d69744e65774665653a2044656c65676174696f6e204665652067726560408201526d61746572207468616e203130302560901b606082015260800190565b60208082526025908201527f61646446656548616e646c65723a205f66656548616e646c6572206973206d696040820152647373696e6760d81b606082015260800190565b60208082526027908201527f63524d61737465723a206f7264657220616e6420756e697175656e6573732072604082015266195c5d5a5c995960ca1b606082015260800190565b6020808252601b908201527f72656d6f766546656548616e646c65723a206e6f742061646465640000000000604082015260600190565b6020808252601b908201527f6d617374657257697468647261773a20616d6f756e7420697320300000000000604082015260600190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b60208082526033908201527f6d61737465724465706f7369743a20616d6f756e7420746f206465706f7369746040820152722073686f756c6420626520706f73697469766560681b606082015260800190565b60208082526023908201527f63524d656d6265723a205f66656548616e646c657247726f75702072657175696040820152621c995960ea1b606082015260800190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b6020808252818101527f6d61737465724465706f7369743a2063616e206e6f742067657420746f6b656e604082015260600190565b6020808252601e908201527f63524d61737465723a205f65706f636847726f75702072657175697265640000604082015260600190565b6020808252601e908201527f63524d656d6265723a205f65706f636847726f75702072657175697265640000604082015260600190565b6020808252602a908201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6040820152691bdd081cdd58d8d9595960b21b606082015260800190565b6020808252601f908201527f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400604082015260600190565b815181526020808301519082015260409182015115159181019190915260600190565b90815260200190565b918252602082015260400190565b92835260208301919091521515604082015260600190565b6040518181016001600160401b0381118282101715613cc957600080fd5b604052919050565b60006001600160401b03821115613ce6578081fd5b5060209081020190565b60005b83811015613d0b578181015183820152602001613cf3565b838111156127ae5750506000910152565b6001600160a01b038116811461139857600080fdfe63524d61737465723a20706f6f6c4d6173746572207368617265207472616e73666572206661696c656463524d656d6265723a20706f6f6c4d656d626572207368617265207472616e73666572206661696c6564a264697066735822122064a8ca2ec5b6b3488c9c7dd1d5256f4571d7600191dc525e4b07dc15d4290cb664736f6c63430006060033

Verified Source Code Partial Match

Compiler: v0.6.6+commit.6c089d02 EVM: istanbul Optimization: Yes (200 runs)
KyberPoolMaster.sol 1629 lines
// File: @openzeppelin/contracts/token/ERC20/IERC20.sol

pragma solidity ^0.6.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `recipient`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `sender` to `recipient` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);
}

// File: @openzeppelin/contracts/math/SafeMath.sol

pragma solidity ^0.6.0;

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");

        return c;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return sub(a, b, "SafeMath: subtraction overflow");
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        uint256 c = a - b;

        return c;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
        if (a == 0) {
            return 0;
        }

        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");

        return c;
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return div(a, b, "SafeMath: division by zero");
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        // Solidity only automatically asserts when dividing by 0
        require(b > 0, errorMessage);
        uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold

        return c;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        return mod(a, b, "SafeMath: modulo by zero");
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts with custom message when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b != 0, errorMessage);
        return a % b;
    }
}

// File: @openzeppelin/contracts/utils/Address.sol

pragma solidity ^0.6.2;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // According to EIP-1052, 0x0 is the value returned for not-yet created accounts
        // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
        // for accounts without code, i.e. `keccak256('')`
        bytes32 codehash;
        bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
        // solhint-disable-next-line no-inline-assembly
        assembly { codehash := extcodehash(account) }
        return (codehash != accountHash && codehash != 0x0);
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
        (bool success, ) = recipient.call{ value: amount }("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }
}

// File: @openzeppelin/contracts/token/ERC20/SafeERC20.sol

pragma solidity ^0.6.0;




/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    using SafeMath for uint256;
    using Address for address;

    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    function safeApprove(IERC20 token, address spender, uint256 value) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        // solhint-disable-next-line max-line-length
        require((value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 newAllowance = token.allowance(address(this), spender).add(value);
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves.

        // A Solidity high level call has three parts:
        //  1. The target address is checked to verify it contains contract code
        //  2. The call itself is made, and success asserted
        //  3. The return value is decoded, which in turn checks the size of the returned data.
        // solhint-disable-next-line max-line-length
        require(address(token).isContract(), "SafeERC20: call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = address(token).call(data);
        require(success, "SafeERC20: low-level call failed");

        if (returndata.length > 0) { // Return data is optional
            // solhint-disable-next-line max-line-length
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}

// File: @openzeppelin/contracts/GSN/Context.sol

pragma solidity ^0.6.0;

/*
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with GSN meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
contract Context {
    // Empty internal constructor, to prevent people from mistakenly deploying
    // an instance of this contract, which should be used via inheritance.
    constructor () internal { }

    function _msgSender() internal view virtual returns (address payable) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes memory) {
        this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
        return msg.data;
    }
}

// File: @openzeppelin/contracts/access/Ownable.sol

pragma solidity ^0.6.0;

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
contract Ownable is Context {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor () internal {
        address msgSender = _msgSender();
        _owner = msgSender;
        emit OwnershipTransferred(address(0), msgSender);
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(_owner == _msgSender(), "Ownable: caller is not the owner");
        _;
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        emit OwnershipTransferred(_owner, address(0));
        _owner = address(0);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        emit OwnershipTransferred(_owner, newOwner);
        _owner = newOwner;
    }
}

// File: contracts/interfaces/IEpochUtils.sol

pragma solidity 0.6.6;

interface IEpochUtils {
    function epochPeriodInSeconds() external view returns (uint256);

    function firstEpochStartTimestamp() external view returns (uint256);

    function getCurrentEpochNumber() external view returns (uint256);

    function getEpochNumber(uint256 timestamp) external view returns (uint256);
}

// File: contracts/interfaces/IKyberDao.sol

pragma solidity 0.6.6;


interface IKyberDao is IEpochUtils {
    event Voted(
        address indexed staker,
        uint256 indexed epoch,
        uint256 indexed campaignID,
        uint256 option
    );

    function getLatestNetworkFeeDataWithCache()
        external
        returns (uint256 feeInBps, uint256 expiryTimestamp);

    function getLatestBRRDataWithCache()
        external
        returns (
            uint256 burnInBps,
            uint256 rewardInBps,
            uint256 rebateInBps,
            uint256 epoch,
            uint256 expiryTimestamp
        );

    function handleWithdrawal(address staker, uint256 penaltyAmount) external;

    function vote(uint256 campaignID, uint256 option) external;

    function getLatestNetworkFeeData()
        external
        view
        returns (uint256 feeInBps, uint256 expiryTimestamp);

    function shouldBurnRewardForEpoch(uint256 epoch)
        external
        view
        returns (bool);

    /**
     * @dev  return staker's reward percentage in precision for a past epoch only
     *       fee handler should call this function when a staker wants to claim reward
     *       return 0 if staker has no votes or stakes
     */
    function getPastEpochRewardPercentageInPrecision(
        address staker,
        uint256 epoch
    ) external view returns (uint256);

    /**
     * @dev  return staker's reward percentage in precision for the current epoch
     *       reward percentage is not finalized until the current epoch is ended
     */
    function getCurrentEpochRewardPercentageInPrecision(address staker)
        external
        view
        returns (uint256);
}

// File: contracts/interfaces/IExtendedKyberDao.sol

pragma solidity 0.6.6;


interface IExtendedKyberDao is IKyberDao {
    function kncToken() external view returns (address);

    function staking() external view returns (address);

    function feeHandler() external view returns (address);
}

// File: contracts/interfaces/IKyberFeeHandler.sol

pragma solidity 0.6.6;


interface IKyberFeeHandler {
    event RewardPaid(
        address indexed staker,
        uint256 indexed epoch,
        IERC20 indexed token,
        uint256 amount
    );
    event RebatePaid(
        address indexed rebateWallet,
        IERC20 indexed token,
        uint256 amount
    );
    event PlatformFeePaid(
        address indexed platformWallet,
        IERC20 indexed token,
        uint256 amount
    );
    event KncBurned(uint256 kncTWei, IERC20 indexed token, uint256 amount);

    function handleFees(
        IERC20 token,
        address[] calldata eligibleWallets,
        uint256[] calldata rebatePercentages,
        address platformWallet,
        uint256 platformFee,
        uint256 networkFee
    ) external payable;

    function claimReserveRebate(address rebateWallet)
        external
        returns (uint256);

    function claimPlatformFee(address platformWallet)
        external
        returns (uint256);

    function claimStakerReward(address staker, uint256 epoch)
        external
        returns (uint256 amount);
}

// File: contracts/interfaces/IExtendedKyberFeeHandler.sol

pragma solidity 0.6.6;


interface IExtendedKyberFeeHandler is IKyberFeeHandler {
    function rewardsPerEpoch(uint256) external view returns (uint256);
}

// File: contracts/interfaces/IKyberStaking.sol

pragma solidity 0.6.6;


interface IKyberStaking is IEpochUtils {
    event Delegated(
        address indexed staker,
        address indexed representative,
        uint256 indexed epoch,
        bool isDelegated
    );
    event Deposited(uint256 curEpoch, address indexed staker, uint256 amount);
    event Withdraw(
        uint256 indexed curEpoch,
        address indexed staker,
        uint256 amount
    );

    function initAndReturnStakerDataForCurrentEpoch(address staker)
        external
        returns (
            uint256 stake,
            uint256 delegatedStake,
            address representative
        );

    function deposit(uint256 amount) external;

    function delegate(address dAddr) external;

    function withdraw(uint256 amount) external;

    /**
     * @notice return combine data (stake, delegatedStake, representative) of a staker
     * @dev allow to get staker data up to current epoch + 1
     */
    function getStakerData(address staker, uint256 epoch)
        external
        view
        returns (
            uint256 stake,
            uint256 delegatedStake,
            address representative
        );

    function getLatestStakerData(address staker)
        external
        view
        returns (
            uint256 stake,
            uint256 delegatedStake,
            address representative
        );

    /**
     * @notice return raw data of a staker for an epoch
     *         WARN: should be used only for initialized data
     *          if data has not been initialized, it will return all 0
     *          pool master shouldn't use this function to compute/distribute rewards of pool members
     */
    function getStakerRawData(address staker, uint256 epoch)
        external
        view
        returns (
            uint256 stake,
            uint256 delegatedStake,
            address representative
        );
}

// File: contracts/KyberPoolMaster.sol

pragma solidity 0.6.6;
pragma experimental ABIEncoderV2;








/**
 * @title Kyber PoolMaster contract
 * @author Protofire
 * @dev Contract that allows pool masters to let pool members claim their designated rewards trustlessly and update fees
 *      with sufficient notice times while maintaining full trustlessness.
 */
contract KyberPoolMaster is Ownable {
    using SafeMath for uint256;

    uint256 internal constant MINIMUM_EPOCH_NOTICE = 1;
    uint256 internal constant MAX_DELEGATION_FEE = 10000;
    uint256 internal constant PRECISION = (10**18);
    IERC20 internal constant ETH_TOKEN_ADDRESS = IERC20(
        0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE
    );

    // Number of epochs after which a change on delegationFee will be applied
    uint256 public immutable epochNotice;

    // Mapping of if staker has claimed reward for Epoch in a feeHandler
    // epoch -> member -> feeHandler -> true | false
    mapping(uint256 => mapping(address => mapping(address => bool)))
        public claimedDelegateReward;

    struct Claim {
        bool claimedByPool;
        uint256 totalRewards;
        uint256 totalStaked;
    }
    //epoch -> feeHandler -> Claim
    mapping(uint256 => mapping(address => Claim)) public epochFeeHandlerClaims;

    // Fee charged by poolMasters to poolMembers for services
    // Denominated in 1e4 units
    // 100 = 1%
    struct DFeeData {
        uint256 fromEpoch;
        uint256 fee;
        bool applied;
    }

    DFeeData[] public delegationFees;

    IERC20 public immutable kncToken;
    IExtendedKyberDao public immutable kyberDao;
    IKyberStaking public immutable kyberStaking;

    address[] public feeHandlersList;
    mapping(address => IERC20) public rewardTokenByFeeHandler;

    uint256 public immutable firstEpoch;

    mapping(address => bool) public successfulClaimByFeeHandler;

    struct RewardInfo {
        IExtendedKyberFeeHandler kyberFeeHandler;
        IERC20 rewardToken;
        uint256 totalRewards;
        uint256 totalFee;
        uint256 rewardsAfterFee;
        uint256 poolMembersShare;
        uint256 poolMasterShare;
    }

    struct UnclaimedRewardData {
        uint256 epoch;
        address feeHandler;
        uint256 rewards;
        IERC20 rewardToken;
    }

    /*** Events ***/
    event CommitNewFees(uint256 deadline, uint256 feeRate);
    event NewFees(uint256 fromEpoch, uint256 feeRate);

    event MemberClaimReward(
        uint256 indexed epoch,
        address indexed poolMember,
        address indexed feeHandler,
        IERC20 rewardToken,
        uint256 reward
    );

    event MasterClaimReward(
        uint256 indexed epoch,
        address indexed feeHandler,
        address indexed poolMaster,
        IERC20 rewardToken,
        uint256 totalRewards,
        uint256 feeApplied,
        uint256 feeAmount,
        uint256 poolMasterShare
    );

    event AddFeeHandler(address indexed feeHandler, IERC20 indexed rewardToken);

    event RemoveFeeHandler(address indexed feeHandler);

    /**
     * @notice Address deploying this contract should be able to receive ETH, owner can be changed using transferOwnership method
     * @param _kyberDao KyberDao contract address
     * @param _epochNotice Number of epochs after which a change on deledatioFee is will be applied
     * @param _delegationFee Fee charged by poolMasters to poolMembers for services - Denominated in 1e4 units - 100 = 1%
     * @param _kyberFeeHandlers Array of FeeHandlers
     * @param _rewardTokens Array of ERC20 tokens used by FeeHandlers to pay reward. Use zero address if FeeHandler pays ETH
     */
    constructor(
        address _kyberDao,
        uint256 _epochNotice,
        uint256 _delegationFee,
        address[] memory _kyberFeeHandlers,
        IERC20[] memory _rewardTokens
    ) public {
        require(_kyberDao != address(0), "ctor: kyberDao is missing");
        require(
            _epochNotice >= MINIMUM_EPOCH_NOTICE,
            "ctor: Epoch Notice too low"
        );
        require(
            _delegationFee <= MAX_DELEGATION_FEE,
            "ctor: Delegation Fee greater than 100%"
        );
        require(
            _kyberFeeHandlers.length > 0,
            "ctor: at least one _kyberFeeHandlers required"
        );
        require(
            _kyberFeeHandlers.length == _rewardTokens.length,
            "ctor: _kyberFeeHandlers and _rewardTokens uneven"
        );

        IExtendedKyberDao _kyberDaoContract = IExtendedKyberDao(_kyberDao);
        kyberDao = _kyberDaoContract;

        kncToken = IERC20(_kyberDaoContract.kncToken());
        kyberStaking = IKyberStaking(_kyberDaoContract.staking());

        epochNotice = _epochNotice;

        uint256 _firstEpoch = _kyberDaoContract.getCurrentEpochNumber();
        firstEpoch = _firstEpoch;

        delegationFees.push(DFeeData(_firstEpoch, _delegationFee, true));

        for (uint256 i = 0; i < _kyberFeeHandlers.length; i++) {
            require(
                _kyberFeeHandlers[i] != address(0),
                "ctor: feeHandler is missing"
            );
            require(
                rewardTokenByFeeHandler[_kyberFeeHandlers[i]] ==
                    IERC20(address(0)),
                "ctor: repeated feeHandler"
            );

            feeHandlersList.push(_kyberFeeHandlers[i]);
            rewardTokenByFeeHandler[_kyberFeeHandlers[i]] = _rewardTokens[i];

            emit AddFeeHandler(
                _kyberFeeHandlers[i],
                rewardTokenByFeeHandler[_kyberFeeHandlers[i]]
            );
        }

        emit CommitNewFees(_firstEpoch, _delegationFee);
        emit NewFees(_firstEpoch, _delegationFee);
    }

    /**
     * @dev adds a new FeeHandler
     * @param _feeHandler FeeHandler address
     * @param _rewardToken Rewards Token address
     */
    function addFeeHandler(address _feeHandler, IERC20 _rewardToken)
        external
        onlyOwner
    {
        require(
            _feeHandler != address(0),
            "addFeeHandler: _feeHandler is missing"
        );
        require(
            rewardTokenByFeeHandler[_feeHandler] == IERC20(address(0)),
            "addFeeHandler: already added"
        );

        feeHandlersList.push(_feeHandler);
        rewardTokenByFeeHandler[_feeHandler] = _rewardToken;

        emit AddFeeHandler(_feeHandler, rewardTokenByFeeHandler[_feeHandler]);
    }

    /**
     * @dev removes a FeeHandler
     * @param _feeHandler FeeHandler address
     */
    function removeFeeHandler(address _feeHandler) external onlyOwner {
        require(
            rewardTokenByFeeHandler[_feeHandler] != IERC20(address(0)),
            "removeFeeHandler: not added"
        );
        require(
            !successfulClaimByFeeHandler[_feeHandler],
            "removeFeeHandler: can not remove FeeHandler successfully claimed"
        );

        if (feeHandlersList[feeHandlersList.length - 1] != _feeHandler) {
            for (uint256 i = 0; i < feeHandlersList.length; i++) {
                if (feeHandlersList[i] == _feeHandler) {
                    feeHandlersList[i] = feeHandlersList[feeHandlersList
                        .length - 1];
                    break;
                }
            }
        }

        feeHandlersList.pop();
        delete rewardTokenByFeeHandler[_feeHandler];

        emit RemoveFeeHandler(_feeHandler);
    }

    /**
     * @dev call to stake more KNC for poolMaster
     * @param amount amount of KNC to stake
     */
    function masterDeposit(uint256 amount) external onlyOwner {
        require(
            amount > 0,
            "masterDeposit: amount to deposit should be positive"
        );

        require(
            kncToken.transferFrom(msg.sender, address(this), amount),
            "masterDeposit: can not get token"
        );

        // approve
        kncToken.approve(address(kyberStaking), amount);

        // deposit in KyberStaking
        kyberStaking.deposit(amount);
    }

    /**
     * @dev call to withdraw KNC from staking
     * @param amount amount of KNC to withdraw
     */
    function masterWithdraw(uint256 amount) external onlyOwner {
        require(amount > 0, "masterWithdraw: amount is 0");

        // withdraw from KyberStaking
        kyberStaking.withdraw(amount);

        // transfer KNC back to pool master
        require(
            kncToken.transfer(msg.sender, amount),
            "masterWithdraw: can not transfer knc to the pool master"
        );
    }

    /**
     * @dev  vote for an option of a campaign
     *       options are indexed from 1 to number of options
     * @param campaignID id of campaign to vote for
     * @param option id of options to vote for
     */
    function vote(uint256 campaignID, uint256 option) external onlyOwner {
        kyberDao.vote(campaignID, option);
    }

    /**
     * @dev  set a new delegation fee to be applied in current epoch + epochNotice
     * @param _fee new fee
     */
    function commitNewFee(uint256 _fee) external onlyOwner {
        require(
            _fee <= MAX_DELEGATION_FEE,
            "commitNewFee: Delegation Fee greater than 100%"
        );

        uint256 curEpoch = kyberDao.getCurrentEpochNumber();
        uint256 fromEpoch = curEpoch.add(epochNotice);

        DFeeData storage lastFee = delegationFees[delegationFees.length - 1];

        if (lastFee.fromEpoch > curEpoch) {
            lastFee.fromEpoch = fromEpoch;
            lastFee.fee = _fee;
        } else {
            if (!lastFee.applied) {
                applyFee(lastFee);
            }

            delegationFees.push(DFeeData(fromEpoch, _fee, false));
        }
        emit CommitNewFees(fromEpoch.sub(1), _fee);
    }

    /**
     * @dev Applies the pending new fee
     */
    function applyPendingFee() public {
        DFeeData storage lastFee = delegationFees[delegationFees.length - 1];
        uint256 curEpoch = kyberDao.getCurrentEpochNumber();

        if (lastFee.fromEpoch <= curEpoch && !lastFee.applied) {
            applyFee(lastFee);
        }
    }

    /**
     * @dev Applies a pending fee
     * @param fee to be applied
     */
    function applyFee(DFeeData storage fee) internal {
        fee.applied = true;
        emit NewFees(fee.fromEpoch, fee.fee);
    }

    /**
     * @dev Gets the id of the delegation fee corresponding to the given epoch
     * @param _epoch for which epoch is querying delegation fee
     * @param _from delegationFees starting index
     */
    function getEpochDFeeDataId(uint256 _epoch, uint256 _from)
        internal
        view
        returns (uint256)
    {
        if (delegationFees[_from].fromEpoch > _epoch) {
            return _from;
        }

        uint256 left = _from;
        uint256 right = delegationFees.length;

        while (left < right) {
            uint256 m = (left + right).div(2);
            if (delegationFees[m].fromEpoch > _epoch) {
                right = m;
            } else {
                left = m + 1;
            }
        }

        return right - 1;
    }

    /**
     * @dev Gets the the delegation fee data corresponding to the given epoch
     * @param epoch for which epoch is querying delegation fee
     */
    function getEpochDFeeData(uint256 epoch)
        public
        view
        returns (DFeeData memory epochDFee)
    {
        epochDFee = delegationFees[getEpochDFeeDataId(epoch, 0)];
    }

    /**
     * @dev Gets the the delegation fee data corresponding to the current epoch
     */
    function delegationFee() public view returns (DFeeData memory) {
        uint256 curEpoch = kyberDao.getCurrentEpochNumber();
        return getEpochDFeeData(curEpoch);
    }

    /**
     * @dev  Queries the amount of unclaimed rewards for the pool in a given epoch and feeHandler
     *       return 0 if PoolMaster has calledRewardMaster
     *       return 0 if staker's reward percentage in precision for the epoch is 0
     *       return 0 if total reward for the epoch is 0
     * @param _epoch for which epoch is querying unclaimed reward
     * @param _feeHandler FeeHandler address
     */
    function getUnclaimedRewards(
        uint256 _epoch,
        IExtendedKyberFeeHandler _feeHandler
    ) public view returns (uint256) {
        if (epochFeeHandlerClaims[_epoch][address(_feeHandler)].claimedByPool) {
            return 0;
        }

        uint256 perInPrecision = kyberDao
            .getPastEpochRewardPercentageInPrecision(address(this), _epoch);
        if (perInPrecision == 0) {
            return 0;
        }

        uint256 rewardsPerEpoch = _feeHandler.rewardsPerEpoch(_epoch);
        if (rewardsPerEpoch == 0) {
            return 0;
        }

        return rewardsPerEpoch.mul(perInPrecision).div(PRECISION);
    }

    /**
     * @dev Returns data related to all epochs and feeHandlers with unclaimed rewards, for the pool.
     */
    function getUnclaimedRewardsData()
        external
        view
        returns (UnclaimedRewardData[] memory)
    {
        uint256 currentEpoch = kyberDao.getCurrentEpochNumber();
        uint256 maxEpochNumber = currentEpoch.sub(firstEpoch);
        uint256[] memory epochGroup = new uint256[](maxEpochNumber);
        uint256 e = 0;
        for (uint256 epoch = firstEpoch; epoch < currentEpoch; epoch++) {
            epochGroup[e] = epoch;
            e++;
        }

        return _getUnclaimedRewardsData(epochGroup, feeHandlersList);
    }

    /**
     * @dev Returns data related to all epochs and feeHandlers, from the given groups, with unclaimed rewards, for the pool.
     */
    function getUnclaimedRewardsData(
        uint256[] calldata _epochGroup,
        address[] calldata _feeHandlerGroup
    ) external view returns (UnclaimedRewardData[] memory) {
        return _getUnclaimedRewardsData(_epochGroup, _feeHandlerGroup);
    }

    function _getUnclaimedRewardsData(
        uint256[] memory _epochGroup,
        address[] memory _feeHandlerGroup
    ) internal view returns (UnclaimedRewardData[] memory) {

            UnclaimedRewardData[] memory epochFeeHanlderRewards
         = new UnclaimedRewardData[](
            _epochGroup.length.mul(_feeHandlerGroup.length)
        );
        uint256 rewardsCounter = 0;
        for (uint256 e = 0; e < _epochGroup.length; e++) {
            for (uint256 f = 0; f < _feeHandlerGroup.length; f++) {
                uint256 unclaimed = getUnclaimedRewards(
                    _epochGroup[e],
                    IExtendedKyberFeeHandler(_feeHandlerGroup[f])
                );

                if (unclaimed > 0) {
                    epochFeeHanlderRewards[rewardsCounter] = UnclaimedRewardData(
                        _epochGroup[e],
                        _feeHandlerGroup[f],
                        unclaimed,
                        rewardTokenByFeeHandler[_feeHandlerGroup[f]]
                    );
                    rewardsCounter++;
                }
            }
        }

        UnclaimedRewardData[] memory result = new UnclaimedRewardData[](
            rewardsCounter
        );
        for (uint256 i = 0; i < (rewardsCounter); i++) {
            result[i] = epochFeeHanlderRewards[i];
        }

        return result;
    }

    /**
     * @dev  Claims rewards for a given group of epochs in all feeHandlers, distribute fees and its share to poolMaster
     * @param _epochGroup An array of epochs for which rewards are being claimed. Asc order and uniqueness is required.
     */
    function claimRewardsMaster(uint256[] memory _epochGroup) public {
        claimRewardsMaster(_epochGroup, feeHandlersList);
    }

    /**
     * @dev  Claims rewards for a given group of epochs and a given group of feeHandlers, distribute fees and its share to poolMaster
     * @param _epochGroup An array of epochs for which rewards are being claimed. Asc order and uniqueness is required.
     * @param _feeHandlerGroup An array of FeeHandlers for which rewards are being claimed.
     */
    function claimRewardsMaster(
        uint256[] memory _epochGroup,
        address[] memory _feeHandlerGroup
    ) public {
        require(_epochGroup.length > 0, "cRMaster: _epochGroup required");
        require(
            isOrderedSet(_epochGroup),
            "cRMaster: order and uniqueness required"
        );
        require(
            _feeHandlerGroup.length > 0,
            "cRMaster: _feeHandlerGroup required"
        );

        uint256[] memory accruedByFeeHandler = new uint256[](
            _feeHandlerGroup.length
        );

        uint256 feeId = 0;

        for (uint256 j = 0; j < _epochGroup.length; j++) {
            uint256 _epoch = _epochGroup[j];
            feeId = getEpochDFeeDataId(_epoch, feeId);
            DFeeData storage epochDFee = delegationFees[feeId];

            if (!epochDFee.applied) {
                applyFee(epochDFee);
            }

            (uint256 stake, uint256 delegatedStake, ) = kyberStaking
                .getStakerRawData(address(this), _epoch);

            for (uint256 i = 0; i < _feeHandlerGroup.length; i++) {
                RewardInfo memory rewardInfo = _claimRewardsFromKyber(
                    _epoch,
                    _feeHandlerGroup[i],
                    epochDFee,
                    stake,
                    delegatedStake
                );

                if (rewardInfo.totalRewards == 0) {
                    continue;
                }

                accruedByFeeHandler[i] = accruedByFeeHandler[i].add(
                    rewardInfo.poolMasterShare
                );

                if (!successfulClaimByFeeHandler[_feeHandlerGroup[i]]) {
                    successfulClaimByFeeHandler[_feeHandlerGroup[i]] = true;
                }
            }
        }

        address poolMaster = owner();
        for (uint256 k = 0; k < accruedByFeeHandler.length; k++) {
            _sendTokens(
                rewardTokenByFeeHandler[_feeHandlerGroup[k]],
                poolMaster,
                accruedByFeeHandler[k],
                "cRMaster: poolMaster share transfer failed"
            );
        }
    }

    function _claimRewardsFromKyber(
        uint256 _epoch,
        address _feeHandlerAddress,
        DFeeData memory epochDFee,
        uint256 stake,
        uint256 delegatedStake
    ) internal returns (RewardInfo memory rewardInfo) {
        rewardInfo.kyberFeeHandler = IExtendedKyberFeeHandler(
            _feeHandlerAddress
        );
        uint256 unclaimed = getUnclaimedRewards(
            _epoch,
            rewardInfo.kyberFeeHandler
        );

        if (unclaimed > 0) {
            rewardInfo
                .rewardToken = rewardTokenByFeeHandler[_feeHandlerAddress];

            rewardInfo.kyberFeeHandler.claimStakerReward(address(this), _epoch);

            rewardInfo.totalRewards = unclaimed;

            rewardInfo.totalFee = rewardInfo
                .totalRewards
                .mul(epochDFee.fee)
                .div(MAX_DELEGATION_FEE);
            rewardInfo.rewardsAfterFee = rewardInfo.totalRewards.sub(
                rewardInfo.totalFee
            );

            rewardInfo.poolMembersShare = calculateRewardsShare(
                delegatedStake,
                stake.add(delegatedStake),
                rewardInfo.rewardsAfterFee
            );
            rewardInfo.poolMasterShare = rewardInfo.totalRewards.sub(
                rewardInfo.poolMembersShare
            ); // fee + poolMaster stake share

            epochFeeHandlerClaims[_epoch][_feeHandlerAddress] = Claim(
                true,
                rewardInfo.poolMembersShare,
                delegatedStake
            );

            emit MasterClaimReward(
                _epoch,
                _feeHandlerAddress,
                payable(owner()),
                rewardInfo.rewardToken,
                rewardInfo.totalRewards,
                epochDFee.fee,
                rewardInfo.totalFee,
                rewardInfo.poolMasterShare.sub(rewardInfo.totalFee)
            );
        }
    }

    /**
     * @dev  Helper method to transfer tokens
     * @param _token address of the token
     * @param _receiver account that will receive the transfer
     * @param _value the amount of tokens to transfer
     * @param _errorMsg error msg in case transfer of native tokens fails
     */
    function _sendTokens(
        IERC20 _token,
        address _receiver,
        uint256 _value,
        string memory _errorMsg
    ) internal {
        if (_value == 0) {
            return;
        }

        if (_token == ETH_TOKEN_ADDRESS) {
            (bool success, ) = _receiver.call{value: _value}("");
            require(success, _errorMsg);
        } else {
            SafeERC20.safeTransfer(_token, _receiver, _value);
        }
    }

    /**
     * @dev  Queries the amount of unclaimed rewards for the pool member in a given epoch and feeHandler
     *       return 0 if PoolMaster has not called claimRewardMaster
     *       return 0 if PoolMember has previously claimed reward for the epoch
     *       return 0 if PoolMember has not stake for the epoch
     *       return 0 if PoolMember has not delegated it stake to this contract for the epoch
     * @param _poolMember address of pool member
     * @param _epoch for which epoch the member is querying unclaimed reward
     * @param _feeHandler FeeHandler address
     */
    function getUnclaimedRewardsMember(
        address _poolMember,
        uint256 _epoch,
        address _feeHandler
    ) public view returns (uint256) {
        if (
            !epochFeeHandlerClaims[_epoch][address(_feeHandler)].claimedByPool
        ) {
            return 0;
        }

        if (claimedDelegateReward[_epoch][_poolMember][_feeHandler]) {
            return 0;
        }

        (uint256 stake, , address representative) = kyberStaking.getStakerData(
            _poolMember,
            _epoch
        );

        if (stake == 0) {
            return 0;
        }

        if (representative != address(this)) {
            return 0;
        }


            Claim memory rewardForEpoch
         = epochFeeHandlerClaims[_epoch][_feeHandler];

        return
            calculateRewardsShare(
                stake,
                rewardForEpoch.totalStaked,
                rewardForEpoch.totalRewards
            );
    }

    /**
     * @dev  Returns data related to all epochs and feeHandlers with unclaimed rewards, for a the poolMember. From initial to current epoch.
     * @param _poolMember address of pool member
     */
    function getAllUnclaimedRewardsDataMember(address _poolMember)
        external
        view
        returns (UnclaimedRewardData[] memory)
    {
        uint256 currentEpoch = kyberDao.getCurrentEpochNumber();
        return
            _getAllUnclaimedRewardsDataMember(
                _poolMember,
                firstEpoch,
                currentEpoch
            );
    }

    /**
     * @dev Returns data related to all epochs and feeHandlers with unclaimed rewards, for a the poolMember.
     * @param _poolMember address of pool member
     * @param _fromEpoch initial epoch parameter
     * @param _toEpoch end epoch parameter
     */
    function getAllUnclaimedRewardsDataMember(
        address _poolMember,
        uint256 _fromEpoch,
        uint256 _toEpoch
    ) external view returns (UnclaimedRewardData[] memory) {
        return
            _getAllUnclaimedRewardsDataMember(
                _poolMember,
                _fromEpoch,
                _toEpoch
            );
    }

    /**
     * @dev Queries data related to epochs and feeHandlers with unclaimed rewards, for a the poolMember
     * @param _poolMember address of pool member
     * @param _fromEpoch initial epoch parameter
     * @param _toEpoch end epoch parameter
     */
    function _getAllUnclaimedRewardsDataMember(
        address _poolMember,
        uint256 _fromEpoch,
        uint256 _toEpoch
    ) internal view returns (UnclaimedRewardData[] memory) {
        uint256 maxEpochNumber = _toEpoch.sub(_fromEpoch).add(1);
        uint256[] memory epochGroup = new uint256[](maxEpochNumber);
        uint256 e = 0;
        for (uint256 epoch = _fromEpoch; epoch <= _toEpoch; epoch++) {
            epochGroup[e] = epoch;
            e++;
        }

        return
            _getUnclaimedRewardsDataMember(
                _poolMember,
                epochGroup,
                feeHandlersList
            );
    }

    function _getUnclaimedRewardsDataMember(
        address _poolMember,
        uint256[] memory _epochGroup,
        address[] memory _feeHandlerGroup
    ) internal view returns (UnclaimedRewardData[] memory) {

            UnclaimedRewardData[] memory epochFeeHanlderRewards
         = new UnclaimedRewardData[](
            _epochGroup.length.mul(_feeHandlerGroup.length)
        );

        uint256 rewardsCounter = 0;
        for (uint256 e = 0; e < _epochGroup.length; e++) {
            for (uint256 f = 0; f < _feeHandlerGroup.length; f++) {
                uint256 unclaimed = getUnclaimedRewardsMember(
                    _poolMember,
                    _epochGroup[e],
...

// [truncated — 55767 bytes total]

Read Contract

claimedDelegateReward 0xc92d7169 → bool
delegationFee 0xc5f0a58f → tuple
delegationFees 0x29f6ff41 → uint256, uint256, bool
delegationFeesLength 0xc08da7a1 → uint256
epochFeeHandlerClaims 0xde37b7a1 → bool, uint256, uint256
epochNotice 0xba2d373c → uint256
feeHandlersList 0xb0cd498b → address
feeHandlersListLength 0x4edd0d67 → uint256
firstEpoch 0x41682744 → uint256
getAllUnclaimedRewardsDataMember 0xb8a4aeaf → tuple[]
getAllUnclaimedRewardsDataMember 0xc5e6e357 → tuple[]
getEpochDFeeData 0xb3e9ba27 → tuple
getUnclaimedRewards 0xdec36554 → uint256
getUnclaimedRewardsData 0x22b143fb → tuple[]
getUnclaimedRewardsData 0xe25208e3 → tuple[]
getUnclaimedRewardsMember 0x9e3853ec → uint256
kncToken 0x811c7fe2 → address
kyberDao 0x4d8f5105 → address
kyberStaking 0xf0359d1b → address
owner 0x8da5cb5b → address
rewardTokenByFeeHandler 0x413f92c0 → address
successfulClaimByFeeHandler 0x09f67b3a → bool

Write Contract 13 functions

These functions modify contract state and require a wallet transaction to execute.

addFeeHandler 0x7ee1506d
address _feeHandler
address _rewardToken
applyPendingFee 0x35f8aa9b
No parameters
claimRewardsMaster 0x8769e324
uint256[] _epochGroup
address[] _feeHandlerGroup
claimRewardsMaster 0xa969b186
uint256[] _epochGroup
claimRewardsMember 0xd172d3a3
address _poolMember
uint256[] _epochGroup
address[] _feeHandlerGroup
claimRewardsMember 0xd4b94901
address _poolMember
uint256[] _epochGroup
commitNewFee 0x9faf1d51
uint256 _fee
masterDeposit 0x02662585
uint256 amount
masterWithdraw 0x9d21ce9c
uint256 amount
removeFeeHandler 0xd2f31c39
address _feeHandler
renounceOwnership 0x715018a6
No parameters
transferOwnership 0xf2fde38b
address newOwner
vote 0xb384abef
uint256 campaignID
uint256 option

Recent Transactions

No transactions found for this address