Address Contract Partially Verified
Address
0x49dAeD112eA68c6dCC3Ffce8Aad355760263e1fe
Balance
0 ETH
Nonce
1
Code Size
23905 bytes
Creator
0x724b7402...BEF3 at tx 0x32ed3c5c...e6f36d
Indexed Transactions
0
Contract Bytecode
23905 bytes
0x608060405234801561000f575f80fd5b506004361061034c575f3560e01c806301ffc9a71461035057806306fdde0314610378578063095ea7b31461038d5780630d7abc33146103a05780630f2b2639146103b857806318160ddd146103cd5780631e7ff8f6146103d5578063228d71a9146103f657806323b872dd14610409578063248a9ca31461041c578063253d17351461042f5780632d08265a1461044f5780632f2ff15d14610462578063309756fb14610475578063313ce5671461048957806336568abe1461049e578063389ed267146104b157806339509351146104c55780633b573c4a146104d85780633f4ba83a146104eb5780634162169f146104f35780634cfeb862146105145780634e91f81114610527578063509c5df61461053a57806352349b17146105445780635512e5921461054e57806357b2acbd146105615780635c975abb146105745780635f5658151461057f57806363c2a36a14610592578063676e5550146105a55780636c7ac9d8146105b85780636f4a2cd0146105cc57806370a08231146105d45780637542ff95146105fc5780637682c9021461060f5780637e978af8146106225780638456cb591461062a578063848f151314610632578063851a2844146106455780638523c175146106735780638c1d4082146106865780638dd1480214610699578063916b9eba146106ac57806391d14854146106b4578063953a2f53146106c757806395d89b41146106db578063964a7596146106e35780639a3cac6a1461071d5780639faa7cfd14610730578063a217fddf14610743578063a24529471461074a578063a457c2d714610754578063a9059cbb14610767578063ac7237071461077a578063afd290a71461078d578063b0e21e8a14610795578063b226dc96146107a3578063b35e9aae146107ab578063b3bc19e0146107e7578063b5bfddea146107f1578063c30b47d714610805578063c697d2c714610818578063c75e78321461082b578063c89e43611461083e578063d280f14f14610846578063d547741f1461084e578063dd62ed3e14610861578063e5a3a14714610874578063e78cea9214610887578063e8f8708f1461089b578063e9c26518146108ae578063f5e95acb146108c2578063fc0c546a146108d5575b5f80fd5b61036361035e36600461503f565b6108e8565b60405190151581526020015b60405180910390f35b61038061091e565b60405161036f9190615066565b61036361039b3660046150af565b6109ae565b6103aa6101075481565b60405190815260200161036f565b6103cb6103c63660046150d9565b6109c5565b005b6035546103aa565b6103e86103e33660046150d9565b610a27565b60405161036f9291906150f4565b6103cb6104043660046150d9565b610a9c565b610363610417366004615102565b610b3b565b6103aa61042a366004615140565b610b60565b61044261043d366004615140565b610b74565b60405161036f9190615157565b6103cb61045d3660046151c3565b610c0e565b6103cb610470366004615231565b610d9f565b6103aa5f80516020615ccc83398151915281565b60125b60405160ff909116815260200161036f565b6103cb6104ac366004615231565b610dbc565b6103aa5f80516020615d0c83398151915281565b6103636104d33660046150af565b610e3a565b6103cb6104e6366004615140565b610e78565b6103cb610ed8565b61010354610507906001600160a01b031681565b60405161036f919061525f565b6103cb610522366004615140565b610efb565b6103cb610535366004615288565b6112a3565b6103aa6101095481565b6103aa6101065481565b6103aa61055c3660046152ae565b611362565b6103cb61056f3660046150d9565b61151c565b60c95460ff16610363565b6103aa61058d366004615140565b611587565b6103cb6105a03660046150d9565b61167d565b6103aa6105b33660046150d9565b6116e1565b61010054610507906001600160a01b031681565b6103cb61174e565b6103aa6105e23660046150d9565b6001600160a01b03165f9081526033602052604090205490565b60fd54610507906001600160a01b031681565b6103cb61061d366004615140565b611dbb565b6103aa611e07565b6103cb611ed3565b6103cb6106403660046150d9565b611ef3565b610658610653366004615140565b611f7c565b6040805193845260208401929092529082015260600161036f565b610658610681366004615140565b611fa6565b6103cb610694366004615140565b611fd2565b6103cb6106a73660046150d9565b612073565b6104426120d7565b6103636106c2366004615231565b612160565b61010254610507906001600160a01b031681565b61038061218a565b6101045461070d9060ff808216916101008104821691620100008204811691630100000090041684565b60405161036f94939291906152ed565b6103cb61072b3660046150d9565b612199565b6103cb61073e366004615312565b612205565b6103aa5f81565b6103aa6101085481565b6103636107623660046150af565b612307565b6103636107753660046150af565b6123a3565b60ff54610507906001600160a01b031681565b6103aa6123b0565b61010c5461048c9060ff1681565b6103aa61243e565b6107be6107b9366004615140565b612459565b604080519485526020850193909352918301526001600160a01b0316606082015260800161036f565b6103aa6101055481565b6103aa5f80516020615cec83398151915281565b60fe54610507906001600160a01b031681565b6107be610826366004615363565b61249b565b6103cb6108393660046150d9565b6124e7565b6103cb6125b8565b6103cb61284b565b6103cb61085c366004615231565b6129e0565b6103aa61086f366004615383565b6129fd565b6103aa6108823660046153af565b612a27565b61010154610507906001600160a01b031681565b60fc54610507906001600160a01b031681565b6103aa5f80516020615c8c83398151915281565b6103cb6108d03660046153da565b612d5d565b60fb54610507906001600160a01b031681565b5f6001600160e01b03198216637965db0b60e01b148061091857506301ffc9a760e01b6001600160e01b03198316145b92915050565b60606036805461092d90615490565b80601f016020809104026020016040519081016040528092919081815260200182805461095990615490565b80156109a45780601f1061097b576101008083540402835291602001916109a4565b820191905f5260205f20905b81548152906001019060200180831161098757829003601f168201915b5050505050905090565b5f336109bb818585612fd1565b5060019392505050565b5f80516020615c8c8339815191526109dd81336130f4565b60fc80546001600160a01b0319166001600160a01b0384169081179091556040517fb8e1a40638c48c0ebe9679e0b5b032f2066cf44139d775cc09c945b5df070c4e905f90a25050565b5f80826001600160a01b0316631e7ff8f6306040518263ffffffff1660e01b8152600401610a55919061525f565b6040805180830381865afa158015610a6f573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a9391906154c2565b91509150915091565b5f80516020615c8c833981519152610ab481336130f4565b6001600160a01b038216610ae35760405162461bcd60e51b8152600401610ada906154e4565b60405180910390fd5b61010080546001600160a01b0319166001600160a01b0384161790556040517f9bd13a2a464ceec711278c0b605c5e1f465328005dc4ee6076dae3f271de202e90610b2f90849061525f565b60405180910390a15050565b5f33610b48858285613158565b610b538585856131d0565b60019150505b9392505050565b5f9081526097602052604090206001015490565b606061010b5f8381526020019081526020015f20805480602002602001604051908101604052809291908181526020015f905b82821015610c03575f84815260209081902060408051608081018252600486029092018054835260018082015484860152600282015492840192909252600301546001600160a01b031660608301529083529092019101610ba7565b505050509050919050565b60c95460ff1615610c315760405162461bcd60e51b8152600401610ada90615515565b5f5b81811015610d9a5760fe546001600160a01b031663430c208133858585818110610c5f57610c5f61553f565b905060200201356040518363ffffffff1660e01b8152600401610c83929190615553565b602060405180830381865afa158015610c9e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610cc2919061556c565b610cfa5760405162461bcd60e51b81526020600482015260096024820152682737ba1037bbb732b960b91b6044820152606401610ada565b61010b5f848484818110610d1057610d1061553f565b9050602002013581526020019081526020015f20805490505f14610d5457610d4f838383818110610d4357610d4361553f565b90506020020135613389565b610d92565b60405162461bcd60e51b815260206004820152601360248201527224b73b30b634b21031b630b4b6903a37b5b2b760691b6044820152606401610ada565b600101610c33565b505050565b610da882610b60565b610db281336130f4565b610d9a8383613772565b6001600160a01b0381163314610e2c5760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b6064820152608401610ada565b610e3682826137f7565b5050565b335f8181526034602090815260408083206001600160a01b03871684529091528120549091906109bb9082908690610e7390879061559b565b612fd1565b5f80516020615c8c833981519152610e9081336130f4565b6101088054908390556040517fbf99ce7c5a72f4c7135bb72a36193d147a37a54bfcf63ec29505b5e6d5e2921d90610ecb90839086906150f4565b60405180910390a1505050565b5f80516020615ccc833981519152610ef081336130f4565b610ef861385d565b50565b60c95460ff1615610f1e5760405162461bcd60e51b8152600401610ada90615515565b610f266138ea565b600261010d5561010a54808210610f6f5760405162461bcd60e51b815260206004820152600d60248201526c0d2dcecc2d8d2c840d2dcc8caf609b1b6044820152606401610ada565b5f61010a8381548110610f8457610f8461553f565b5f9182526020918290206040805160808101825260049384029092018054835260018101548386015260028101548383018190526003909101546001600160a01b03908116606085015260fd54835163900cf0cf60e01b81529351949750919591169363900cf0cf93838201939091908290030181865afa15801561100b573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061102f91906155ae565b101561104d5760405162461bcd60e51b8152600401610ada906155c5565b60fb546040516370a0823160e01b81525f916001600160a01b0316906370a082319061107d90309060040161525f565b602060405180830381865afa158015611098573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110bc91906155ae565b90506110d08260600151836020015161393f565b60fb546040516370a0823160e01b81525f9183916001600160a01b03909116906370a082319061110490309060040161525f565b602060405180830381865afa15801561111f573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061114391906155ae565b61114d91906155f4565b9050806101065f828254611161919061559b565b9091555061117290506001856155f4565b8514158015611182575083600114155b156112135761010a6111956001866155f4565b815481106111a5576111a561553f565b905f5260205f20906004020161010a86815481106111c5576111c561553f565b5f918252602090912082546004909202019081556001808301549082015560028083015490820155600391820154910180546001600160a01b0319166001600160a01b039092169190911790555b61010a80548061122557611225615607565b5f8281526020812060045f1990930192830201818155600181018290556002810182905560030180546001600160a01b03191690559155606084015160405183926001600160a01b0392909216917f4c42a3bec298a4d82d41b7a540d8ebc22d91ee8a61459bce23849ff470d31dea91a35050600161010d55505050565b5f80516020615c8c8339815191526112bb81336130f4565b5f8260ff161180156112d1575060648260ff1611155b6113135760405162461bcd60e51b8152602060048201526013602482015272496e76616c69642070726f74636f6c2066656560681b6044820152606401610ada565b61010c805460ff84811660ff1983168117909355604080519190921680825260208201939093527f6b1719571aee7af62357ac4d4c98cc35155a52a5fcf0c09198874443c0fe430d9101610ecb565b5f61136f60c95460ff1690565b1561138c5760405162461bcd60e51b8152600401610ada90615515565b6113946138ea565b600261010d55836113b75760405162461bcd60e51b8152600401610ada9061561b565b60fb546113cf906001600160a01b0316333087613998565b5f6113d985611f7c565b505090505f81116114185760405162461bcd60e51b81526020600482015260096024820152684d696e74205a45524f60b81b6044820152606401610ada565b82156114a65761142830826139f0565b610101546114419030906001600160a01b031683612fd1565b6101015460405163197a0edf60e31b81526001600160a01b039091169063cbd076f8906114749087908590600401615553565b5f604051808303815f87803b15801561148b575f80fd5b505af115801561149d573d5f803e3d5ffd5b505050506114b0565b6114b084826139f0565b846101065f8282546114c2919061559b565b90915550506040805186815284151560208201526001600160a01b0386169133917f1269134ce636cffdcd6973a66ab4f9246bf6e1f1b64479c8cabd893aac6b7514910160405180910390a3600161010d55949350505050565b5f80516020615c8c83398151915261153481336130f4565b60fe80546001600160a01b038481166001600160a01b03198316179092556040519116907fbad9e31f77110bb6f7a649c7263210f1d20b87084c6df2799e0f736879de106290610ecb9083908690615643565b5f81815261010b602052604081205415611676575f82815261010b6020908152604080832080548251818502810185019093528083529192909190849084015b82821015611623575f84815260209081902060408051608081018252600486029092018054835260018082015484860152600282015492840192909252600301546001600160a01b0316606083015290835290920191016115c7565b5050505090505f805f90505b825181101561166e5761165a83828151811061164d5761164d61553f565b6020026020010151613ab9565b611664908361559b565b915060010161162f565b509392505050565b505f919050565b5f80516020615c8c83398151915261169581336130f4565b61010280546001600160a01b0319166001600160a01b0384161790556040517f05500b91006845ebc8df439a628a3c0a94ba8b3a63f65d2e4ce3a6fb3e29d9c990610b2f90849061525f565b604051630676e55560e41b81525f906001600160a01b0383169063676e55509061170f90309060040161525f565b602060405180830381865afa15801561172a573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061091891906155ae565b60c95460ff16156117715760405162461bcd60e51b8152600401610ada90615515565b6117796138ea565b600261010d555f61178861243e565b90505f60fc5f9054906101000a90046001600160a01b03166001600160a01b031663a33538596040518163ffffffff1660e01b81526004015f60405180830381865afa1580156117da573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526118019190810190615787565b80519091505f5b81811015611963575f8382815181106118235761182361553f565b60200260200101515f015190505f816001600160a01b031663676e5550306040518263ffffffff1660e01b815260040161185d919061525f565b602060405180830381865afa158015611878573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061189c91906155ae565b90505f826001600160a01b0316639b2cb5d86040518163ffffffff1660e01b8152600401602060405180830381865afa1580156118db573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118ff91906155ae565b90508082111561195857826001600160a01b031663c7b8981c6040518163ffffffff1660e01b81526004015f604051808303815f87803b158015611941575f80fd5b505af1158015611953573d5f803e3d5ffd5b505050505b505050600101611808565b506101065460fb546040516370a0823160e01b81525f92916001600160a01b0316906370a082319061199990309060040161525f565b602060405180830381865afa1580156119b4573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119d891906155ae565b6119e291906155f4565b61010c549091505f906064906119fb9060ff16846157b8565b611a0591906157cf565b9050610108548111611a695760405162461bcd60e51b815260206004820152602760248201527f416d6f756e7420746f2064697374726962757465206c6f776572207468616e206044820152666d696e696d756d60c81b6064820152608401610ada565b60fb546040516370a0823160e01b81525f916001600160a01b0316906370a0823190611a9990309060040161525f565b602060405180830381865afa158015611ab4573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ad891906155ae565b610104549091505f90606490611af19060ff16856157b8565b611afb91906157cf565b610104549091505f90606490611b1a9062010000900460ff16866157b8565b611b2491906157cf565b610104549091505f90606490611b44906301000000900460ff16876157b8565b611b4e91906157cf565b610104549091505f90606490611b6c90610100900460ff16886157b8565b611b7691906157cf565b90505f611b8389836157cf565b6101035460fb54919250611ba4916001600160a01b03908116911687613c3f565b60ff5460fb54611bc1916001600160a01b03918216911686613c3f565b60fb546101005460405163095ea7b360e01b81526001600160a01b039283169263095ea7b392611bf8929116908790600401615553565b6020604051808303815f875af1158015611c14573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611c38919061556c565b506101005460fb5461010254604051638b9e4f9360e01b81526001600160a01b0393841693638b9e4f9393611c78939082169291169088906004016157ee565b5f604051808303815f87803b158015611c8f575f80fd5b505af1158015611ca1573d5f803e3d5ffd5b505050505f5b89811015611ced57611ce58b8281518110611cc457611cc461553f565b602090810291909101810151015160fb546001600160a01b03169084613c3f565b600101611ca7565b5060fb546040516370a0823160e01b81525f916001600160a01b0316906370a0823190611d1e90309060040161525f565b602060405180830381865afa158015611d39573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611d5d91906155ae565b90505f611d6a82896155f4565b6101068390559050611d7a61243e565b6040518e9083907f34c80d224e6055b3362d4601ac3744c3a95f5b2e57c6837eb3b254ec99a043f1905f90a45050600161010d555050505050505050505050565b5f80516020615c8c833981519152611dd381336130f4565b61010782905560405182907f1cabc2f7b706218bb8613769cd658789cd6f1860310413b841020a2c7b7a0e32905f90a25050565b5f805f60fc5f9054906101000a90046001600160a01b03166001600160a01b0316630926efe46040518163ffffffff1660e01b81526004015f60405180830381865afa158015611e59573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052611e809190810190615787565b90505f5b8151811015611ecb575f611eb3838381518110611ea357611ea361553f565b60200260200101515f0151610a27565b509050611ec0818561559b565b935050600101611e84565b509092915050565b5f80516020615d0c833981519152611eeb81336130f4565b610ef8613c5e565b5f80516020615c8c833981519152611f0b81336130f4565b6001600160a01b038216611f315760405162461bcd60e51b8152600401610ada906154e4565b60ff80546001600160a01b0319166001600160a01b0384161790556040517f6726f33c09f112dfafea8225d11c58e7d600be7941768b9cc75ceecd33a9eea390610b2f90849061525f565b5f805f611f8860355490565b9150611f9261243e565b9050611f9e8482613cb6565b949193509150565b5f805f611fb260355490565b91505f611fbd61243e565b9050611fc98582613d04565b95929450925050565b5f80516020615c8c833981519152611fea81336130f4565b60648211156120385760405162461bcd60e51b815260206004820152601a60248201527904665652070657263656e746167652065786365656473203130360341b6044820152606401610ada565b6101058054908390556040517fac61f8429419f4eb22bff37f03260acc3706b74b0b4895c18940db182a45e32990610ecb90839086906150f4565b5f80516020615c8c83398151915261208b81336130f4565b61010180546001600160a01b0319166001600160a01b0384161790556040517fe605ac02ea219003ec58fc9cf4d4b3c5f2d62ec39807b1c63886ddd47a6fcd6e90610b2f90849061525f565b606061010a805480602002602001604051908101604052809291908181526020015f905b82821015612157575f84815260209081902060408051608081018252600486029092018054835260018082015484860152600282015492840192909252600301546001600160a01b0316606083015290835290920191016120fb565b50505050905090565b5f9182526097602090815260408084206001600160a01b0393909316845291905290205460ff1690565b60606037805461092d90615490565b5f80516020615c8c8339815191526121b181336130f4565b61010380546001600160a01b038481166001600160a01b03198316179092556040519116907f3b8dbc80bf27331221431f1c8b2c6fe358eadfdb3c3d7085e6a2521eeb775b0790610ecb9083908690615643565b5f80516020615c8c83398151915261221d81336130f4565b81836122298688615812565b6122339190615812565b61223d9190615812565b60ff1660641461227f5760405162461bcd60e51b815260206004820152600d60248201526c073756d2866656529213d31303609c1b6044820152606401610ada565b610104805460ff87811661ffff1990921691909117610100878316021763ffff00001916620100008683160263ff0000001916176301000000918516919091021790556040517f747eaccb30a9769474f1620ae0dd833b1ffb89520dcac6833b33df942b7c0c49906122f89087908790879087906152ed565b60405180910390a15050505050565b335f8181526034602090815260408083206001600160a01b03871684529091528120549091908381101561238b5760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b6064820152608401610ada565b6123988286868403612fd1565b506001949350505050565b5f336109bb8185856131d0565b61010a545f90815b818110156124395761242561010a82815481106123d7576123d761553f565b5f918252602091829020604080516080810182526004909302909101805483526001810154938301939093526002830154908201526003909101546001600160a01b03166060820152613ab9565b61242f908461559b565b92506001016123b8565b505090565b5f80612448611e07565b905061245381613d3f565b91505090565b61010a8181548110612469575f80fd5b5f918252602090912060049091020180546001820154600283015460039093015491935091906001600160a01b031684565b61010b602052815f5260405f2081815481106124b5575f80fd5b5f918252602090912060049091020180546001820154600283015460039093015491945092506001600160a01b031684565b6124ef6138ea565b600261010d5560fc546001600160a01b031633146125455760405162461bcd60e51b81526020600482015260136024820152722737ba1030903737b2329037b832b930ba37b960691b6044820152606401610ada565b5f61254f82610a27565b5090505f61255d8383613d6e565b9050805f0361256d5750506125af565b6125778383613e23565b60405182906001600160a01b038516907f65fcdf1cdc99352d178d6d953d52e01307cde7a592027b09c9e1d9ac8eb09ab7905f90a350505b50600161010d55565b60c95460ff16156125db5760405162461bcd60e51b8152600401610ada90615515565b6125e36138ea565b600261010d5561010654610109546101075461260090829061559b565b821161265c5760405162461bcd60e51b815260206004820152602560248201527f416d6f756e7420746f2064656c6567617465206c6f776572207468616e206d696044820152646e696d756d60d81b6064820152608401610ada565b5f61266782846155f4565b60fc54604051637202ba3760e11b8152600481018390529192505f91829182916001600160a01b039091169063e405746e906024015f60405180830381865afa1580156126b6573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526126dd9190810190615887565b825160fd5460fb54949750929550909350915f9182916001600160a01b039182169161270b91168284613feb565b60fb54612722906001600160a01b0316828a613feb565b5f61272d858a6157cf565b90505f5b858110156127f1578615612793578781815181106127515761275161553f565b60200260200101515f03156127e957868a8983815181106127745761277461553f565b602002602001015161278691906157b8565b61279091906157cf565b91505b5f8982815181106127a6576127a661553f565b60200260200101515f015190505f6127be8285613d6e565b9050805f036127ce5750506127e9565b6127d982855f6140ec565b506127e4848761559b565b955050505b600101612731565b506127fc838a6155f4565b93506128088a8561559b565b61010655604051849084907f421adba60af7a6b11679e2ac133b1bc91d3de91d56866ec19703d9d60cf950c8905f90a35050600161010d55505050505050505050565b5f80516020615c8c83398151915261286381336130f4565b5f61286c6123b0565b610109546101065461287e91906155f4565b612888919061559b565b60fc54604051639552d81d60e01b8152600481018390529192505f918291829182916001600160a01b031690639552d81d906024015f60405180830381865afa1580156128d7573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526128fe91908101906158ee565b93509350935093505f805f5b86518110156129d5578581815181106129255761292561553f565b60200260200101515f03156129cd5784848783815181106129485761294861553f565b602002602001015161295a91906157b8565b61296491906157cf565b925082156129cd5786818151811061297e5761297e61553f565b60200260200101515f015191505f6129968385613d6e565b9050805f036129a557506129cd565b6129cb8883815181106129ba576129ba61553f565b60200260200101515f015185613e23565b505b60010161290a565b505050505050505050565b6129e982610b60565b6129f381336130f4565b610d9a83836137f7565b6001600160a01b039182165f90815260346020908152604080832093909416825291909152205490565b5f612a3460c95460ff1690565b15612a515760405162461bcd60e51b8152600401610ada90615515565b612a596138ea565b600261010d556001600160a01b038216331480612a885750612a885f80516020615cec83398151915233612160565b612ad45760405162461bcd60e51b815260206004820181905260248201527f43616e6e6f7420776974686472617720666f7220616e6f7468657220757365726044820152606401610ada565b5f612adf848661559b565b11612afc5760405162461bcd60e51b8152600401610ada9061561b565b5f80612b0661243e565b90505f612b138783613d04565b90505f612b208784613d04565b9050871580612b2e57508115155b8015612b415750861580612b4157508015155b612b825760405162461bcd60e51b81526020600482015260126024820152715769746864726177205a45524f20424f4e4560701b6044820152606401610ada565b5f8815612c675760fb5460ff546040516370a0823160e01b81525f926001600160a01b03908116926370a0823192612bc0929091169060040161525f565b602060405180830381865afa158015612bdb573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612bff91906155ae565b90505f8111612c205760405162461bcd60e51b8152600401610ada9061595c565b80841115612c65575f8911612c475760405162461bcd60e51b8152600401610ada9061595c565b60019150612c5581856155f4565b612c5f908461559b565b92508093505b505b8715612c7a57612c77828861415c565b94505b8815612c8a57612c8a83886144f2565b8015612cdb575f612c9b8486613cb6565b61010354909150612cb79089906001600160a01b0316836131d0565b612cd58882612cc68c8e61559b565b612cd091906155f4565b614634565b50612d04565b8815612cfa5761010354612cfa9088906001600160a01b03168b6131d0565b612d048789614634565b6001600160a01b0387167f8004354d3b8d0065a795593eb6b4e51d3d2e4b8e85d664831aad89104f196a9b612d398a8c61559b565b60405190815260200160405180910390a25050600161010d55509095945050505050565b5f54610100900460ff16612d76575f5460ff1615612d7e565b612d7e61476c565b612de15760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610ada565b5f54610100900460ff16158015612e01575f805461ffff19166101011790555b612e0961477c565b612e116147a2565b612e5f6040518060400160405280600e81526020016d4b39205374616b656420424f4e4560901b815250604051806040016040528060068152602001656b6e424f4e4560d01b8152506147d4565b612e695f89613772565b612e805f80516020615c8c83398151915289613772565b612e975f80516020615d0c83398151915289613772565b612eae5f80516020615ccc83398151915289613772565b612ec55f80516020615cec83398151915284613772565b60fc80546001600160a01b03199081166001600160a01b038d81169190911790925560fd805482168a841617905560fe80548216898416179055610103805482168b841617905560fb805482168c841617905560ff805482168884161790556101008054821687841617905561010180548216868416179055610102805490911691841691909117905561010c8054606460ff19909116179055600a6101055560408051608081018252600581525f6020820181905291810191909152605f606090910152610104805463ffffffff1916635f0000051790556a0422ca8b0a00a425000000610107819055610108558015612fc5575f805461ff00191690555b50505050505050505050565b6001600160a01b0383166130335760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610ada565b6001600160a01b0382166130945760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610ada565b6001600160a01b038381165f8181526034602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b6130fe8282612160565b610e3657613116816001600160a01b03166014614813565b613121836020614813565b6040516020016131329291906159b4565b60408051601f198184030181529082905262461bcd60e51b8252610ada91600401615066565b5f61316384846129fd565b90505f1981146131ca57818110156131bd5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610ada565b6131ca8484848403612fd1565b50505050565b6001600160a01b0383166132345760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610ada565b6001600160a01b0382166132965760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610ada565b6001600160a01b0383165f908152603360205260409020548181101561330d5760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401610ada565b6001600160a01b038085165f9081526033602052604080822085850390559185168152908120805484929061334390849061559b565b92505081905550826001600160a01b0316846001600160a01b03165f80516020615cac8339815191528460405161337c91815260200190565b60405180910390a36131ca565b5f81815261010b6020908152604080832080548251818502810185019093528083529192909190849084015b82821015613411575f84815260209081902060408051608081018252600486029092018054835260018082015484860152600282015492840192909252600301546001600160a01b0316606083015290835290920191016133b5565b505050509050805f815181106134295761342961553f565b60200260200101516040015160fd5f9054906101000a90046001600160a01b03166001600160a01b031663900cf0cf6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613485573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906134a991906155ae565b10156134c75760405162461bcd60e51b8152600401610ada906155c5565b60fe54604051630852cd8d60e31b8152600481018490526001600160a01b03909116906342966c68906024015f604051808303815f87803b15801561350a575f80fd5b505af115801561351c573d5f803e3d5ffd5b5050505f83815261010b60205260408120613538925090614fef565b805160fb546040516370a0823160e01b81525f9182916001600160a01b03909116906370a082319061356e90309060040161525f565b602060405180830381865afa158015613589573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906135ad91906155ae565b90505f5b8381101561369f575f6001600160a01b03168582815181106135d5576135d561553f565b6020026020010151606001516001600160a01b031614613638576136338582815181106136045761360461553f565b6020026020010151606001518683815181106136225761362261553f565b60200260200101516020015161393f565b613697565b5f85828151811061364b5761364b61553f565b60200260200101515f01519050806101095f82825461366a91906155f4565b92505081905550806101065f82825461368391906155f4565b909155506136939050818561559b565b9350505b6001016135b1565b5060fb546040516370a0823160e01b815282916001600160a01b0316906370a08231906136d090309060040161525f565b602060405180830381865afa1580156136eb573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061370f91906155ae565b61371991906155f4565b613723908361559b565b60fb5490925061373d906001600160a01b03163384613c3f565b6040518290869033907ff6209e64e006f1421ebd7a27569b31a4d6c62ad38aac9e57c1f2e3b4cd4a535b905f90a45050505050565b61377c8282612160565b610e36575f8281526097602090815260408083206001600160a01b03851684529091529020805460ff191660011790556137b33390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6138018282612160565b15610e36575f8281526097602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b60c95460ff166138a65760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610ada565b60c9805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516138e0919061525f565b60405180910390a1565b600261010d540361393d5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610ada565b565b6040516374bfeee160e11b8152600481018290526001600160a01b0383169063e97fddc2906024015f604051808303815f87803b15801561397e575f80fd5b505af1158015613990573d5f803e3d5ffd5b505050505050565b6131ca846323b872dd60e01b8585856040516024016139b9939291906157ee565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526149a8565b6001600160a01b038216613a465760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610ada565b8060355f828254613a57919061559b565b90915550506001600160a01b0382165f9081526033602052604081208054839290613a8390849061559b565b90915550506040518181526001600160a01b038316905f905f80516020615cac8339815191529060200160405180910390a35050565b60608101515f906001600160a01b0316613ad257505190565b5f826060015190505f613b43826001600160a01b0316635c5f7dae6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613b1a573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613b3e91906155ae565b614a79565b90505f826001600160a01b031663bfb18f296040518163ffffffff1660e01b8152600401602060405180830381865afa158015613b82573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613ba691906155ae565b602086015160405163795be58760e01b81529192505f916001600160a01b0386169163795be58791613bdc913091600401615553565b6040805180830381865afa158015613bf6573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613c1a9190615a03565b80519091508390613c2b90846157b8565b613c3591906157cf565b9695505050505050565b610d9a8363a9059cbb60e01b84846040516024016139b9929190615553565b60c95460ff1615613c815760405162461bcd60e51b8152600401610ada90615515565b60c9805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586138d33390565b5f80613cc160355490565b90508015613ccf5780613cd2565b60015b90508215613ce05782613ce3565b60015b92505f83613cf183876157b8565b613cfb91906157cf565b95945050505050565b5f80613d0f60355490565b90508015613d1d5780613d20565b60015b90508215613d2e5782613d31565b60015b92505f81613cf185876157b8565b5f61010954613d4c6123b0565b61010654613d5a908561559b565b613d64919061559b565b61091891906155f4565b5f808390505f613db3826001600160a01b0316635c5f7dae6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613b1a573d5f803e3d5ffd5b90505f826001600160a01b0316633ba0b9a96040518163ffffffff1660e01b8152600401602060405180830381865afa158015613df2573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613e1691906155ae565b905080613c2b83876157b8565b613e2f82825f19614aa6565b60fd54604080516080810182525f81529051630c11b08160e21b81526001600160a01b039283169261010a92916020830191871690633046c20490613e7890309060040161525f565b602060405180830381865afa158015613e93573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613eb791906155ae565b8152602001836001600160a01b031663a7ab69616040518163ffffffff1660e01b8152600401602060405180830381865afa158015613ef8573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613f1c91906155ae565b846001600160a01b031663900cf0cf6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613f58573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613f7c91906155ae565b613f86919061559b565b81526001600160a01b039586166020918201528254600180820185555f94855293829020835160049092020190815590820151928101929092556040810151600283015560600151600390910180546001600160a01b03191691909416179092555050565b8015806140625750604051636eb1769f60e11b81526001600160a01b0384169063dd62ed3e906140219030908690600401615643565b602060405180830381865afa15801561403c573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061406091906155ae565b155b6140cd5760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608401610ada565b610d9a8363095ea7b360e01b84846040516024016139b9929190615553565b5f80846001600160a01b0316636ab1507185856040518363ffffffff1660e01b815260040161411c9291906150f4565b6020604051808303815f875af1158015614138573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613cfb91906155ae565b60fc546040516308b16df560e21b8152600481018490525f9182918291829182918291829182916001600160a01b03909116906322c5b7d4906024015f60405180830381865afa1580156141b2573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526141d99190810190615a33565b6101065461010954969c50949a5092985090965094509250905f818311614200575f61420a565b61420a82846155f4565b90505f614217828a61559b565b90508d8110156142605760405162461bcd60e51b8152602060048201526014602482015273546f6f206d75636820746f20776974686472617760601b6044820152606401610ada565b505060fe546040516335313c2160e11b81528d93506001600160a01b039091169150636a62784290614296908d9060040161525f565b6020604051808303815f875af11580156142b2573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906142d691906155ae565b9750851561431e5781156142f9576142f288888d858a86614b06565b905061431e565b6143068888878685614b98565b9050801561431e5761431b8888868685614b98565b90505b858b11156144a15760fd545f89815261010b60209081526040808320815160808101835286815280840194909452815163a7ab696160e01b815282516001600160a01b039096169591949392840192869263a7ab69619260048082019392918290030181865afa158015614394573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906143b891906155ae565b846001600160a01b031663900cf0cf6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156143f4573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061441891906155ae565b614422919061559b565b81525f60209182018190528354600180820186559482528282208451600490920201908155918301519382019390935560408201516002820155606090910151600390910180546001600160a01b0319166001600160a01b03909216919091179055610109805484929061449790849061559b565b909155505f925050505b50505050505050826001600160a01b03167f8a8169c8a646f81d6d6ad8ed0cf560361c75cb37a74656f2487d0fa9bfcb0844856040516144e391815260200190565b60405180910390a29392505050565b5f6064610105548461450491906157b8565b61450e91906157cf565b60ff5460fb549192506001600160a01b039081169163d9caed1291168461453585886155f4565b6040518463ffffffff1660e01b8152600401614553939291906157ee565b5f604051808303815f87803b15801561456a575f80fd5b505af115801561457c573d5f803e3d5ffd5b505060ff5460fb5461010354604051636ce5768960e11b81526001600160a01b03938416955063d9caed1294506145bf93928316929091169086906004016157ee565b5f604051808303815f87803b1580156145d6575f80fd5b505af11580156145e8573d5f803e3d5ffd5b50505050816001600160a01b03167f212bb9103631d17f954c525856e0b79b3309c283440626af872e4176b673ab7d84836040516146279291906150f4565b60405180910390a2505050565b6001600160a01b0382166146945760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608401610ada565b6001600160a01b0382165f90815260336020526040902054818110156147075760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b6064820152608401610ada565b6001600160a01b0383165f9081526033602052604081208383039055603580548492906147359084906155f4565b90915550506040518281525f906001600160a01b038516905f80516020615cac8339815191529060200160405180910390a3505050565b5f61477630614c77565b15905090565b5f54610100900460ff1661393d5760405162461bcd60e51b8152600401610ada90615ae9565b5f54610100900460ff166147c85760405162461bcd60e51b8152600401610ada90615ae9565b60c9805460ff19169055565b5f54610100900460ff166147fa5760405162461bcd60e51b8152600401610ada90615ae9565b60366148068382615b7f565b506037610d9a8282615b7f565b60605f6148218360026157b8565b61482c90600261559b565b6001600160401b038111156148435761484361565d565b6040519080825280601f01601f19166020018201604052801561486d576020820181803683370190505b509050600360fc1b815f815181106148875761488761553f565b60200101906001600160f81b03191690815f1a905350600f60fb1b816001815181106148b5576148b561553f565b60200101906001600160f81b03191690815f1a9053505f6148d78460026157b8565b6148e290600161559b565b90505b6001811115614959576f181899199a1a9b1b9c1cb0b131b232b360811b85600f16601081106149165761491661553f565b1a60f81b82828151811061492c5761492c61553f565b60200101906001600160f81b03191690815f1a90535060049490941c9361495281615c3a565b90506148e5565b508315610b595760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610ada565b5f6149fc826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316614c869092919063ffffffff16565b805190915015610d9a5780806020019051810190614a1a919061556c565b610d9a5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610ada565b5f60088210614a9457680a18f07d736b90be55601d1b614a97565b60645b6001600160681b031692915050565b60405163c83ec04d60e01b81526001600160a01b0384169063c83ec04d90614ad490859085906004016150f4565b5f604051808303815f87803b158015614aeb575f80fd5b505af1158015614afd573d5f803e3d5ffd5b50505050505050565b5f80614b128487614c9c565b90505f614b1f86836157cf565b90505f5b86811015614b8a575f898281518110614b3e57614b3e61553f565b60200260200101515f015190505f614b568285613d6e565b11614b735760405162461bcd60e51b8152600401610ada90615c4f565b614b7f8b828589614cb0565b955050600101614b23565b509298975050505050505050565b5f805b8451811015614c6c575f858281518110614bb757614bb761553f565b602002602001015190505f858281518110614bd457614bd461553f565b60200260200101519050805f03614bec575050614c64565b5f614bf78287614c9c565b90505f898481518110614c0c57614c0c61553f565b60200260200101515f015190505f614c248284613d6e565b11614c415760405162461bcd60e51b8152600401610ada90615c4f565b614c4d8b82848a614cb0565b9650865f03614c5f5750505050614c6c565b505050505b600101614b9b565b509095945050505050565b6001600160a01b03163b151590565b6060614c9484845f85614e8b565b949350505050565b5f818311614caa5782610b59565b50919050565b5f614cbd84845f19614aa6565b60fd545f86815261010b6020908152604080832081516080810183529384529051630c11b08160e21b81526001600160a01b0394851694919392830191891690633046c20490614d1190309060040161525f565b602060405180830381865afa158015614d2c573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190614d5091906155ae565b8152602001836001600160a01b031663a7ab69616040518163ffffffff1660e01b8152600401602060405180830381865afa158015614d91573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190614db591906155ae565b846001600160a01b031663900cf0cf6040518163ffffffff1660e01b8152600401602060405180830381865afa158015614df1573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190614e1591906155ae565b614e1f919061559b565b81526001600160a01b038881166020928301528354600180820186555f958652948390208451600490920201908155918301519382019390935560408201516002820155606090910151600390910180546001600160a01b03191691909216179055613c3584846155f4565b606082471015614eec5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610ada565b614ef585614c77565b614f415760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610ada565b5f80866001600160a01b03168587604051614f5c9190615c80565b5f6040518083038185875af1925050503d805f8114614f96576040519150601f19603f3d011682016040523d82523d5f602084013e614f9b565b606091505b5091509150614fab828286614fb6565b979650505050505050565b60608315614fc5575081610b59565b825115614fd55782518084602001fd5b8160405162461bcd60e51b8152600401610ada9190615066565b5080545f8255600402905f5260205f2090810190610ef891905b8082111561503b575f8082556001820181905560028201556003810180546001600160a01b0319169055600401615009565b5090565b5f6020828403121561504f575f80fd5b81356001600160e01b031981168114610b59575f80fd5b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b6001600160a01b0381168114610ef8575f80fd5b5f80604083850312156150c0575f80fd5b82356150cb8161509b565b946020939093013593505050565b5f602082840312156150e9575f80fd5b8135610b598161509b565b918252602082015260400190565b5f805f60608486031215615114575f80fd5b833561511f8161509b565b9250602084013561512f8161509b565b929592945050506040919091013590565b5f60208284031215615150575f80fd5b5035919050565b602080825282518282018190525f919060409081850190868401855b828110156151b657815180518552868101518786015285810151868601526060908101516001600160a01b03169085015260809093019290850190600101615173565b5091979650505050505050565b5f80602083850312156151d4575f80fd5b82356001600160401b03808211156151ea575f80fd5b818501915085601f8301126151fd575f80fd5b81358181111561520b575f80fd5b8660208260051b850101111561521f575f80fd5b60209290920196919550909350505050565b5f8060408385031215615242575f80fd5b8235915060208301356152548161509b565b809150509250929050565b6001600160a01b0391909116815260200190565b803560ff81168114615283575f80fd5b919050565b5f60208284031215615298575f80fd5b610b5982615273565b8015158114610ef8575f80fd5b5f805f606084860312156152c0575f80fd5b8335925060208401356152d28161509b565b915060408401356152e2816152a1565b809150509250925092565b60ff948516815292841660208401529083166040830152909116606082015260800190565b5f805f8060808587031215615325575f80fd5b61532e85615273565b935061533c60208601615273565b925061534a60408601615273565b915061535860608601615273565b905092959194509250565b5f8060408385031215615374575f80fd5b50508035926020909101359150565b5f8060408385031215615394575f80fd5b823561539f8161509b565b915060208301356152548161509b565b5f805f606084860312156153c1575f80fd5b833592506020840135915060408401356152e28161509b565b5f805f805f805f805f6101208a8c0312156153f3575f80fd5b89356153fe8161509b565b985060208a013561540e8161509b565b975060408a013561541e8161509b565b965060608a013561542e8161509b565b955060808a013561543e8161509b565b945060a08a013561544e8161509b565b935060c08a013561545e8161509b565b925060e08a013561546e8161509b565b91506101008a013561547f8161509b565b809150509295985092959850929598565b600181811c908216806154a457607f821691505b602082108103614caa57634e487b7160e01b5f52602260045260245ffd5b5f80604083850312156154d3575f80fd5b505080516020909101519092909150565b60208082526017908201527643616e6e6f7420736574207a65726f206164647265737360481b604082015260600190565b60208082526010908201526f14185d5cd8589b194e881c185d5cd95960821b604082015260600190565b634e487b7160e01b5f52603260045260245ffd5b6001600160a01b03929092168252602082015260400190565b5f6020828403121561557c575f80fd5b8151610b59816152a1565b634e487b7160e01b5f52601160045260245ffd5b8082018082111561091857610918615587565b5f602082840312156155be575f80fd5b5051919050565b602080825260159082015274139bdd0818589b19481d1bc818db185a5b481e595d605a1b604082015260600190565b8181038181111561091857610918615587565b634e487b7160e01b5f52603160045260245ffd5b6020808252600e908201526d125b9d985b1a5908185b5bdd5b9d60921b604082015260600190565b6001600160a01b0392831681529116602082015260400190565b634e487b7160e01b5f52604160045260245ffd5b604080519081016001600160401b03811182821017156156935761569361565d565b60405290565b604051601f8201601f191681016001600160401b03811182821017156156c1576156c161565d565b604052919050565b5f6001600160401b038211156156e1576156e161565d565b5060051b60200190565b5f82601f8301126156fa575f80fd5b8151602061570f61570a836156c9565b615699565b82815260069290921b8401810191818101908684111561572d575f80fd5b8286015b8481101561577c5760408189031215615748575f80fd5b615750615671565b815161575b8161509b565b81528185015161576a8161509b565b81860152835291830191604001615731565b509695505050505050565b5f60208284031215615797575f80fd5b81516001600160401b038111156157ac575f80fd5b614c94848285016156eb565b808202811582820484141761091857610918615587565b5f826157e957634e487b7160e01b5f52601260045260245ffd5b500490565b6001600160a01b039384168152919092166020820152604081019190915260600190565b60ff818116838216019081111561091857610918615587565b5f82601f83011261583a575f80fd5b8151602061584a61570a836156c9565b8083825260208201915060208460051b87010193508684111561586b575f80fd5b602086015b8481101561577c5780518352918301918301615870565b5f805f60608486031215615899575f80fd5b83516001600160401b03808211156158af575f80fd5b6158bb878388016156eb565b945060208601519150808211156158d0575f80fd5b506158dd8682870161582b565b925050604084015190509250925092565b5f805f8060808587031215615901575f80fd5b84516001600160401b0380821115615917575f80fd5b615923888389016156eb565b95506020870151915080821115615938575f80fd5b506159458782880161582b565b604087015160609097015195989097509350505050565b60208082526021908201527f496e7374616e7420706f6f6c20696e73756666696369656e742062616c616e636040820152606560f81b606082015260800190565b5f81518060208401855e5f93019283525090919050565b76020b1b1b2b9b9a1b7b73a3937b61d1030b1b1b7bab73a1604d1b81525f6159df601783018561599d565b7001034b99036b4b9b9b4b733903937b6329607d1b8152613cfb601182018561599d565b5f60408284031215615a13575f80fd5b615a1b615671565b82518152602083015160208201528091505092915050565b5f805f805f8060c08789031215615a48575f80fd5b86516001600160401b0380821115615a5e575f80fd5b615a6a8a838b016156eb565b9750602089015196506040890151915080821115615a86575f80fd5b615a928a838b0161582b565b95506060890151915080821115615aa7575f80fd5b615ab38a838b0161582b565b94506080890151915080821115615ac8575f80fd5b50615ad589828a0161582b565b92505060a087015190509295509295509295565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b601f821115610d9a57805f5260205f20601f840160051c81016020851015615b595750805b601f840160051c820191505b81811015615b78575f8155600101615b65565b5050505050565b81516001600160401b03811115615b9857615b9861565d565b615bac81615ba68454615490565b84615b34565b602080601f831160018114615bdf575f8415615bc85750858301515b5f19600386901b1c1916600185901b178555613990565b5f85815260208120601f198616915b82811015615c0d57888601518255948401946001909101908401615bee565b5085821015615c2a57878501515f19600388901b60f8161c191681555b5050505050600190811b01905550565b5f81615c4857615c48615587565b505f190190565b6020808252601790820152765a45524f2073686172657320746f20776974686472617760481b604082015260600190565b5f610b59828461599d56fe3b5d4cc60d3ec3516ee8ae083bd60934f6eb2a6c54b1229985c41bfb092b2603ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef265b220c5a8891efdd9e1b1b7fa72f257bd5169f8d87e319cf3dad6ff52b94ae52ba824bfabc2bcfcdf7f0edbb486ebb05e1836c90e78047efeb949990f72e5f139c2898040ef16910dc9f44dc697df79363da767d8bc92f2e310312b816e46da26469706673582212204ac11027ede7e54985b358fea9b04f5c1f74b8d61eff1c10661ef16f87f82cc764736f6c63430008190033
Verified Source Code Partial Match
Compiler: v0.8.25+commit.b61c2a91
EVM: cancun
Optimization: Yes (1 runs)
KnBONE.sol 1210 lines
// The following code is based on the Shardlabs' source code of Lido for Polygon
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.25;
import "./interfaces/IKnBONE.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";
import "./interfaces/IStakeManager.sol";
import "./interfaces/IValidatorShare.sol";
import "./interfaces/INodeOperatorRegistry.sol";
import "./interfaces/IUnstBONE.sol";
import "./interfaces/IInstantPool.sol";
import "./interfaces/IDepositManager.sol";
import "./interfaces/IBridgeETH.sol";
contract KnBONE is
IKnBONE,
ERC20Upgradeable,
AccessControlUpgradeable,
PausableUpgradeable
{
using SafeERC20Upgradeable for IERC20Upgradeable;
/// @notice BONE ERC20 token.
IERC20Upgradeable public token;
/// @notice node operator registry interface.
INodeOperatorRegistry public nodeOperatorRegistry;
/// @notice StakeManager interface.
IStakeManager public stakeManager;
/// @notice unstBONE interface.
IUnstBONE public unstBONE;
/// @notice InstantPool interface.
IInstantPool public instantPool;
/// @notice DepositManager interface.
IDepositManager public depositManager;
/// @notice Bridge interface.
IBridgeETH public bridge;
/// @notice address of L2 staking.
address public l2Staking;
/// @notice dao address.
address public dao;
/// @notice The fee distribution.
FeeDistribution public entityFees;
/// @notice fee percentage for using instant pool.
uint256 public instantPoolUsageFee;
/// @notice total buffered BONE in the contract.
uint256 public totalBuffered;
/// @notice delegation lower bound.
uint256 public delegationLowerBound;
/// @notice reward distribution lower bound.
uint256 public rewardDistributionLowerBound;
/// @notice reserved funds in BONE.
uint256 public reservedFunds;
/// @notice DAO Role.
bytes32 public constant DAO_ROLE = keccak256("DAO_ROLE");
bytes32 public constant PAUSE_ROLE =
keccak256("PAUSE_ROLE");
bytes32 public constant UNPAUSE_ROLE =
keccak256("UNPAUSE_ROLE");
bytes32 public constant BRIDGE_ROLE = keccak256("BRIDGE_ROLE");
/// @notice When an operator quit the system knBONE contract withdraw the total delegated
/// to it. The request is stored inside this array.
RequestWithdraw[] public knBONEWithdrawRequest;
/// @notice token to Array WithdrawRequest mapping one-to-many.
mapping(uint256 => RequestWithdraw[]) public token2WithdrawRequests;
/// @notice protocol fee.
uint8 public protocolFee;
/// @notice these state variable are used to mark entrance and exit form a contract function
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
/// @notice used to execute the recovery 1 time
bool private recovered;
/// @notice Prevents a contract from calling itself, directly or indirectly.
modifier nonReentrant() {
_nonReentrant();
_status = _ENTERED;
_;
_status = _NOT_ENTERED;
}
/// @param _nodeOperatorRegistry - Address of the node operator registry
/// @param _token - Address of BONE token on Ethereum Mainnet
/// @param _dao - Address of the DAO
/// @param _stakeManager - Address of the stake manager
/// @param _unstBONE - Address of the knBONE NFT
/// @param _instantPool - Address of the intstant pool
/// @param _depositManager - Address of the deposit manager
/// @param _bridge - Address of the bridge
/// @param _l2Staking - Address of the L2 staking
function initialize(
INodeOperatorRegistry _nodeOperatorRegistry,
IERC20Upgradeable _token,
address _dao,
IStakeManager _stakeManager,
IUnstBONE _unstBONE,
IInstantPool _instantPool,
IDepositManager _depositManager,
IBridgeETH _bridge,
address _l2Staking
) external initializer {
__AccessControl_init_unchained();
__Pausable_init_unchained();
__ERC20_init_unchained("K9 Staked BONE", "knBONE");
_grantRole(DEFAULT_ADMIN_ROLE, _dao);
_grantRole(DAO_ROLE, _dao);
_grantRole(PAUSE_ROLE, _dao);
_grantRole(UNPAUSE_ROLE, _dao);
_grantRole(BRIDGE_ROLE, address(_bridge));
nodeOperatorRegistry = _nodeOperatorRegistry;
stakeManager = IStakeManager(_stakeManager);
unstBONE = IUnstBONE(_unstBONE);
dao = _dao;
token = _token;
instantPool = _instantPool;
depositManager = _depositManager;
bridge = _bridge;
l2Staking = _l2Staking;
protocolFee = 100;
instantPoolUsageFee = 10;
entityFees = FeeDistribution(5, 0, 0, 95);
delegationLowerBound = 5000000000000000000000000;
rewardDistributionLowerBound = 5000000000000000000000000;
}
/// @notice Send funds to knBONE contract and mint knBONE to receiver
/// @notice Requires that msg.sender has approved _amount of BONE to this contract
/// @param _amount - Amount of BONE sent from msg.sender to this contract
/// @param _receiver - receiver address.
/// @param _transferToL2 - whether or not transfer knBONE to L2
/// @return Amount of knBONE shares generated
function submit(uint256 _amount, address _receiver, bool _transferToL2)
external
whenNotPaused
nonReentrant
returns (uint256)
{
require(_amount > 0, "Invalid amount");
token.safeTransferFrom(
msg.sender,
address(this),
_amount
);
(
uint256 amountToMint,
,
) = convertBONEToKnBONE(_amount);
require(amountToMint > 0, "Mint ZERO");
if (_transferToL2) {
_mint(address(this), amountToMint);
_approve(address(this), address(bridge), amountToMint);
bridge.depositForUser(_receiver, amountToMint);
}
else {
_mint(_receiver, amountToMint);
}
totalBuffered += _amount;
emit SubmitEvent(msg.sender, _amount, _receiver, _transferToL2);
return amountToMint;
}
/// @notice Allows to request withdraw and use instant pool
/// @param _instantPoolAmount - Amount of knBONE that is requested to withdraw using instant pool
/// @param _requestWithdrawAmount - Amount of knBONE that is requested to withdraw using queue
/// @param _user - user to withdraw from
/// @return NFT token id.
function requestWithdrawSplit(uint256 _instantPoolAmount, uint256 _requestWithdrawAmount, address _user) external whenNotPaused nonReentrant returns(uint256) {
require(_user == msg.sender || hasRole(BRIDGE_ROLE, msg.sender), "Cannot withdraw for another user");
require((_instantPoolAmount + _requestWithdrawAmount) > 0, "Invalid amount");
uint256 tokenId;
uint256 totalPooledBONE = getTotalPooledBONE();
uint256 instantPoolAmountInBONE = _convertKnBONEToBONE(
_instantPoolAmount,
totalPooledBONE
);
uint256 requestWithdrawAmountInBONE = _convertKnBONEToBONE(
_requestWithdrawAmount,
totalPooledBONE
);
require((_instantPoolAmount == 0 || instantPoolAmountInBONE != 0) && (_requestWithdrawAmount == 0 || requestWithdrawAmountInBONE != 0), "Withdraw ZERO BONE");
bool flag;
if (_instantPoolAmount > 0) {
uint256 instantPoolBalance = token.balanceOf(address(instantPool));
require(instantPoolBalance > 0, "Instant pool insufficient balance");
if (instantPoolAmountInBONE > instantPoolBalance) {
require(_requestWithdrawAmount > 0, "Instant pool insufficient balance");
flag = true;
requestWithdrawAmountInBONE += instantPoolAmountInBONE - instantPoolBalance;
instantPoolAmountInBONE = instantPoolBalance;
}
}
if (_requestWithdrawAmount > 0) {
tokenId = _requestWithdrawInternal(requestWithdrawAmountInBONE, _user);
}
if (_instantPoolAmount > 0) {
_withdrawFromInstantPool(instantPoolAmountInBONE, _user);
}
if (flag) {
uint256 knBONEFromBONE = _convertBONEToKnBONE(instantPoolAmountInBONE, totalPooledBONE);
_transfer(_user, dao, knBONEFromBONE);
_burn(_user, _instantPoolAmount + _requestWithdrawAmount - knBONEFromBONE);
}
else {
if (_instantPoolAmount > 0) {
_transfer(_user, dao, _instantPoolAmount);
}
_burn(_user, _requestWithdrawAmount);
}
emit RequestWithdrawSplit(_user, _instantPoolAmount + _requestWithdrawAmount);
return tokenId;
}
function _withdrawFromInstantPool(uint256 _amountInBONE, address _user) private {
uint256 fee = (_amountInBONE * instantPoolUsageFee) / 100;
instantPool.withdraw(token, _user, _amountInBONE - fee);
instantPool.withdraw(token, dao, fee);
emit InstantPoolWithdraw(_user, _amountInBONE, fee);
}
function _requestWithdrawInternal(uint256 totalAmount2WithdrawInBONE, address _user)
private
returns (uint256)
{
uint256 tokenId;
{
(
INodeOperatorRegistry.ValidatorData[] memory activeNodeOperators,
uint256 totalDelegated,
uint256[] memory bigNodeOperatorIds,
uint256[] memory smallNodeOperatorIds,
uint256[] memory allowedAmountToRequestFromOperators,
uint256 totalValidatorsToWithdrawFrom
) = nodeOperatorRegistry.getValidatorsRequestWithdraw(totalAmount2WithdrawInBONE);
{
uint256 totalBufferedMem = totalBuffered;
uint256 reservedFundsMem = reservedFunds;
uint256 localActiveBalance = totalBufferedMem > reservedFundsMem
? totalBufferedMem - reservedFundsMem
: 0;
uint256 liquidity = totalDelegated + localActiveBalance;
require(
liquidity >= totalAmount2WithdrawInBONE,
"Too much to withdraw"
);
}
// Added a scoop here to fix stack too deep error
{
uint256 currentAmount2WithdrawInBONE = totalAmount2WithdrawInBONE;
tokenId = unstBONE.mint(_user);
if (totalDelegated != 0) {
if (totalValidatorsToWithdrawFrom != 0) {
currentAmount2WithdrawInBONE = _requestWithdrawBalanced(
tokenId,
activeNodeOperators,
totalAmount2WithdrawInBONE,
totalValidatorsToWithdrawFrom,
totalDelegated,
currentAmount2WithdrawInBONE
);
} else {
// request withdraw from big delegated validators
currentAmount2WithdrawInBONE = _requestWithdrawUnbalanced(
tokenId,
activeNodeOperators,
bigNodeOperatorIds,
allowedAmountToRequestFromOperators,
currentAmount2WithdrawInBONE
);
// request withdraw from small delegated validators
if (currentAmount2WithdrawInBONE != 0) {
currentAmount2WithdrawInBONE = _requestWithdrawUnbalanced(
tokenId,
activeNodeOperators,
smallNodeOperatorIds,
allowedAmountToRequestFromOperators,
currentAmount2WithdrawInBONE
);
}
}
}
if (totalAmount2WithdrawInBONE > totalDelegated) {
IStakeManager stakeManagerMem = stakeManager;
token2WithdrawRequests[tokenId].push(
RequestWithdraw(
currentAmount2WithdrawInBONE,
0,
stakeManagerMem.epoch() + stakeManagerMem.withdrawalDelay(),
address(0)
)
);
reservedFunds += currentAmount2WithdrawInBONE;
currentAmount2WithdrawInBONE = 0;
}
}
}
emit RequestWithdrawEvent(_user, totalAmount2WithdrawInBONE);
return tokenId;
}
/// @notice Request withdraw when system is balanced
function _requestWithdrawBalanced(
uint256 tokenId,
INodeOperatorRegistry.ValidatorData[] memory activeNodeOperators,
uint256 totalAmount2WithdrawInBONE,
uint256 totalValidatorsToWithdrawFrom,
uint256 totalDelegated,
uint256 currentAmount2WithdrawInBONE
) private returns (uint256) {
uint256 totalAmount = min(totalDelegated, totalAmount2WithdrawInBONE);
uint256 amount2WithdrawFromValidator = totalAmount /
totalValidatorsToWithdrawFrom;
for (uint256 idx = 0; idx < totalValidatorsToWithdrawFrom; idx++) {
address validatorShare = activeNodeOperators[idx].validatorShare;
require(
_calculateValidatorShares(
validatorShare,
amount2WithdrawFromValidator
) > 0,
"ZERO shares to withdraw"
);
currentAmount2WithdrawInBONE = _requestWithdraw(
tokenId,
validatorShare,
amount2WithdrawFromValidator,
currentAmount2WithdrawInBONE
);
}
return currentAmount2WithdrawInBONE;
}
/// @notice Request withdraw when system is unbalanced
function _requestWithdrawUnbalanced(
uint256 tokenId,
INodeOperatorRegistry.ValidatorData[] memory activeNodeOperators,
uint256[] memory nodeOperatorIds,
uint256[] memory allowedAmountToRequestFromOperators,
uint256 currentAmount2WithdrawInBONE
) private returns (uint256) {
for (uint256 idx = 0; idx < nodeOperatorIds.length; idx++) {
uint256 id = nodeOperatorIds[idx];
uint256 amountCanBeRequested = allowedAmountToRequestFromOperators[
id
];
if (amountCanBeRequested == 0) continue;
uint256 amount2WithdrawFromValidator = min(amountCanBeRequested, currentAmount2WithdrawInBONE);
address validatorShare = activeNodeOperators[id].validatorShare;
require(
_calculateValidatorShares(
validatorShare,
amount2WithdrawFromValidator
) > 0,
"ZERO shares to withdraw"
);
currentAmount2WithdrawInBONE = _requestWithdraw(
tokenId,
validatorShare,
amount2WithdrawFromValidator,
currentAmount2WithdrawInBONE
);
if (currentAmount2WithdrawInBONE == 0) break;
}
return currentAmount2WithdrawInBONE;
}
function _requestWithdraw(
uint256 tokenId,
address validatorShare,
uint256 amount2WithdrawFromValidator,
uint256 currentAmount2WithdrawInBONE
) private returns (uint256) {
sellVoucher_new(
validatorShare,
amount2WithdrawFromValidator,
type(uint256).max
);
IStakeManager stakeManagerMem = stakeManager;
token2WithdrawRequests[tokenId].push(
RequestWithdraw(
0,
IValidatorShare(validatorShare).unbondNonces(address(this)),
stakeManagerMem.epoch() + stakeManagerMem.withdrawalDelay(),
validatorShare
)
);
currentAmount2WithdrawInBONE -= amount2WithdrawFromValidator;
return currentAmount2WithdrawInBONE;
}
/// @notice This will be included in the cron job
/// @notice Delegates tokens to validator share contract
function delegate() external whenNotPaused nonReentrant {
uint256 ltotalBuffered = totalBuffered;
uint256 lreservedFunds = reservedFunds;
require(
ltotalBuffered > delegationLowerBound + lreservedFunds,
"Amount to delegate lower than minimum"
);
uint256 amountToDelegate = ltotalBuffered - lreservedFunds;
(
INodeOperatorRegistry.ValidatorData[]
memory delegatableNodeOperators,
uint256[] memory operatorRatiosToDelegate,
uint256 totalRatio
) = nodeOperatorRegistry.getValidatorsDelegationAmount(
amountToDelegate
);
uint256 totalDelegatableNodeOperators = delegatableNodeOperators.length;
uint256 remainder;
uint256 amountDelegated;
address stakeManagerAddress = address(stakeManager);
token.safeApprove(stakeManagerAddress, 0);
token.safeApprove(
stakeManagerAddress,
amountToDelegate
);
// If the total Ratio is equal to ZERO that means the system is balanced so we
// distribute the buffered tokens equally between the validators
uint256 amountToDelegatePerOperator = amountToDelegate / totalDelegatableNodeOperators;
for (uint256 i = 0; i < totalDelegatableNodeOperators; i++) {
if (totalRatio != 0) {
if (operatorRatiosToDelegate[i] == 0) continue;
amountToDelegatePerOperator =
(operatorRatiosToDelegate[i] * amountToDelegate) /
totalRatio;
}
address _validatorAddress = delegatableNodeOperators[i]
.validatorShare;
uint256 shares = _calculateValidatorShares(
_validatorAddress,
amountToDelegatePerOperator
);
if (shares == 0) continue;
buyVoucher(_validatorAddress, amountToDelegatePerOperator, 0);
amountDelegated += amountToDelegatePerOperator;
}
remainder = amountToDelegate - amountDelegated;
totalBuffered = remainder + lreservedFunds;
emit DelegateEvent(amountDelegated, remainder);
}
/// @notice Claims tokens from validator share and sends them to the
/// user if his request is in the userToWithdrawRequest
/// @param _tokenId - List of token IDs to be claimed
function claimTokens(uint256[] calldata _tokenId) external whenNotPaused {
for (uint256 i; i < _tokenId.length; i++) {
require(
unstBONE.isApprovedOrOwner(msg.sender, _tokenId[i]),
"Not owner"
);
if (token2WithdrawRequests[_tokenId[i]].length != 0) {
_claimTokensV2(_tokenId[i]);
} else {
revert("Invalid claim token");
}
}
}
/// @notice Claims tokens v2
function _claimTokensV2(uint256 _tokenId) private {
RequestWithdraw[] memory usersRequest = token2WithdrawRequests[
_tokenId
];
require(
stakeManager.epoch() >= usersRequest[0].requestEpoch,
"Not able to claim yet"
);
unstBONE.burn(_tokenId);
delete token2WithdrawRequests[_tokenId];
uint256 length = usersRequest.length;
uint256 amountToClaim;
uint256 balanceBeforeClaim = token.balanceOf(
address(this)
);
for (uint256 idx = 0; idx < length; idx++) {
if (usersRequest[idx].validatorAddress != address(0)) {
unstakeClaimTokens_new(
usersRequest[idx].validatorAddress,
usersRequest[idx].validatorNonce
);
} else {
uint256 _amountToClaim = usersRequest[idx]
.amount2WithdrawFromKnBONE;
reservedFunds -= _amountToClaim;
totalBuffered -= _amountToClaim;
amountToClaim += _amountToClaim;
}
}
amountToClaim +=
token.balanceOf(address(this)) -
balanceBeforeClaim;
token.safeTransfer(msg.sender, amountToClaim);
emit ClaimTokensEvent(msg.sender, _tokenId, amountToClaim);
}
/// @notice Distributes rewards claimed from validator shares based on fees defined
/// in entityFee.
function distributeRewards() external whenNotPaused nonReentrant {
uint256 totalPooledBefore = getTotalPooledBONE();
INodeOperatorRegistry.ValidatorData[] memory operatorInfos = nodeOperatorRegistry.listDelegatedNodeOperators();
uint256 totalActiveOperatorInfos = operatorInfos.length;
for (uint256 i = 0; i < totalActiveOperatorInfos; i++) {
IValidatorShare validatorShare = IValidatorShare(
operatorInfos[i].validatorShare
);
uint256 knBONEReward = validatorShare.getLiquidRewards(
address(this)
);
uint256 rewardThreshold = validatorShare.minAmount();
if (knBONEReward > rewardThreshold) {
validatorShare.withdrawRewards();
}
}
uint256 totalRewards = token.balanceOf(
address(this)
) - totalBuffered;
uint256 protocolRewards = totalRewards * protocolFee / 100;
require(
protocolRewards > rewardDistributionLowerBound,
"Amount to distribute lower than minimum"
);
uint256 balanceBeforeDistribution = token.balanceOf(
address(this)
);
uint256 daoRewards = (protocolRewards * entityFees.dao) / 100;
uint256 instantPoolRewards = (protocolRewards * entityFees.instantPool) / 100;
uint256 stakingRewards = (protocolRewards * entityFees.staking) / 100;
uint256 operatorsRewards = (protocolRewards * entityFees.operators) / 100;
uint256 operatorReward = operatorsRewards / totalActiveOperatorInfos;
token.safeTransfer(dao, daoRewards);
token.safeTransfer(address(instantPool), instantPoolRewards);
token.approve(address(depositManager), stakingRewards);
depositManager.depositERC20ForUser(address(token), l2Staking, stakingRewards);
for (uint256 i = 0; i < totalActiveOperatorInfos; i++) {
token.safeTransfer(
operatorInfos[i].rewardAddress,
operatorReward
);
}
uint256 currentBalance = token.balanceOf(
address(this)
);
uint256 totalDistributed = balanceBeforeDistribution - currentBalance;
// Add the remainder to totalBuffered
totalBuffered = currentBalance;
emit DistributeRewardsEvent(totalDistributed, totalPooledBefore, getTotalPooledBONE());
}
/// @notice Only NodeOperatorRegistry can call this function
/// @notice Withdraws funds from stopped validator.
/// @param _validatorShare - Address of the validator share that will be withdrawn
function withdrawTotalDelegated(address _validatorShare)
external
nonReentrant
{
require(
msg.sender == address(nodeOperatorRegistry),
"Not a node operator"
);
(uint256 stakedAmount, ) = getTotalStake(
IValidatorShare(_validatorShare)
);
// Check if the validator has enough shares.
uint256 shares = _calculateValidatorShares(
_validatorShare,
stakedAmount
);
if (shares == 0) {
return;
}
_createWithdrawRequest(_validatorShare, stakedAmount);
emit WithdrawTotalDelegatedEvent(_validatorShare, stakedAmount);
}
/// @notice Rebalane the system by request withdraw from the validators that contains
/// more token delegated to them.
function rebalanceDelegatedTokens() external onlyRole(DAO_ROLE) {
uint256 amountToReDelegate = totalBuffered -
reservedFunds +
calculatePendingBufferedTokens();
(
INodeOperatorRegistry.ValidatorData[] memory nodeOperators,
uint256[] memory operatorRatiosToRebalance,
uint256 totalRatio,
uint256 totalToWithdraw
) = nodeOperatorRegistry.getValidatorsRebalanceAmount(
amountToReDelegate
);
uint256 amountToWithdraw;
address _validatorAddress;
for (uint256 i = 0; i < nodeOperators.length; i++) {
if (operatorRatiosToRebalance[i] == 0) continue;
amountToWithdraw =
(operatorRatiosToRebalance[i] * totalToWithdraw) /
totalRatio;
if (amountToWithdraw == 0) continue;
_validatorAddress = nodeOperators[i].validatorShare;
uint256 shares = _calculateValidatorShares(
_validatorAddress,
amountToWithdraw
);
if (shares == 0) continue;
_createWithdrawRequest(
nodeOperators[i].validatorShare,
amountToWithdraw
);
}
}
function _createWithdrawRequest(address _validatorShare, uint256 amount)
private
{
sellVoucher_new(_validatorShare, amount, type(uint256).max);
IStakeManager stakeManagerMem = stakeManager;
knBONEWithdrawRequest.push(
RequestWithdraw(
0,
IValidatorShare(_validatorShare).unbondNonces(address(this)),
stakeManagerMem.epoch() + stakeManagerMem.withdrawalDelay(),
_validatorShare
)
);
}
/// @notice calculate the total amount stored in knBONEWithdrawRequest array.
/// @return pendingBufferedTokens the total pending amount for knBONE.
function calculatePendingBufferedTokens()
public
view
returns (uint256 pendingBufferedTokens)
{
uint256 pendingWithdrawalLength = knBONEWithdrawRequest.length;
for (uint256 i = 0; i < pendingWithdrawalLength; i++) {
pendingBufferedTokens += _getBONEFromRequestData(
knBONEWithdrawRequest[i]
);
}
return pendingBufferedTokens;
}
/// @notice Claims tokens from validator share and sends them to the knBONE contract.
function claimTokensFromValidatorToContract(uint256 _index)
external
whenNotPaused
nonReentrant
{
uint256 length = knBONEWithdrawRequest.length;
require(_index < length, "invalid index");
RequestWithdraw memory lsRequest = knBONEWithdrawRequest[_index];
require(
stakeManager.epoch() >= lsRequest.requestEpoch,
"Not able to claim yet"
);
uint256 balanceBeforeClaim = token.balanceOf(
address(this)
);
unstakeClaimTokens_new(
lsRequest.validatorAddress,
lsRequest.validatorNonce
);
uint256 claimedAmount = token.balanceOf(
address(this)
) - balanceBeforeClaim;
totalBuffered += claimedAmount;
if (_index != length - 1 && length != 1) {
knBONEWithdrawRequest[_index] = knBONEWithdrawRequest[length - 1];
}
knBONEWithdrawRequest.pop();
emit ClaimTotalDelegatedEvent(
lsRequest.validatorAddress,
claimedAmount
);
}
/// @notice Pauses the contract
function pause() external onlyRole(PAUSE_ROLE) {
_pause();
}
/// @notice Unpauses the contract
function unpause() external onlyRole(UNPAUSE_ROLE) {
_unpause();
}
////////////////////////////////////////////////////////////
///// ///
///// ***ValidatorShare API*** ///
///// ///
////////////////////////////////////////////////////////////
/// @notice Returns the knBONEWithdrawRequest list
function getTotalWithdrawRequest()
public
view
returns (RequestWithdraw[] memory)
{
return knBONEWithdrawRequest;
}
/// @notice API for delegated buying vouchers from validatorShare
/// @param _validatorShare - Address of validatorShare contract
/// @param _amount - Amount of BONE to use for buying vouchers
/// @param _minSharesToMint - Minimum of shares that is bought with _amount of BONE
/// @return Actual amount of BONE used to buy voucher, might differ from _amount because of _minSharesToMint
function buyVoucher(
address _validatorShare,
uint256 _amount,
uint256 _minSharesToMint
) private returns (uint256) {
uint256 amountSpent = IValidatorShare(_validatorShare).buyVoucher(
_amount,
_minSharesToMint
);
return amountSpent;
}
/// @notice API for delegated unstaking and claiming tokens from validatorShare
/// @param _validatorShare - Address of validatorShare contract
/// @param _unbondNonce - Unbond nonce
function unstakeClaimTokens_new(
address _validatorShare,
uint256 _unbondNonce
) private {
IValidatorShare(_validatorShare).unstakeClaimTokens_new(_unbondNonce);
}
/// @notice API for delegated selling vouchers from validatorShare
/// @param _validatorShare - Address of validatorShare contract
/// @param _claimAmount - Amount of BONE to claim
/// @param _maximumSharesToBurn - Maximum amount of shares to burn
function sellVoucher_new(
address _validatorShare,
uint256 _claimAmount,
uint256 _maximumSharesToBurn
) private {
IValidatorShare(_validatorShare).sellVoucher_new(
_claimAmount,
_maximumSharesToBurn
);
}
/// @notice API for getting total stake of this contract from validatorShare
/// @param _validatorShare - Address of validatorShare contract
/// @return Total stake of this contract and BONE -> share exchange rate
function getTotalStake(IValidatorShare _validatorShare)
public
view
returns (uint256, uint256)
{
return _validatorShare.getTotalStake(address(this));
}
/// @notice API for liquid rewards of this contract from validatorShare
/// @param _validatorShare - Address of validatorShare contract
/// @return Liquid rewards of this contract
function getLiquidRewards(IValidatorShare _validatorShare)
external
view
returns (uint256)
{
return _validatorShare.getLiquidRewards(address(this));
}
////////////////////////////////////////////////////////////
///// ///
///// ***Helpers & Utilities*** ///
///// ///
////////////////////////////////////////////////////////////
/// @notice Helper function for that returns total pooled BONE
/// @return Total pooled BONE
function getTotalStakeAcrossAllValidators()
public
view
returns (uint256)
{
uint256 totalStake;
INodeOperatorRegistry.ValidatorData[] memory nodeOperators = nodeOperatorRegistry.listWithdrawNodeOperators();
for (uint256 i = 0; i < nodeOperators.length; i++) {
(uint256 currValidatorShare, ) = getTotalStake(
IValidatorShare(nodeOperators[i].validatorShare)
);
totalStake += currValidatorShare;
}
return totalStake;
}
/// @notice Function that calculates total pooled BONE
/// @return Total pooled BONE
function getTotalPooledBONE() public view returns (uint256) {
uint256 totalStaked = getTotalStakeAcrossAllValidators();
return _getTotalPooledBONE(totalStaked);
}
function _getTotalPooledBONE(uint256 _totalStaked)
private
view
returns (uint256)
{
return
_totalStaked +
totalBuffered +
calculatePendingBufferedTokens() -
reservedFunds;
}
/// @notice Function that converts arbitrary knBONE to BONE
/// @param _amountInKnBONE - Amount of knBONE to convert to BONE
/// @return amountInBONE - Amount of BONE after conversion,
/// @return totalKnBONEAmount - Total knBONE in the contract,
/// @return totalPooledBONE - Total BONE in the staking pool
function convertKnBONEToBONE(uint256 _amountInKnBONE)
external
view
returns (
uint256 amountInBONE,
uint256 totalKnBONEAmount,
uint256 totalPooledBONE
)
{
totalKnBONEAmount = totalSupply();
uint256 _totalPooledBONE = getTotalPooledBONE();
return (
_convertKnBONEToBONE(_amountInKnBONE, _totalPooledBONE),
totalKnBONEAmount,
_totalPooledBONE
);
}
/// @notice Function that converts arbitrary amount of knBONE to BONE
/// @param _knBONEAmount - amount of knBONE to convert to BONE
/// @return amountInBONE, totalKnBONEAmount and totalPooledBONE
function _convertKnBONEToBONE(
uint256 _knBONEAmount,
uint256 _totalPooledBONE
) private view returns (uint256) {
uint256 totalKnBONESupply = totalSupply();
totalKnBONESupply = totalKnBONESupply == 0 ? 1 : totalKnBONESupply;
_totalPooledBONE = _totalPooledBONE == 0 ? 1 : _totalPooledBONE;
uint256 amountInBONE = (_knBONEAmount * _totalPooledBONE) /
totalKnBONESupply;
return amountInBONE;
}
/// @notice Function that converts arbitrary BONE to knBONE
/// @param _amountInBONE - Amount of BONE to convert to knBONE
/// @return amountInKnBONE - Amount of BONE to converted to knBONE
/// @return totalKnBONESupply - Total amount of knBONE in the contract
/// @return totalPooledBONE - Total amount of BONE in the staking pool
function convertBONEToKnBONE(uint256 _amountInBONE)
public
view
returns (
uint256 amountInKnBONE,
uint256 totalKnBONESupply,
uint256 totalPooledBONE
)
{
totalKnBONESupply = totalSupply();
totalPooledBONE = getTotalPooledBONE();
return (
_convertBONEToKnBONE(_amountInBONE, totalPooledBONE),
totalKnBONESupply,
totalPooledBONE
);
}
function getToken2WithdrawRequests(uint256 _tokenId)
external
view
returns (RequestWithdraw[] memory)
{
return token2WithdrawRequests[_tokenId];
}
/// @notice Function that converts arbitrary amount of BONE to knBONE
/// @param _BONEAmount - Amount in BONE to convert to knBONE
/// @return amountInKnBONE , totalKnBONEAmount and totalPooledBONE
function _convertBONEToKnBONE(
uint256 _BONEAmount,
uint256 _totalPooledBONE
) private view returns (uint256) {
uint256 totalKnBONESupply = totalSupply();
totalKnBONESupply = totalKnBONESupply == 0 ? 1 : totalKnBONESupply;
_totalPooledBONE = _totalPooledBONE == 0 ? 1 : _totalPooledBONE;
uint256 amountInKnBONE = (_BONEAmount * totalKnBONESupply) /
_totalPooledBONE;
return amountInKnBONE;
}
////////////////////////////////////////////////////////////
///// ///
///// ***Setters*** ///
///// ///
////////////////////////////////////////////////////////////
/// @notice Function that sets entity fees
/// @notice Callable only by dao
/// @param _daoFee - DAO fee in %
/// @param _operatorsFee - Operator fees in %
/// @param _instantPoolFee - Instant pool fee in %
/// @param _stakingFee - L2 staking fee in %
function setFees(
uint8 _daoFee,
uint8 _operatorsFee,
uint8 _instantPoolFee,
uint8 _stakingFee
) external onlyRole(DAO_ROLE) {
require(
_daoFee + _operatorsFee + _instantPoolFee + _stakingFee == 100,
"sum(fee)!=100"
);
entityFees.dao = _daoFee;
entityFees.operators = _operatorsFee;
entityFees.instantPool = _instantPoolFee;
entityFees.staking = _stakingFee;
emit SetFees(_daoFee, _operatorsFee, _instantPoolFee, _stakingFee);
}
/// @notice Function that sets protocol fee
/// @param _newProtocolFee new protocol fee
function setProtocolFee(uint8 _newProtocolFee)
external
onlyRole(DAO_ROLE)
{
require(
_newProtocolFee > 0 && _newProtocolFee <= 100,
"Invalid protcol fee"
);
uint8 oldProtocolFee = protocolFee;
protocolFee = _newProtocolFee;
emit SetProtocolFee(oldProtocolFee, _newProtocolFee);
}
/// @notice Function that sets instant pool usage fee
/// @param _instantPoolUsageFee new instant pool usage fee
function setInstantPoolUsageFee(uint256 _instantPoolUsageFee) external onlyRole(DAO_ROLE) {
require(_instantPoolUsageFee <= 100, "Fee percentage exceeds 100");
uint256 oldInstantPoolUsageFee = instantPoolUsageFee;
instantPoolUsageFee = _instantPoolUsageFee;
emit SetInstantPoolUsageFee(oldInstantPoolUsageFee, _instantPoolUsageFee);
}
/// @notice Function that sets new dao address
/// @notice Callable only by dao
/// @param _newDAO - New dao address
function setDaoAddress(address _newDAO) external onlyRole(DAO_ROLE) {
address oldDAO = dao;
dao = _newDAO;
emit SetDaoAddress(oldDAO, _newDAO);
}
/// @notice Function that sets new node operator address
/// @notice Only callable by dao
/// @param _address - New node operator address
function setNodeOperatorRegistryAddress(address _address)
external
onlyRole(DAO_ROLE)
{
nodeOperatorRegistry = INodeOperatorRegistry(_address);
emit SetNodeOperatorRegistryAddress(_address);
}
/// @notice Function that sets new instant pool address
/// @notice Only callable by dao
/// @param _instantPool - New instant pool address
function setInstantPool(IInstantPool _instantPool) external onlyRole(DAO_ROLE) {
require(address(_instantPool) != address(0), "Cannot set zero address");
instantPool = _instantPool;
emit SetInstantPool(address(_instantPool));
}
/// @notice Function that sets new deposit manager address
/// @notice Only callable by dao
/// @param _depositManager - New deposit manager address
function setDepositManager(IDepositManager _depositManager) external onlyRole(DAO_ROLE) {
require(address(_depositManager) != address(0), "Cannot set zero address");
depositManager = _depositManager;
emit SetDepositManager(address(_depositManager));
}
/// @notice Function that sets new bridge address
/// @notice Only callable by dao
/// @param _bridge - New bridge address
function setBridge(IBridgeETH _bridge) external onlyRole(DAO_ROLE) {
bridge = _bridge;
emit SetBridge(address(_bridge));
}
/// @notice Function that sets new L2 staking address
/// @notice Only callable by dao
/// @param _l2Staking - New L2 staking address
function setL2Staking(address _l2Staking) external onlyRole(DAO_ROLE) {
l2Staking = _l2Staking;
emit SetL2Staking(_l2Staking);
}
/// @notice Function that sets new lower bound for delegation
/// @notice Only callable by dao
/// @param _delegationLowerBound - New lower bound for delegation
function setDelegationLowerBound(uint256 _delegationLowerBound)
external
onlyRole(DAO_ROLE)
{
delegationLowerBound = _delegationLowerBound;
emit SetDelegationLowerBound(_delegationLowerBound);
}
/// @notice Function that sets new lower bound for rewards distribution
/// @notice Only callable by dao
/// @param _newRewardDistributionLowerBound - New lower bound for rewards distribution
function setRewardDistributionLowerBound(
uint256 _newRewardDistributionLowerBound
) external onlyRole(DAO_ROLE) {
uint256 oldRewardDistributionLowerBound = rewardDistributionLowerBound;
rewardDistributionLowerBound = _newRewardDistributionLowerBound;
emit SetRewardDistributionLowerBound(
oldRewardDistributionLowerBound,
_newRewardDistributionLowerBound
);
}
/// @notice Function that sets the unstBONE address
/// @param _newUnstBONE new _newUnstBONE address
function setUnstBONE(address _newUnstBONE) external onlyRole(DAO_ROLE) {
address oldUnstBONE = address(unstBONE);
unstBONE = IUnstBONE(_newUnstBONE);
emit SetUnstBONE(oldUnstBONE, _newUnstBONE);
}
/// @notice Function that retrieves the amount of BONE that will be claimed from the NFT token
/// @param _tokenId - Id of the unstBONE
function getBONEFromTokenId(uint256 _tokenId)
external
view
returns (uint256)
{
if (token2WithdrawRequests[_tokenId].length != 0) {
RequestWithdraw[] memory requestsData = token2WithdrawRequests[
_tokenId
];
uint256 totalBONE;
for (uint256 idx = 0; idx < requestsData.length; idx++) {
totalBONE += _getBONEFromRequestData(requestsData[idx]);
}
return totalBONE;
}
return 0;
}
function _getBONEFromRequestData(RequestWithdraw memory requestData)
private
view
returns (uint256)
{
if (requestData.validatorAddress == address(0)) {
return requestData.amount2WithdrawFromKnBONE;
}
IValidatorShare validatorShare = IValidatorShare(
requestData.validatorAddress
);
uint256 exchangeRatePrecision = _getExchangeRatePrecision(
validatorShare.validatorId()
);
uint256 withdrawExchangeRate = validatorShare.withdrawExchangeRate();
IValidatorShare.DelegatorUnbond memory unbond = validatorShare
.unbonds_new(address(this), requestData.validatorNonce);
return (withdrawExchangeRate * unbond.shares) / exchangeRatePrecision;
}
function _nonReentrant() private view {
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
}
/// @dev get the exchange rate precision per validator.
/// More details: https://github.com/maticnetwork/contracts/blob/v0.3.0-backport/contracts/staking/validatorShare/ValidatorShare.sol#L21
/// https://github.com/maticnetwork/contracts/blob/v0.3.0-backport/contracts/staking/validatorShare/ValidatorShare.sol#L87
function _getExchangeRatePrecision(uint256 _validatorId)
private
pure
returns (uint256)
{
return _validatorId < 8 ? 100 : 10**29;
}
/// @dev calculate the number of shares to get when delegate an amount of BONE
function _calculateValidatorShares(
address _validatorAddress,
uint256 _amountInBONE
) private view returns (uint256) {
IValidatorShare validatorShare = IValidatorShare(_validatorAddress);
uint256 exchangeRatePrecision = _getExchangeRatePrecision(
validatorShare.validatorId()
);
uint256 rate = validatorShare.exchangeRate();
return (_amountInBONE * exchangeRatePrecision) / rate;
}
function min(uint256 _valueA, uint256 _valueB) private pure returns(uint256) {
return _valueA > _valueB ? _valueB : _valueA;
}
}
IKnBONE.sol 165 lines
// The following code is based on the Shardlabs' source code of Lido for Polygon
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.25;
import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
interface IKnBONE is IERC20Upgradeable {
/// @notice The request withdraw struct.
/// @param amount2WithdrawFromKnBONE amount in BONE.
/// @param validatorNonce validator nonce.
/// @param requestEpoch request epoch.
/// @param validatorAddress validator share address.
struct RequestWithdraw {
uint256 amount2WithdrawFromKnBONE;
uint256 validatorNonce;
uint256 requestEpoch;
address validatorAddress;
}
/// @notice The fee distribution struct.
/// @param dao dao fee.
/// @param operators operators fee.
/// @param instantPool instant pool fee.
/// @param staking L2 staking fee.
struct FeeDistribution {
uint8 dao;
uint8 operators;
uint8 instantPool;
uint8 staking;
}
function requestWithdrawSplit(uint256 _instantPoolAmount, uint256 _requestWithdrawAmount, address _user) external returns(uint256);
function withdrawTotalDelegated(address _validatorShare) external;
////////////////////////////////////////////////////////////
///// ///
///// ***EVENTS*** ///
///// ///
////////////////////////////////////////////////////////////
/// @notice Emit when submit.
/// @param _from msg.sender.
/// @param _amount amount.
/// @param _receiver receiver address.
/// @param _transferToL2 whether or not transfer to L2 was done.
event SubmitEvent(address indexed _from, uint256 _amount, address indexed _receiver, bool _transferToL2);
/// @notice Emits when instant pool is used.
/// @param _from user to withdraw,
/// @param _amountWithFeeInBONE total amount to withdraw in BONE.
/// @param _feeAmountInBONE fee amount in BONE.
event InstantPoolWithdraw(address indexed _from, uint256 _amountWithFeeInBONE, uint256 _feeAmountInBONE);
/// @notice Emit when request withdraw.
/// @param _from user to withdraw.
/// @param _amountInBONE amount in BONE.
event RequestWithdrawEvent(address indexed _from, uint256 _amountInBONE);
/// @notice Emits when any kind of withdraw is done.
/// @param _from user to withdraw.
/// @param _totalAmountInKnBONE total amount to withdraw in knBONE.
event RequestWithdrawSplit(address indexed _from, uint256 _totalAmountInKnBONE);
/// @notice Emit when distribute rewards.
/// @param _amount amount distributed.
/// @param totalPooledBefore totalPooled variable at the start of transaction.
/// @param totalPooledAfter totalPooled varable at the end of transaction.
event DistributeRewardsEvent(uint256 indexed _amount, uint256 indexed totalPooledBefore, uint256 indexed totalPooledAfter);
/// @notice Emit when withdraw total delegated.
/// @param _from msg.sender.
/// @param _amount amount.
event WithdrawTotalDelegatedEvent(
address indexed _from,
uint256 indexed _amount
);
/// @notice Emit when delegate.
/// @param _amountDelegated amount to delegate.
/// @param _remainder remainder.
event DelegateEvent(
uint256 indexed _amountDelegated,
uint256 indexed _remainder
);
/// @notice Emit when ClaimTokens.
/// @param _from msg.sender.
/// @param _id token id.
/// @param _amountClaimed amount Claimed.
event ClaimTokensEvent(
address indexed _from,
uint256 indexed _id,
uint256 indexed _amountClaimed
);
/// @notice Emit when set new NodeOperatorRegistryAddress.
/// @param _newNodeOperatorRegistryAddress the new NodeOperatorRegistryAddress.
event SetNodeOperatorRegistryAddress(
address indexed _newNodeOperatorRegistryAddress
);
/// @notice Emit when set new SetDelegationLowerBound.
/// @param _delegationLowerBound the old DelegationLowerBound.
event SetDelegationLowerBound(uint256 indexed _delegationLowerBound);
/// @notice Emit when set new RewardDistributionLowerBound.
/// @param oldRewardDistributionLowerBound the old RewardDistributionLowerBound.
/// @param newRewardDistributionLowerBound the new RewardDistributionLowerBound.
event SetRewardDistributionLowerBound(
uint256 oldRewardDistributionLowerBound,
uint256 newRewardDistributionLowerBound
);
/// @notice Emit when set new unstBONE.
/// @param oldUnstBONE the old unstBONE.
/// @param newUnstBONE the new unstBONE.
event SetUnstBONE(address oldUnstBONE, address newUnstBONE);
/// @notice Emit when set new DAO.
/// @param oldDaoAddress the old DAO.
/// @param newDaoAddress the new DAO.
event SetDaoAddress(address oldDaoAddress, address newDaoAddress);
/// @notice Emit when set fees.
/// @param daoFee the new daoFee
/// @param operatorsFee the new operatorsFee
/// @param instantPoolFee the new instantPoolFee
/// @param stakingFee the new stakingFee
event SetFees(uint256 daoFee, uint256 operatorsFee, uint256 instantPoolFee, uint256 stakingFee);
/// @notice Emit when set ProtocolFee.
/// @param oldProtocolFee the new ProtocolFee
/// @param newProtocolFee the new ProtocolFee
event SetProtocolFee(uint8 oldProtocolFee, uint8 newProtocolFee);
/// @notice Emits when instantPoolUsageFee is set.
/// @param oldInstantPoolUsageFee old instantPoolUsageFee
/// @param newInstantPoolUsageFee new instantPoolUsageFee
event SetInstantPoolUsageFee(uint256 oldInstantPoolUsageFee, uint256 newInstantPoolUsageFee);
/// @notice Emits when instantPool is set.
/// @param instantPool new instantPool
event SetInstantPool(address instantPool);
/// @notice Emits when depositManager is set.
/// @param depositManager new depositManager
event SetDepositManager(address depositManager);
/// @notice Emits when bridge is set.
/// @param bridge new bridge
event SetBridge(address bridge);
/// @notice Emits when l2Staking is set.
/// @param l2Staking new l2Staking
event SetL2Staking(address l2Staking);
/// @notice Emit when set ProtocolFee.
/// @param validatorShare vaidatorshare address.
/// @param amountClaimed amount claimed.
event ClaimTotalDelegatedEvent(
address indexed validatorShare,
uint256 indexed amountClaimed
);
}
IUnstBONE.sol 17 lines
// The following code is based on the Shardlabs' source code of Lido for Polygon
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.25;
import "@openzeppelin/contracts-upgradeable/token/ERC721/IERC721Upgradeable.sol";
interface IUnstBONE is IERC721Upgradeable {
function mint(address _to) external returns (uint256);
function burn(uint256 _tokenId) external;
function isApprovedOrOwner(address _spender, uint256 _tokenId)
external
view
returns (bool);
}
IBridgeETH.sol 6 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;
interface IBridgeETH {
function depositForUser(address _user, uint256 _amount) external;
}
IInstantPool.sol 8 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;
import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
interface IInstantPool {
function withdraw(IERC20Upgradeable token, address receiver, uint256 amount) external;
}
IStakeManager.sol 50 lines
// The following code is based on the Shardlabs' source code of Lido for Polygon
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.25;
interface IStakeManager {
/// @dev Polygon stakeManager status and Validator struct
/// https://github.com/maticnetwork/contracts/blob/v0.3.0-backport/contracts/staking/stakeManager/StakeManagerStorage.sol
enum Status {
Inactive,
Active,
Locked,
Unstaked
}
struct Validator {
uint256 amount;
uint256 reward;
uint256 activationEpoch;
uint256 deactivationEpoch;
uint256 jailTime;
address signer;
address contractAddress;
Status status;
uint256 commissionRate;
uint256 lastCommissionUpdate;
uint256 delegatorsReward;
uint256 delegatedAmount;
uint256 initialRewardPerStake;
}
function getValidatorContract(uint256 validatorId)
external
view
returns (address);
function delegationDeposit(
uint256 validatorId,
uint256 amount,
address delegator
) external returns (bool);
function epoch() external view returns (uint256);
function validators(uint256 _index)
external
view
returns (Validator memory);
function withdrawalDelay() external view returns (uint256);
}
IDepositManager.sol 6 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;
interface IDepositManager {
function depositERC20ForUser(address _token, address _user, uint256 _amount) external;
}
IValidatorShare.sol 71 lines
// The following code is based on the Shardlabs' source code of Lido for Polygon
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.25;
interface IValidatorShare {
struct DelegatorUnbond {
uint256 shares;
uint256 withdrawEpoch;
}
function unbondNonces(address _address) external view returns (uint256);
function activeAmount() external view returns (uint256);
function validatorId() external view returns (uint256);
function withdrawExchangeRate() external view returns (uint256);
function withdrawRewards() external;
function unstakeClaimTokens() external;
function minAmount() external view returns (uint256);
function getLiquidRewards(address user) external view returns (uint256);
function delegation() external view returns (bool);
function updateDelegation(bool _delegation) external;
function buyVoucher(uint256 _amount, uint256 _minSharesToMint)
external
returns (uint256);
function sellVoucher_new(uint256 claimAmount, uint256 maximumSharesToBurn)
external;
function unstakeClaimTokens_new(uint256 unbondNonce) external;
function unbonds_new(address _address, uint256 _unbondNonce)
external
view
returns (DelegatorUnbond memory);
function getTotalStake(address user)
external
view
returns (uint256, uint256);
function owner() external view returns (address);
function restake() external returns (uint256, uint256);
function unlock() external;
function lock() external;
function drain(
address token,
address payable destination,
uint256 amount
) external;
function slash(uint256 _amount) external;
function migrateOut(address user, uint256 amount) external;
function migrateIn(address user, uint256 amount) external;
function exchangeRate() external view returns (uint256);
}
INodeOperatorRegistry.sol 208 lines
// The following code is based on the Shardlabs' source code of Lido for Polygon
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.25;
interface INodeOperatorRegistry {
/// @notice Node Operator Registry Statuses
/// StakeManager statuses: https://github.com/maticnetwork/contracts/blob/v0.3.0-backport/contracts/staking/stakeManager/StakeManagerStorage.sol#L13
/// ACTIVE: (validator.status == status.Active && validator.deactivationEpoch == 0)
/// JAILED: (validator.status == status.Locked && validator.deactivationEpoch == 0)
/// EJECTED: ((validator.status == status.Active || validator.status == status.Locked) && validator.deactivationEpoch != 0)
/// UNSTAKED: (validator.status == status.Unstaked)
enum NodeOperatorRegistryStatus {
INACTIVE,
ACTIVE,
JAILED,
EJECTED,
UNSTAKED
}
/// @notice The full node operator struct.
/// @param validatorId the validator id on stakeManager.
/// @param commissionRate rate of each operator
/// @param validatorShare the validator share address of the validator.
/// @param rewardAddress the reward address.
/// @param delegation delegation.
/// @param status the status of the node operator in the stake manager.
struct FullNodeOperatorRegistry {
uint256 validatorId;
uint256 commissionRate;
address validatorShare;
address rewardAddress;
bool delegation;
NodeOperatorRegistryStatus status;
}
/// @notice The node operator struct
/// @param validatorShare the validator share address of the validator.
/// @param rewardAddress the reward address.
struct ValidatorData {
address validatorShare;
address rewardAddress;
}
function addNodeOperator(uint256 validatorId, address rewardAddress)
external;
function exitNodeOperatorRegistry() external;
function removeNodeOperator(uint256 validatorId) external;
function removeInvalidNodeOperator(uint256 validatorId) external;
function setKnBONEAddress(address newKnBONE) external;
function setRewardAddress(address newRewardAddress) external;
function setDistanceThreshold(uint256 distanceThreshold) external;
function setMinRequestWithdrawRange(uint8 minRequestWithdrawRange) external;
function setMaxWithdrawPercentagePerRebalance(
uint256 maxWithdrawPercentagePerRebalance
) external;
function listDelegatedNodeOperators()
external
view
returns (ValidatorData[] memory);
function listWithdrawNodeOperators()
external
view
returns (ValidatorData[] memory);
function getValidatorsDelegationAmount(uint256 amountToDelegate)
external
view
returns (
ValidatorData[] memory validators,
uint256[] memory operatorRatiosToDelegate,
uint256 totalRatio
);
function getValidatorsRebalanceAmount(uint256 totalBuffered)
external
view
returns (
ValidatorData[] memory validators,
uint256[] memory operatorRatiosToRebalance,
uint256 totalRatio,
uint256 totalToWithdraw
);
function getValidatorsRequestWithdraw(uint256 _withdrawAmount)
external
view
returns (
ValidatorData[] memory validators,
uint256 totalDelegated,
uint256[] memory bigNodeOperatorIds,
uint256[] memory smallNodeOperatorIds,
uint256[] memory operatorAmountCanBeRequested,
uint256 totalValidatorToWithdrawFrom
);
function getNodeOperator(uint256 validatorId)
external
view
returns (FullNodeOperatorRegistry memory operatorStatus);
function getNodeOperator(address rewardAddress)
external
view
returns (FullNodeOperatorRegistry memory operatorStatus);
function getNodeOperatorStatus(uint256 validatorId)
external
view
returns (NodeOperatorRegistryStatus operatorStatus);
function getValidatorIds() external view returns (uint256[] memory);
function getProtocolStats()
external
view
returns (
bool isBalanced,
uint256 distanceThreshold,
uint256 minAmount,
uint256 maxAmount
);
function getStats()
external
view
returns (
uint256 inactiveNodeOperator,
uint256 activeNodeOperator,
uint256 jailedNodeOperator,
uint256 ejectedNodeOperator,
uint256 unstakedNodeOperator
);
////////////////////////////////////////////////////////////
///// ///
///// ***EVENTS*** ///
///// ///
////////////////////////////////////////////////////////////
/// @notice Add Node Operator event
/// @param validatorId validator id.
/// @param rewardAddress reward address.
event AddNodeOperator(uint256 validatorId, address rewardAddress);
/// @notice Remove Node Operator event.
/// @param validatorId validator id.
/// @param rewardAddress reward address.
event RemoveNodeOperator(uint256 validatorId, address rewardAddress);
/// @notice Remove Invalid Node Operator event.
/// @param validatorId validator id.
/// @param rewardAddress reward address.
event RemoveInvalidNodeOperator(uint256 validatorId, address rewardAddress);
/// @notice Set knBONE address event.
/// @param oldKnBONE old knBONE address.
/// @param newKnBONE new knBONE address.
event SetKnBONEAddress(address oldKnBONE, address newKnBONE);
/// @notice Set reward address event.
/// @param validatorId the validator id.
/// @param oldRewardAddress old reward address.
/// @param newRewardAddress new reward address.
event SetRewardAddress(
uint256 validatorId,
address oldRewardAddress,
address newRewardAddress
);
/// @notice Emit when the distance threshold is changed.
/// @param oldDistanceThreshold the old distance threshold.
/// @param newDistanceThreshold the new distance threshold.
event SetDistanceThreshold(
uint256 oldDistanceThreshold,
uint256 newDistanceThreshold
);
/// @notice Emit when the min request withdraw range is changed.
/// @param oldMinRequestWithdrawRange the old min request withdraw range.
/// @param newMinRequestWithdrawRange the new min request withdraw range.
event SetMinRequestWithdrawRange(
uint8 oldMinRequestWithdrawRange,
uint8 newMinRequestWithdrawRange
);
/// @notice Emit when the max withdraw percentage per rebalance is changed.
/// @param oldMaxWithdrawPercentagePerRebalance the old max withdraw percentage per rebalance.
/// @param newMaxWithdrawPercentagePerRebalance the new max withdraw percentage per rebalance.
event SetMaxWithdrawPercentagePerRebalance(
uint256 oldMaxWithdrawPercentagePerRebalance,
uint256 newMaxWithdrawPercentagePerRebalance
);
/// @notice Emit when the node operator exits the registry
/// @param validatorId node operator id
/// @param rewardAddress node operator reward address
event ExitNodeOperator(uint256 validatorId, address rewardAddress);
}
AddressUpgradeable.sol 195 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library AddressUpgradeable {
/**
* @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
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @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");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
ContextUpgradeable.sol 37 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
import "../proxy/utils/Initializable.sol";
/**
* @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 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.
*/
abstract contract ContextUpgradeable is Initializable {
function __Context_init() internal onlyInitializing {
}
function __Context_init_unchained() internal onlyInitializing {
}
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
/**
* This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[50] private __gap;
}
StringsUpgradeable.sol 67 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)
pragma solidity ^0.8.0;
/**
* @dev String operations.
*/
library StringsUpgradeable {
bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
// Inspired by OraclizeAPI's implementation - MIT licence
// https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol
if (value == 0) {
return "0";
}
uint256 temp = value;
uint256 digits;
while (temp != 0) {
digits++;
temp /= 10;
}
bytes memory buffer = new bytes(digits);
while (value != 0) {
digits -= 1;
buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
value /= 10;
}
return string(buffer);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
if (value == 0) {
return "0x00";
}
uint256 temp = value;
uint256 length = 0;
while (temp != 0) {
length++;
temp >>= 8;
}
return toHexString(value, length);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _HEX_SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
}
Initializable.sol 80 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.0;
import "../../utils/AddressUpgradeable.sol";
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To initialize the implementation contract, you can either invoke the
* initializer manually, or you can include a constructor to automatically mark it as initialized when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() initializer {}
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Indicates that the contract has been initialized.
*/
bool private _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private _initializing;
/**
* @dev Modifier to protect an initializer function from being invoked twice.
*/
modifier initializer() {
// If the contract is initializing we ignore whether _initialized is set in order to support multiple
// inheritance patterns, but we only do this in the context of a constructor, because in other contexts the
// contract may have been reentered.
require(_initializing ? _isConstructor() : !_initialized, "Initializable: contract is already initialized");
bool isTopLevelCall = !_initializing;
if (isTopLevelCall) {
_initializing = true;
_initialized = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
}
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} modifier, directly or indirectly.
*/
modifier onlyInitializing() {
require(_initializing, "Initializable: contract is not initializing");
_;
}
function _isConstructor() private view returns (bool) {
return !AddressUpgradeable.isContract(address(this));
}
}
PausableUpgradeable.sol 103 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (security/Pausable.sol)
pragma solidity ^0.8.0;
import "../utils/ContextUpgradeable.sol";
import "../proxy/utils/Initializable.sol";
/**
* @dev Contract module which allows children to implement an emergency stop
* mechanism that can be triggered by an authorized account.
*
* This module is used through inheritance. It will make available the
* modifiers `whenNotPaused` and `whenPaused`, which can be applied to
* the functions of your contract. Note that they will not be pausable by
* simply including this module, only once the modifiers are put in place.
*/
abstract contract PausableUpgradeable is Initializable, ContextUpgradeable {
/**
* @dev Emitted when the pause is triggered by `account`.
*/
event Paused(address account);
/**
* @dev Emitted when the pause is lifted by `account`.
*/
event Unpaused(address account);
bool private _paused;
/**
* @dev Initializes the contract in unpaused state.
*/
function __Pausable_init() internal onlyInitializing {
__Pausable_init_unchained();
}
function __Pausable_init_unchained() internal onlyInitializing {
_paused = false;
}
/**
* @dev Returns true if the contract is paused, and false otherwise.
*/
function paused() public view virtual returns (bool) {
return _paused;
}
/**
* @dev Modifier to make a function callable only when the contract is not paused.
*
* Requirements:
*
* - The contract must not be paused.
*/
modifier whenNotPaused() {
require(!paused(), "Pausable: paused");
_;
}
/**
* @dev Modifier to make a function callable only when the contract is paused.
*
* Requirements:
*
* - The contract must be paused.
*/
modifier whenPaused() {
require(paused(), "Pausable: not paused");
_;
}
/**
* @dev Triggers stopped state.
*
* Requirements:
*
* - The contract must not be paused.
*/
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
/**
* @dev Returns to normal state.
*
* Requirements:
*
* - The contract must be paused.
*/
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
/**
* This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}
ERC20Upgradeable.sol 395 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/ERC20.sol)
pragma solidity ^0.8.0;
import "./IERC20Upgradeable.sol";
import "./extensions/IERC20MetadataUpgradeable.sol";
import "../../utils/ContextUpgradeable.sol";
import "../../proxy/utils/Initializable.sol";
/**
* @dev Implementation of the {IERC20} interface.
*
* This implementation is agnostic to the way tokens are created. This means
* that a supply mechanism has to be added in a derived contract using {_mint}.
* For a generic mechanism see {ERC20PresetMinterPauser}.
*
* TIP: For a detailed writeup see our guide
* https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
* to implement supply mechanisms].
*
* We have followed general OpenZeppelin Contracts guidelines: functions revert
* instead returning `false` on failure. This behavior is nonetheless
* conventional and does not conflict with the expectations of ERC20
* applications.
*
* Additionally, an {Approval} event is emitted on calls to {transferFrom}.
* This allows applications to reconstruct the allowance for all accounts just
* by listening to said events. Other implementations of the EIP may not emit
* these events, as it isn't required by the specification.
*
* Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
* functions have been added to mitigate the well-known issues around setting
* allowances. See {IERC20-approve}.
*/
contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20Upgradeable, IERC20MetadataUpgradeable {
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
/**
* @dev Sets the values for {name} and {symbol}.
*
* The default value of {decimals} is 18. To select a different value for
* {decimals} you should overload it.
*
* All two of these values are immutable: they can only be set once during
* construction.
*/
function __ERC20_init(string memory name_, string memory symbol_) internal onlyInitializing {
__ERC20_init_unchained(name_, symbol_);
}
function __ERC20_init_unchained(string memory name_, string memory symbol_) internal onlyInitializing {
_name = name_;
_symbol = symbol_;
}
/**
* @dev Returns the name of the token.
*/
function name() public view virtual override returns (string memory) {
return _name;
}
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
/**
* @dev Returns the number of decimals used to get its user representation.
* For example, if `decimals` equals `2`, a balance of `505` tokens should
* be displayed to a user as `5.05` (`505 / 10 ** 2`).
*
* Tokens usually opt for a value of 18, imitating the relationship between
* Ether and Wei. This is the value {ERC20} uses, unless this function is
* overridden;
*
* NOTE: This information is only used for _display_ purposes: it in
* no way affects any of the arithmetic of the contract, including
* {IERC20-balanceOf} and {IERC20-transfer}.
*/
function decimals() public view virtual override returns (uint8) {
return 18;
}
/**
* @dev See {IERC20-totalSupply}.
*/
function totalSupply() public view virtual override returns (uint256) {
return _totalSupply;
}
/**
* @dev See {IERC20-balanceOf}.
*/
function balanceOf(address account) public view virtual override returns (uint256) {
return _balances[account];
}
/**
* @dev See {IERC20-transfer}.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - the caller must have a balance of at least `amount`.
*/
function transfer(address to, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_transfer(owner, to, amount);
return true;
}
/**
* @dev See {IERC20-allowance}.
*/
function allowance(address owner, address spender) public view virtual override returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*
* NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
* `transferFrom`. This is semantically equivalent to an infinite approval.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_approve(owner, spender, amount);
return true;
}
/**
* @dev See {IERC20-transferFrom}.
*
* Emits an {Approval} event indicating the updated allowance. This is not
* required by the EIP. See the note at the beginning of {ERC20}.
*
* NOTE: Does not update the allowance if the current allowance
* is the maximum `uint256`.
*
* Requirements:
*
* - `from` and `to` cannot be the zero address.
* - `from` must have a balance of at least `amount`.
* - the caller must have allowance for ``from``'s tokens of at least
* `amount`.
*/
function transferFrom(
address from,
address to,
uint256 amount
) public virtual override returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, amount);
_transfer(from, to, amount);
return true;
}
/**
* @dev Atomically increases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, _allowances[owner][spender] + addedValue);
return true;
}
/**
* @dev Atomically decreases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `spender` must have allowance for the caller of at least
* `subtractedValue`.
*/
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
address owner = _msgSender();
uint256 currentAllowance = _allowances[owner][spender];
require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
unchecked {
_approve(owner, spender, currentAllowance - subtractedValue);
}
return true;
}
/**
* @dev Moves `amount` of tokens from `sender` to `recipient`.
*
* This internal function is equivalent to {transfer}, and can be used to
* e.g. implement automatic token fees, slashing mechanisms, etc.
*
* Emits a {Transfer} event.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `from` must have a balance of at least `amount`.
*/
function _transfer(
address from,
address to,
uint256 amount
) internal virtual {
require(from != address(0), "ERC20: transfer from the zero address");
require(to != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(from, to, amount);
uint256 fromBalance = _balances[from];
require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
unchecked {
_balances[from] = fromBalance - amount;
}
_balances[to] += amount;
emit Transfer(from, to, amount);
_afterTokenTransfer(from, to, amount);
}
/** @dev Creates `amount` tokens and assigns them to `account`, increasing
* the total supply.
*
* Emits a {Transfer} event with `from` set to the zero address.
*
* Requirements:
*
* - `account` cannot be the zero address.
*/
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: mint to the zero address");
_beforeTokenTransfer(address(0), account, amount);
_totalSupply += amount;
_balances[account] += amount;
emit Transfer(address(0), account, amount);
_afterTokenTransfer(address(0), account, amount);
}
/**
* @dev Destroys `amount` tokens from `account`, reducing the
* total supply.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* Requirements:
*
* - `account` cannot be the zero address.
* - `account` must have at least `amount` tokens.
*/
function _burn(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: burn from the zero address");
_beforeTokenTransfer(account, address(0), amount);
uint256 accountBalance = _balances[account];
require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
unchecked {
_balances[account] = accountBalance - amount;
}
_totalSupply -= amount;
emit Transfer(account, address(0), amount);
_afterTokenTransfer(account, address(0), amount);
}
/**
* @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
*
* This internal function is equivalent to `approve`, and can be used to
* e.g. set automatic allowances for certain subsystems, etc.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `owner` cannot be the zero address.
* - `spender` cannot be the zero address.
*/
function _approve(
address owner,
address spender,
uint256 amount
) internal virtual {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
/**
* @dev Spend `amount` form the allowance of `owner` toward `spender`.
*
* Does not update the allowance amount in case of infinite allowance.
* Revert if not enough allowance is available.
*
* Might emit an {Approval} event.
*/
function _spendAllowance(
address owner,
address spender,
uint256 amount
) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
require(currentAllowance >= amount, "ERC20: insufficient allowance");
unchecked {
_approve(owner, spender, currentAllowance - amount);
}
}
}
/**
* @dev Hook that is called before any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* will be transferred to `to`.
* - when `from` is zero, `amount` tokens will be minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens will be burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _beforeTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual {}
/**
* @dev Hook that is called after any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* has been transferred to `to`.
* - when `from` is zero, `amount` tokens have been minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens have been burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _afterTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual {}
/**
* This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[45] private __gap;
}
IERC20Upgradeable.sol 82 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20Upgradeable {
/**
* @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 `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, 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 `from` to `to` 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 from,
address to,
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);
}
AccessControlUpgradeable.sol 236 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (access/AccessControl.sol)
pragma solidity ^0.8.0;
import "./IAccessControlUpgradeable.sol";
import "../utils/ContextUpgradeable.sol";
import "../utils/StringsUpgradeable.sol";
import "../utils/introspection/ERC165Upgradeable.sol";
import "../proxy/utils/Initializable.sol";
/**
* @dev Contract module that allows children to implement role-based access
* control mechanisms. This is a lightweight version that doesn't allow enumerating role
* members except through off-chain means by accessing the contract event logs. Some
* applications may benefit from on-chain enumerability, for those cases see
* {AccessControlEnumerable}.
*
* Roles are referred to by their `bytes32` identifier. These should be exposed
* in the external API and be unique. The best way to achieve this is by
* using `public constant` hash digests:
*
* ```
* bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
* ```
*
* Roles can be used to represent a set of permissions. To restrict access to a
* function call, use {hasRole}:
*
* ```
* function foo() public {
* require(hasRole(MY_ROLE, msg.sender));
* ...
* }
* ```
*
* Roles can be granted and revoked dynamically via the {grantRole} and
* {revokeRole} functions. Each role has an associated admin role, and only
* accounts that have a role's admin role can call {grantRole} and {revokeRole}.
*
* By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
* that only accounts with this role will be able to grant or revoke other
* roles. More complex role relationships can be created by using
* {_setRoleAdmin}.
*
* WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
* grant and revoke this role. Extra precautions should be taken to secure
* accounts that have been granted it.
*/
abstract contract AccessControlUpgradeable is Initializable, ContextUpgradeable, IAccessControlUpgradeable, ERC165Upgradeable {
function __AccessControl_init() internal onlyInitializing {
}
function __AccessControl_init_unchained() internal onlyInitializing {
}
struct RoleData {
mapping(address => bool) members;
bytes32 adminRole;
}
mapping(bytes32 => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
/**
* @dev Modifier that checks that an account has a specific role. Reverts
* with a standardized message including the required role.
*
* The format of the revert reason is given by the following regular expression:
*
* /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
*
* _Available since v4.1._
*/
modifier onlyRole(bytes32 role) {
_checkRole(role, _msgSender());
_;
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControlUpgradeable).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) public view virtual override returns (bool) {
return _roles[role].members[account];
}
/**
* @dev Revert with a standard message if `account` is missing `role`.
*
* The format of the revert reason is given by the following regular expression:
*
* /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
*/
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert(
string(
abi.encodePacked(
"AccessControl: account ",
StringsUpgradeable.toHexString(uint160(account), 20),
" is missing role ",
StringsUpgradeable.toHexString(uint256(role), 32)
)
)
);
}
}
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {
return _roles[role].adminRole;
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been revoked `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*/
function renounceRole(bytes32 role, address account) public virtual override {
require(account == _msgSender(), "AccessControl: can only renounce roles for self");
_revokeRole(role, account);
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event. Note that unlike {grantRole}, this function doesn't perform any
* checks on the calling account.
*
* [WARNING]
* ====
* This function should only be called from the constructor when setting
* up the initial roles for the system.
*
* Using this function in any other way is effectively circumventing the admin
* system imposed by {AccessControl}.
* ====
*
* NOTE: This function is deprecated in favor of {_grantRole}.
*/
function _setupRole(bytes32 role, address account) internal virtual {
_grantRole(role, account);
}
/**
* @dev Sets `adminRole` as ``role``'s admin role.
*
* Emits a {RoleAdminChanged} event.
*/
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
bytes32 previousAdminRole = getRoleAdmin(role);
_roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
/**
* @dev Grants `role` to `account`.
*
* Internal function without access restriction.
*/
function _grantRole(bytes32 role, address account) internal virtual {
if (!hasRole(role, account)) {
_roles[role].members[account] = true;
emit RoleGranted(role, account, _msgSender());
}
}
/**
* @dev Revokes `role` from `account`.
*
* Internal function without access restriction.
*/
function _revokeRole(bytes32 role, address account) internal virtual {
if (hasRole(role, account)) {
_roles[role].members[account] = false;
emit RoleRevoked(role, account, _msgSender());
}
}
/**
* This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}
IERC721Upgradeable.sol 143 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721.sol)
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165Upgradeable.sol";
/**
* @dev Required interface of an ERC721 compliant contract.
*/
interface IERC721Upgradeable is IERC165Upgradeable {
/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
*/
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
/**
* @dev Returns the number of tokens in ``owner``'s account.
*/
function balanceOf(address owner) external view returns (uint256 balance);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function ownerOf(uint256 tokenId) external view returns (address owner);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
* are aware of the ERC721 protocol to prevent tokens from being forever locked.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) external;
/**
* @dev Transfers `tokenId` token from `from` to `to`.
*
* WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address from,
address to,
uint256 tokenId
) external;
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account.
* The approval is cleared when the token is transferred.
*
* Only a single account can be approved at a time, so approving the zero address clears previous approvals.
*
* Requirements:
*
* - The caller must own the token or be an approved operator.
* - `tokenId` must exist.
*
* Emits an {Approval} event.
*/
function approve(address to, uint256 tokenId) external;
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function getApproved(uint256 tokenId) external view returns (address operator);
/**
* @dev Approve or remove `operator` as an operator for the caller.
* Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
*
* Requirements:
*
* - The `operator` cannot be the caller.
*
* Emits an {ApprovalForAll} event.
*/
function setApprovalForAll(address operator, bool _approved) external;
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}
*/
function isApprovedForAll(address owner, address operator) external view returns (bool);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes calldata data
) external;
}
IAccessControlUpgradeable.sol 88 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)
pragma solidity ^0.8.0;
/**
* @dev External interface of AccessControl declared to support ERC165 detection.
*/
interface IAccessControlUpgradeable {
/**
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
*
* `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
* {RoleAdminChanged} not being emitted signaling this.
*
* _Available since v3.1._
*/
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
/**
* @dev Emitted when `account` is granted `role`.
*
* `sender` is the account that originated the contract call, an admin role
* bearer except when using {AccessControl-_setupRole}.
*/
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Emitted when `account` is revoked `role`.
*
* `sender` is the account that originated the contract call:
* - if using `revokeRole`, it is the admin role bearer
* - if using `renounceRole`, it is the role bearer (i.e. `account`)
*/
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) external view returns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) external view returns (bytes32);
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been granted `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*/
function renounceRole(bytes32 role, address account) external;
}
ERC165Upgradeable.sol 42 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
pragma solidity ^0.8.0;
import "./IERC165Upgradeable.sol";
import "../../proxy/utils/Initializable.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/
abstract contract ERC165Upgradeable is Initializable, IERC165Upgradeable {
function __ERC165_init() internal onlyInitializing {
}
function __ERC165_init_unchained() internal onlyInitializing {
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165Upgradeable).interfaceId;
}
/**
* This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[50] private __gap;
}
SafeERC20Upgradeable.sol 99 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20Upgradeable.sol";
import "../../../utils/AddressUpgradeable.sol";
/**
* @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 IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20Upgradeable {
using AddressUpgradeable for address;
function safeTransfer(
IERC20Upgradeable token,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(
IERC20Upgradeable token,
address from,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(
IERC20Upgradeable 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'
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(
IERC20Upgradeable token,
address spender,
uint256 value
) internal {
uint256 newAllowance = token.allowance(address(this), spender) + value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(
IERC20Upgradeable token,
address spender,
uint256 value
) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
uint256 newAllowance = oldAllowance - value;
_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(IERC20Upgradeable 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. We use {Address.functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
// Return data is optional
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
IERC165Upgradeable.sol 25 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165Upgradeable {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
IERC20MetadataUpgradeable.sol 28 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.0;
import "../IERC20Upgradeable.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*
* _Available since v4.1._
*/
interface IERC20MetadataUpgradeable is IERC20Upgradeable {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}
Read Contract
BRIDGE_ROLE 0xb5bfddea → bytes32
DAO_ROLE 0xe9c26518 → bytes32
DEFAULT_ADMIN_ROLE 0xa217fddf → bytes32
PAUSE_ROLE 0x389ed267 → bytes32
UNPAUSE_ROLE 0x309756fb → bytes32
allowance 0xdd62ed3e → uint256
balanceOf 0x70a08231 → uint256
bridge 0xe78cea92 → address
calculatePendingBufferedTokens 0xafd290a7 → uint256
convertBONEToKnBONE 0x851a2844 → uint256, uint256, uint256
convertKnBONEToBONE 0x8523c175 → uint256, uint256, uint256
dao 0x4162169f → address
decimals 0x313ce567 → uint8
delegationLowerBound 0x0d7abc33 → uint256
depositManager 0x6c7ac9d8 → address
entityFees 0x964a7596 → uint8, uint8, uint8, uint8
getBONEFromTokenId 0x5f565815 → uint256
getLiquidRewards 0x676e5550 → uint256
getRoleAdmin 0x248a9ca3 → bytes32
getToken2WithdrawRequests 0x253d1735 → tuple[]
getTotalPooledBONE 0xb226dc96 → uint256
getTotalStake 0x1e7ff8f6 → uint256, uint256
getTotalStakeAcrossAllValidators 0x7e978af8 → uint256
getTotalWithdrawRequest 0x916b9eba → tuple[]
hasRole 0x91d14854 → bool
instantPool 0xac723707 → address
instantPoolUsageFee 0xb3bc19e0 → uint256
knBONEWithdrawRequest 0xb35e9aae → uint256, uint256, uint256, address
l2Staking 0x953a2f53 → address
name 0x06fdde03 → string
nodeOperatorRegistry 0xe8f8708f → address
paused 0x5c975abb → bool
protocolFee 0xb0e21e8a → uint8
reservedFunds 0x509c5df6 → uint256
rewardDistributionLowerBound 0xa2452947 → uint256
stakeManager 0x7542ff95 → address
supportsInterface 0x01ffc9a7 → bool
symbol 0x95d89b41 → string
token 0xfc0c546a → address
token2WithdrawRequests 0xc697d2c7 → uint256, uint256, uint256, address
totalBuffered 0x52349b17 → uint256
totalSupply 0x18160ddd → uint256
unstBONE 0xc30b47d7 → address
Write Contract 31 functions
These functions modify contract state and require a wallet transaction to execute.
approve 0x095ea7b3
address spender
uint256 amount
returns: bool
claimTokens 0x2d08265a
uint256[] _tokenId
claimTokensFromValidatorToContract 0x4cfeb862
uint256 _index
decreaseAllowance 0xa457c2d7
address spender
uint256 subtractedValue
returns: bool
delegate 0xc89e4361
No parameters
distributeRewards 0x6f4a2cd0
No parameters
grantRole 0x2f2ff15d
bytes32 role
address account
increaseAllowance 0x39509351
address spender
uint256 addedValue
returns: bool
initialize 0xf5e95acb
address _nodeOperatorRegistry
address _token
address _dao
address _stakeManager
address _unstBONE
address _instantPool
address _depositManager
address _bridge
address _l2Staking
pause 0x8456cb59
No parameters
rebalanceDelegatedTokens 0xd280f14f
No parameters
renounceRole 0x36568abe
bytes32 role
address account
requestWithdrawSplit 0xe5a3a147
uint256 _instantPoolAmount
uint256 _requestWithdrawAmount
address _user
returns: uint256
revokeRole 0xd547741f
bytes32 role
address account
setBridge 0x8dd14802
address _bridge
setDaoAddress 0x9a3cac6a
address _newDAO
setDelegationLowerBound 0x7682c902
uint256 _delegationLowerBound
setDepositManager 0x228d71a9
address _depositManager
setFees 0x9faa7cfd
uint8 _daoFee
uint8 _operatorsFee
uint8 _instantPoolFee
uint8 _stakingFee
setInstantPool 0x848f1513
address _instantPool
setInstantPoolUsageFee 0x8c1d4082
uint256 _instantPoolUsageFee
setL2Staking 0x63c2a36a
address _l2Staking
setNodeOperatorRegistryAddress 0x0f2b2639
address _address
setProtocolFee 0x4e91f811
uint8 _newProtocolFee
setRewardDistributionLowerBound 0x3b573c4a
uint256 _newRewardDistributionLowerBound
setUnstBONE 0x57b2acbd
address _newUnstBONE
submit 0x5512e592
uint256 _amount
address _receiver
bool _transferToL2
returns: uint256
transfer 0xa9059cbb
address to
uint256 amount
returns: bool
transferFrom 0x23b872dd
address from
address to
uint256 amount
returns: bool
unpause 0x3f4ba83a
No parameters
withdrawTotalDelegated 0xc75e7832
address _validatorShare
Recent Transactions
No transactions found for this address