{"constructor_args":"0x000000000000000000000000967c84b731679e36a344002b8e3ce50620a7f69f0000000000000000000000005684a06cab22db16d901fee2a5c081b4c91ea40e000000000000000000000000924f5ad34698fd20c90fe5d5a8a0abd3b42dc71100000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000046","is_partially_verified":true,"is_changed_bytecode":false,"abi":[{"inputs":[{"internalType":"address","name":"timelock_","type":"address"},{"internalType":"address","name":"staking_","type":"address"},{"internalType":"address","name":"guardian_","type":"address"},{"internalType":"uint96","name":"_quorumPercentageVotes","type":"uint96"},{"internalType":"uint96","name":"_majorityPercentageVotes","type":"uint96"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"}],"name":"ProposalCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"address","name":"proposer","type":"address"},{"indexed":false,"internalType":"address[]","name":"targets","type":"address[]"},{"indexed":false,"internalType":"uint256[]","name":"values","type":"uint256[]"},{"indexed":false,"internalType":"string[]","name":"signatures","type":"string[]"},{"indexed":false,"internalType":"bytes[]","name":"calldatas","type":"bytes[]"},{"indexed":false,"internalType":"uint256","name":"startBlock","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"endBlock","type":"uint256"},{"indexed":false,"internalType":"string","name":"description","type":"string"}],"name":"ProposalCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"}],"name":"ProposalExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"eta","type":"uint256"}],"name":"ProposalQueued","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"voter","type":"address"},{"indexed":false,"internalType":"uint256","name":"proposalId","type":"uint256"},{"indexed":false,"internalType":"bool","name":"support","type":"bool"},{"indexed":false,"internalType":"uint256","name":"votes","type":"uint256"}],"name":"VoteCast","type":"event"},{"constant":true,"inputs":[],"name":"BALLOT_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"DOMAIN_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"NAME","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"__abdicate","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"__acceptAdmin","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"newPendingAdmin","type":"address"},{"internalType":"uint256","name":"eta","type":"uint256"}],"name":"__executeSetTimelockPendingAdmin","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"newPendingAdmin","type":"address"},{"internalType":"uint256","name":"eta","type":"uint256"}],"name":"__queueSetTimelockPendingAdmin","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"proposalId","type":"uint256"}],"name":"cancel","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"proposalId","type":"uint256"},{"internalType":"bool","name":"support","type":"bool"}],"name":"castVote","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"proposalId","type":"uint256"},{"internalType":"bool","name":"support","type":"bool"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"castVoteBySig","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"proposalId","type":"uint256"}],"name":"execute","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"proposalId","type":"uint256"}],"name":"getActions","outputs":[{"internalType":"address[]","name":"targets","type":"address[]"},{"internalType":"uint256[]","name":"values","type":"uint256[]"},{"internalType":"string[]","name":"signatures","type":"string[]"},{"internalType":"bytes[]","name":"calldatas","type":"bytes[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"proposalId","type":"uint256"},{"internalType":"address","name":"voter","type":"address"}],"name":"getReceipt","outputs":[{"components":[{"internalType":"bool","name":"hasVoted","type":"bool"},{"internalType":"bool","name":"support","type":"bool"},{"internalType":"uint96","name":"votes","type":"uint96"}],"internalType":"struct GovernorAlpha.Receipt","name":"","type":"tuple"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"guardian","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"latestProposalIds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"majorityPercentageVotes","outputs":[{"internalType":"uint96","name":"","type":"uint96"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"proposalCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"proposalMaxOperations","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"proposalThreshold","outputs":[{"internalType":"uint96","name":"","type":"uint96"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"proposals","outputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint32","name":"startBlock","type":"uint32"},{"internalType":"uint32","name":"endBlock","type":"uint32"},{"internalType":"uint96","name":"forVotes","type":"uint96"},{"internalType":"uint96","name":"againstVotes","type":"uint96"},{"internalType":"uint96","name":"quorum","type":"uint96"},{"internalType":"uint96","name":"majorityPercentage","type":"uint96"},{"internalType":"uint64","name":"eta","type":"uint64"},{"internalType":"uint64","name":"startTime","type":"uint64"},{"internalType":"bool","name":"canceled","type":"bool"},{"internalType":"bool","name":"executed","type":"bool"},{"internalType":"address","name":"proposer","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address[]","name":"targets","type":"address[]"},{"internalType":"uint256[]","name":"values","type":"uint256[]"},{"internalType":"string[]","name":"signatures","type":"string[]"},{"internalType":"bytes[]","name":"calldatas","type":"bytes[]"},{"internalType":"string","name":"description","type":"string"}],"name":"propose","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"proposalId","type":"uint256"}],"name":"queue","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"quorumPercentageVotes","outputs":[{"internalType":"uint96","name":"","type":"uint96"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"quorumVotes","outputs":[{"internalType":"uint96","name":"","type":"uint96"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"staking","outputs":[{"internalType":"contract IStaking","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"proposalId","type":"uint256"}],"name":"state","outputs":[{"internalType":"enum GovernorAlpha.ProposalState","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"timelock","outputs":[{"internalType":"contract ITimelock","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"votingDelay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"votingPeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"}],"conflicting_implementations":null,"certified":false,"additional_sources":[],"is_verified_via_sourcify":false,"can_be_visualized_via_sol2uml":true,"evm_version":"default","language":"solidity","is_verified_via_eth_bytecode_db":true,"is_fully_verified":false,"license_type":"none","is_blueprint":false,"name":"GovernorAlpha","creation_bytecode":"0x60806040523480156200001157600080fd5b50604051620044ee380380620044ee8339810160408190526200003491620000de565b600080546001600160a01b03199081166001600160a01b039788161790915560018054821695871695909517909455600280549094169290941691909117909155600480546001600160601b0319166001600160601b0392831617600160601b600160c01b0319166c010000000000000000000000009290931691909102919091179055620001a1565b8051620000cb816200017c565b92915050565b8051620000cb8162000196565b600080600080600060a08688031215620000f757600080fd5b6000620001058888620000be565b95505060206200011888828901620000be565b94505060406200012b88828901620000be565b93505060606200013e88828901620000d1565b92505060806200015188828901620000d1565b9150509295509295909350565b60006001600160a01b038216620000cb565b6001600160601b031690565b62000187816200015e565b81146200019357600080fd5b50565b620001878162000170565b61433d80620001b16000396000f3fe6080604052600436106101c25760003560e01c8063760fbc13116100f7578063d33219b411610095578063deaaa7cc11610064578063deaaa7cc146104ce578063e23a9a52146104e3578063e265379014610510578063fe0d94c114610525576101c2565b8063d33219b414610464578063da35c66414610479578063da95691a1461048e578063ddf0b009146104ae576101c2565b8063a3f4df7e116100d1578063a3f4df7e14610403578063b2b0d91f14610425578063b58131b01461043a578063b9a619611461044f576101c2565b8063760fbc13146103b95780637bdbe4d0146103ce57806391500671146103e3576101c2565b8063328dd9821161016457806340e58ee51161013e57806340e58ee514610335578063452a9320146103555780634634c61f146103775780634cf088d914610397576101c2565b8063328dd982146102c35780633932abb1146102f35780633e4f49e614610308576101c2565b806317977c61116101a057806317977c611461024c57806320606b701461026c57806321f43e421461028157806324bc1a64146102a1576101c2565b8063013cf08b146101c757806302a251a31461020857806315373e3d1461022a575b600080fd5b3480156101d357600080fd5b506101e76101e2366004612c28565b610538565b6040516101ff9c9b9a99989796959493929190613e01565b60405180910390f35b34801561021457600080fd5b5061021d6105d8565b6040516101ff9190613b13565b34801561023657600080fd5b5061024a610245366004612c76565b6105df565b005b34801561025857600080fd5b5061021d610267366004612a71565b6105ee565b34801561027857600080fd5b5061021d610600565b34801561028d57600080fd5b5061024a61029c366004612a97565b610617565b3480156102ad57600080fd5b506102b66106fe565b6040516101ff9190613ec2565b3480156102cf57600080fd5b506102e36102de366004612c28565b610805565b6040516101ff9493929190613ac6565b3480156102ff57600080fd5b5061021d610a94565b34801561031457600080fd5b50610328610323366004612c28565b610a99565b6040516101ff9190613bc1565b34801561034157600080fd5b5061024a610350366004612c28565b610d21565b34801561036157600080fd5b5061036a610ef9565b6040516101ff919061393a565b34801561038357600080fd5b5061024a610392366004612ca6565b610f08565b3480156103a357600080fd5b506103ac61109b565b6040516101ff9190613bb3565b3480156103c557600080fd5b5061024a6110aa565b3480156103da57600080fd5b5061021d6110e6565b3480156103ef57600080fd5b5061024a6103fe366004612a97565b6110eb565b34801561040f57600080fd5b506104186111c0565b6040516101ff9190613bcf565b34801561043157600080fd5b506102b66111f1565b34801561044657600080fd5b506102b6611200565b34801561045b57600080fd5b5061024a6112cd565b34801561047057600080fd5b506103ac611352565b34801561048557600080fd5b5061021d611361565b34801561049a57600080fd5b5061021d6104a9366004612ad1565b611367565b3480156104ba57600080fd5b5061024a6104c9366004612c28565b6119ee565b3480156104da57600080fd5b5061021d611c9e565b3480156104ef57600080fd5b506105036104fe366004612c46565b611caa565b6040516101ff9190613d30565b34801561051c57600080fd5b506102b6611d19565b61024a610533366004612c28565b611d2f565b6005602052600090815260409020805460018201546002830154600390930154919263ffffffff808316936401000000008404909116926001600160601b03600160401b808304821694600160a01b90930482169383831693600160601b8104909316926001600160401b03600160c01b9091048116929082169160ff918104821691600160481b820416906001600160a01b03600160501b909104168c565b610b405b90565b6105ea338383611f11565b5050565b60066020526000908152604090205481565b60405161060c90613924565b604051809103902081565b6002546001600160a01b0316331461064a5760405162461bcd60e51b815260040161064190613c10565b60405180910390fd5b600080546040516001600160a01b0390911691630825f38f9183919061067490879060200161393a565b604051602081830303815290604052856040518563ffffffff1660e01b81526004016106a39493929190613970565b600060405180830381600087803b1580156106bd57600080fd5b505af11580156106d1573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526106f99190810190612bf4565b505050565b600080600160009054906101000a90046001600160a01b03166001600160a01b0316632522d7ba61074a600143036040518060600160405280603181526020016141446031913961217c565b426040518363ffffffff1660e01b8152600401610768929190613eb4565b60206040518083038186803b15801561078057600080fd5b505afa158015610794573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506107b89190810190612d0e565b600454604080516060810190915260328082529293506064926107ee926001600160601b031691859161417560208301396121ac565b6001600160601b0316816107fe57fe5b0491505090565b6060806060806000600560008781526020019081526020016000209050806004018160050182600601836007018380548060200260200160405190810160405280929190818152602001828054801561088757602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610869575b50505050509350828054806020026020016040519081016040528092919081815260200182805480156108d957602002820191906000526020600020905b8154815260200190600101908083116108c5575b5050505050925081805480602002602001604051908101604052809291908181526020016000905b828210156109ac5760008481526020908190208301805460408051601f60026000196101006001871615020190941693909304928301859004850281018501909152818152928301828280156109985780601f1061096d57610100808354040283529160200191610998565b820191906000526020600020905b81548152906001019060200180831161097b57829003601f168201915b505050505081526020019060010190610901565b50505050915080805480602002602001604051908101604052809291908181526020016000905b82821015610a7e5760008481526020908190208301805460408051601f6002600019610100600187161502019094169390930492830185900485028101850190915281815292830182828015610a6a5780601f10610a3f57610100808354040283529160200191610a6a565b820191906000526020600020905b815481529060010190602001808311610a4d57829003601f168201915b5050505050815260200190600101906109d3565b5050505090509450945094509450509193509193565b600190565b60008160035410158015610aad5750600082115b610ac95760405162461bcd60e51b815260040161064190613c20565b60008281526005602052604090206003810154600160401b900460ff1615610af5576002915050610d1c565b600181015463ffffffff164311610b10576000915050610d1c565b6001810154640100000000900463ffffffff164311610b33576001915050610d1c565b600181015460408051606081019091526037808252600092610b78926001600160601b03600160401b8304811693600160a01b90930416916141c96020830139612215565b90506000610ba082606460405180606001604052806025815260200161424260259139612248565b9050610bda816004600c9054906101000a90046001600160601b03166040518060600160405280603f81526020016140ad603f91396121ac565b60018401549091506001600160601b03808316600160401b90920416111580610c13575060028301546001600160601b03908116908316105b15610c245760039350505050610d1c565b6002830154600160c01b90046001600160401b0316610c495760049350505050610d1c565b6003830154600160481b900460ff1615610c695760079350505050610d1c565b6002830154600054604080516360d143f160e11b81529051610d0293600160c01b90046001600160401b0316926001600160a01b03169163c1a287e2916004808301926020929190829003018186803b158015610cc557600080fd5b505afa158015610cd9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610cfd9190810190612bd6565b61229a565b4210610d145760069350505050610d1c565b600593505050505b919050565b6000610d2c82610a99565b90506007816007811115610d3c57fe5b1415610d5a5760405162461bcd60e51b815260040161064190613cf0565b60008281526005602052604090206002546001600160a01b03163314610d925760405162461bcd60e51b815260040161064190613c90565b60038101805468ff00000000000000001916600160401b17905560005b6004820154811015610ebc576000546004830180546001600160a01b039092169163591fcdfe919084908110610de157fe5b6000918252602090912001546005850180546001600160a01b039092169185908110610e0957fe5b9060005260206000200154856006018581548110610e2357fe5b90600052602060002001866007018681548110610e3c57fe5b906000526020600020018760020160189054906101000a90046001600160401b03166040518663ffffffff1660e01b8152600401610e7e959493929190613a4e565b600060405180830381600087803b158015610e9857600080fd5b505af1158015610eac573d6000803e3d6000fd5b505060019092019150610daf9050565b507f789cf55be980739dad1d0699b93b58e806b51c9d96619bfa8fe0a28abaa7b30c83604051610eec9190613b13565b60405180910390a1505050565b6002546001600160a01b031681565b6000604051610f1690613924565b604080519182900382208282019091526015825274536f7672796e20476f7665726e6f7220416c70686160581b6020909201919091527fddf6fbf241d6c602c276b8332aecac376ff7e0ef2276d109c25930e6911ca2bd610f756122bf565b30604051602001610f899493929190613b21565b6040516020818303038152906040528051906020012090506000604051610faf9061392f565b604051908190038120610fc89189908990602001613b56565b60405160208183030381529060405280519060200120905060008282604051602001610ff59291906138f3565b6040516020818303038152906040528051906020012090506000600182888888604051600081526020016040526040516110329493929190613b7e565b6020604051602081039080840390855afa158015611054573d6000803e3d6000fd5b505050602060405103519050611069816122c3565b6110855760405162461bcd60e51b815260040161064190613cd0565b611090818a8a611f11565b505050505050505050565b6001546001600160a01b031681565b6002546001600160a01b031633146110d45760405162461bcd60e51b815260040161064190613d20565b600280546001600160a01b0319169055565b600a90565b6002546001600160a01b031633146111155760405162461bcd60e51b815260040161064190613c50565b600080546040516001600160a01b0390911691633a66f9019183919061113f90879060200161393a565b604051602081830303815290604052856040518563ffffffff1660e01b815260040161116e9493929190613970565b602060405180830381600087803b15801561118857600080fd5b505af115801561119c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506106f99190810190612bd6565b60405180604001604052806015815260200174536f7672796e20476f7665726e6f7220416c70686160581b81525081565b6004546001600160601b031681565b600080600160009054906101000a90046001600160a01b03166001600160a01b0316632522d7ba61124c6001430360405180606001604052806037815260200161429a6037913961217c565b426040518363ffffffff1660e01b815260040161126a929190613eb4565b60206040518083038186803b15801561128257600080fd5b505afa158015611296573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506112ba9190810190612d0e565b905060646001600160601b0382166107fe565b6002546001600160a01b031633146112f75760405162461bcd60e51b815260040161064190613be0565b6000805460408051630e18b68160e01b815290516001600160a01b0390921692630e18b6819260048084019382900301818387803b15801561133857600080fd5b505af115801561134c573d6000803e3d6000fd5b50505050565b6000546001600160a01b031681565b60035481565b600080611372611200565b600180549192506001600160601b038316916001600160a01b03169063836eebee9033906113a19043906122fc565b426040518463ffffffff1660e01b81526004016113c093929190613948565b60206040518083038186803b1580156113d857600080fd5b505afa1580156113ec573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506114109190810190612d0e565b6001600160601b0316116114365760405162461bcd60e51b815260040161064190613cc0565b85518751148015611448575084518751145b8015611455575083518751145b6114715760405162461bcd60e51b815260040161064190613c80565b865161148f5760405162461bcd60e51b815260040161064190613cb0565b6114976110e6565b875111156114b75760405162461bcd60e51b815260040161064190613c60565b3360009081526006602052604090205480156115345760006114d882610a99565b905060018160078111156114e857fe5b14156115065760405162461bcd60e51b815260040161064190613ce0565b600081600781111561151457fe5b14156115325760405162461bcd60e51b815260040161064190613c40565b505b600061154243610cfd610a94565b9050600061155282610cfd6105d8565b60038054600101905590506115656124aa565b604051806102000160405280600354815260200161159b856040518060600160405280603381526020016142676033913961217c565b63ffffffff1681526020016115c8846040518060600160405280603181526020016141136031913961217c565b63ffffffff16815260200160006001600160601b0316815260200160006001600160601b0316815260200161162b600460009054906101000a90046001600160601b031688604051806060016040528060368152602001614077603691396121ac565b6001600160601b031681526020016116716004600c9054906101000a90046001600160601b031688604051806080016040528060428152602001614200604291396121ac565b6001600160601b0316815260200160006001600160401b031681526020016116b1426040518060600160405280602a81526020016142d1602a9139612324565b6001600160401b03168152602001600015158152602001600015158152602001336001600160a01b031681526020018c81526020018b81526020018a81526020018981525090508060056000836000015181526020019081526020016000206000820151816000015560208201518160010160006101000a81548163ffffffff021916908363ffffffff16021790555060408201518160010160046101000a81548163ffffffff021916908363ffffffff16021790555060608201518160010160086101000a8154816001600160601b0302191690836001600160601b0316021790555060808201518160010160146101000a8154816001600160601b0302191690836001600160601b0316021790555060a08201518160020160006101000a8154816001600160601b0302191690836001600160601b0316021790555060c082015181600201600c6101000a8154816001600160601b0302191690836001600160601b0316021790555060e08201518160020160186101000a8154816001600160401b0302191690836001600160401b031602179055506101008201518160030160006101000a8154816001600160401b0302191690836001600160401b031602179055506101208201518160030160086101000a81548160ff0219169083151502179055506101408201518160030160096101000a81548160ff02191690831515021790555061016082015181600301600a6101000a8154816001600160a01b0302191690836001600160a01b03160217905550610180820151816004019080519060200190611904929190612530565b506101a08201518051611921916005840191602090910190612595565b506101c0820151805161193e9160068401916020909101906125dc565b506101e0820151805161195b916007840191602090910190612635565b509050508060000151600660008361016001516001600160a01b03166001600160a01b03168152602001908152602001600020819055507f7d84a6263ae0d98d3329bd7b46bb4e8d6f98cd35a7adb45c274c8b7fd5ebd5e08160000151338d8d8d8d89898f6040516119d599989796959493929190613d3e565b60405180910390a1519450505050505b95945050505050565b60046119f982610a99565b6007811115611a0457fe5b14611a215760405162461bcd60e51b815260040161064190613bf0565b600081815260056020908152604080832083548251630d48571f60e31b81529251919493611a7a9342936001600160a01b0390931692636a42b8f892600480840193919291829003018186803b158015610cc557600080fd5b905060005b6004830154811015611c2257611c1a836004018281548110611a9d57fe5b6000918252602090912001546005850180546001600160a01b039092169184908110611ac557fe5b9060005260206000200154856006018481548110611adf57fe5b600091825260209182902001805460408051601f6002600019610100600187161502019094169390930492830185900485028101850190915281815292830182828015611b6d5780601f10611b4257610100808354040283529160200191611b6d565b820191906000526020600020905b815481529060010190602001808311611b5057829003601f168201915b5050505050866007018581548110611b8157fe5b600091825260209182902001805460408051601f6002600019610100600187161502019094169390930492830185900485028101850190915281815292830182828015611c0f5780601f10611be457610100808354040283529160200191611c0f565b820191906000526020600020905b815481529060010190602001808311611bf257829003601f168201915b50505050508661234b565b600101611a7f565b50611c45816040518060600160405280602281526020016141a760229139612324565b8260020160186101000a8154816001600160401b0302191690836001600160401b031602179055507f9a2e42fd6722813d69113e7d0079d3d940171428df7373df9c7f7617cfda28928382604051610eec929190613de6565b60405161060c9061392f565b611cb261268e565b5060008281526005602090815260408083206001600160a01b03851684526008018252918290208251606081018452905460ff80821615158352610100820416151592820192909252620100009091046001600160601b0316918101919091525b92915050565b600454600160601b90046001600160601b031681565b6005611d3a82610a99565b6007811115611d4557fe5b14611d625760405162461bcd60e51b815260040161064190613c00565b600081815260056020526040812060038101805469ff0000000000000000001916600160481b179055905b6004820154811015611ed5576000546005830180546001600160a01b0390921691630825f38f919084908110611dbf57fe5b9060005260206000200154846004018481548110611dd957fe5b6000918252602090912001546005860180546001600160a01b039092169186908110611e0157fe5b9060005260206000200154866006018681548110611e1b57fe5b90600052602060002001876007018781548110611e3457fe5b906000526020600020018860020160189054906101000a90046001600160401b03166040518763ffffffff1660e01b8152600401611e76959493929190613a4e565b6000604051808303818588803b158015611e8f57600080fd5b505af1158015611ea3573d6000803e3d6000fd5b50505050506040513d6000823e601f3d908101601f19168201604052611ecc9190810190612bf4565b50600101611d8d565b507f712ae1383f79ac853f8d882153778e0260ef8f03b504e2866e0593e04d2b291f82604051611f059190613b13565b60405180910390a15050565b6001611f1c83610a99565b6007811115611f2757fe5b14611f445760405162461bcd60e51b815260040161064190613d00565b60008281526005602090815260408083206001600160a01b038716845260088101909252909120805460ff1615611f8d5760405162461bcd60e51b815260040161064190613c30565b600180549083015460038401546040516341b775f760e11b81526000936001600160a01b03169263836eebee92611fd9928b9263ffffffff16916001600160401b031690600401613a9e565b60206040518083038186803b158015611ff157600080fd5b505afa158015612005573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506120299190810190612d0e565b905083156120985761206b8360010160089054906101000a90046001600160601b0316826040518060600160405280602781526020016140ec60279139612215565b8360010160086101000a8154816001600160601b0302191690836001600160601b031602179055506120fb565b6120d28360010160149054906101000a90046001600160601b0316826040518060600160405280602781526020016140ec60279139612215565b8360010160146101000a8154816001600160601b0302191690836001600160601b031602179055505b8154600160ff199091161761ff00191661010085151502176dffffffffffffffffffffffff00001916620100006001600160601b038316021782556040517f877856338e13f63d0c36822ff0ef736b80934cd90574a3a5bc9262c39d217c469061216c9088908890889086906139bf565b60405180910390a1505050505050565b60008164010000000084106121a45760405162461bcd60e51b81526004016106419190613bcf565b509192915050565b60006001600160601b0384166121c45750600061220e565b8383026001600160601b0380851690808716908316816121e057fe5b046001600160601b031614839061220a5760405162461bcd60e51b81526004016106419190613bcf565b5090505b9392505050565b6000838301826001600160601b03808716908316101561220a5760405162461bcd60e51b81526004016106419190613bcf565b6000816001600160601b0384166122725760405162461bcd60e51b81526004016106419190613bcf565b506000836001600160601b0316856001600160601b03168161229057fe5b0495945050505050565b60008282018381101561220e5760405162461bcd60e51b815260040161064190613c70565b4690565b600073dcc703c0e500b653ca82273b7bfad8045d85a4706001600160a01b03831614801590611d135750506001600160a01b0316151590565b60008282111561231e5760405162461bcd60e51b815260040161064190613d10565b50900390565b600081600160401b84106121a45760405162461bcd60e51b81526004016106419190613bcf565b6000546040516001600160a01b039091169063f2b065379061237990889088908890889088906020016139f4565b604051602081830303815290604052805190602001206040518263ffffffff1660e01b81526004016123ab9190613b13565b60206040518083038186803b1580156123c357600080fd5b505afa1580156123d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506123fb9190810190612bb8565b156124185760405162461bcd60e51b815260040161064190613ca0565b600054604051633a66f90160e01b81526001600160a01b0390911690633a66f9019061245090889088908890889088906004016139f4565b602060405180830381600087803b15801561246a57600080fd5b505af115801561247e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506124a29190810190612bd6565b505050505050565b604080516102008101825260008082526020820181905291810182905260608082018390526080820183905260a0820183905260c0820183905260e0820183905261010082018390526101208201839052610140820183905261016082019290925261018081018290526101a081018290526101c081018290526101e081019190915290565b828054828255906000526020600020908101928215612585579160200282015b8281111561258557825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190612550565b506125919291506126ae565b5090565b8280548282559060005260206000209081019282156125d0579160200282015b828111156125d05782518255916020019190600101906125b5565b506125919291506126d2565b828054828255906000526020600020908101928215612629579160200282015b8281111561262957825180516126199184916020909101906126ec565b50916020019190600101906125fc565b50612591929150612759565b828054828255906000526020600020908101928215612682579160200282015b8281111561268257825180516126729184916020909101906126ec565b5091602001919060010190612655565b5061259192915061277c565b604080516060810182526000808252602082018190529181019190915290565b6105dc91905b808211156125915780546001600160a01b03191681556001016126b4565b6105dc91905b8082111561259157600081556001016126d8565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061272d57805160ff19168380011785556125d0565b828001600101855582156125d057918201828111156125d05782518255916020019190600101906125b5565b6105dc91905b80821115612591576000612773828261279f565b5060010161275f565b6105dc91905b80821115612591576000612796828261279f565b50600101612782565b50805460018160011615610100020316600290046000825580601f106127c557506127e3565b601f0160209004906000526020600020908101906127e391906126d2565b50565b8035611d138161403e565b600082601f83011261280257600080fd5b813561281561281082613ef6565b613ed0565b9150818183526020840193506020810190508385602084028201111561283a57600080fd5b60005b83811015612866578161285088826127e6565b845250602092830192919091019060010161283d565b5050505092915050565b600082601f83011261288157600080fd5b813561288f61281082613ef6565b81815260209384019390925082018360005b8381101561286657813586016128b788826129c6565b84525060209283019291909101906001016128a1565b600082601f8301126128de57600080fd5b81356128ec61281082613ef6565b81815260209384019390925082018360005b83811015612866578135860161291488826129c6565b84525060209283019291909101906001016128fe565b600082601f83011261293b57600080fd5b813561294961281082613ef6565b9150818183526020840193506020810190508385602084028201111561296e57600080fd5b60005b83811015612866578161298488826129b0565b8452506020928301929190910190600101612971565b8035611d1381614052565b8051611d1381614052565b8035611d138161405b565b8051611d138161405b565b600082601f8301126129d757600080fd5b81356129e561281082613f16565b91508082526020830160208301858383011115612a0157600080fd5b612a0c838284613ff2565b50505092915050565b600082601f830112612a2657600080fd5b8151612a3461281082613f16565b91508082526020830160208301858383011115612a5057600080fd5b612a0c838284613ffe565b8035611d1381614064565b8051611d138161406d565b600060208284031215612a8357600080fd5b6000612a8f84846127e6565b949350505050565b60008060408385031215612aaa57600080fd5b6000612ab685856127e6565b9250506020612ac7858286016129b0565b9150509250929050565b600080600080600060a08688031215612ae957600080fd5b85356001600160401b03811115612aff57600080fd5b612b0b888289016127f1565b95505060208601356001600160401b03811115612b2757600080fd5b612b338882890161292a565b94505060408601356001600160401b03811115612b4f57600080fd5b612b5b888289016128cd565b93505060608601356001600160401b03811115612b7757600080fd5b612b8388828901612870565b92505060808601356001600160401b03811115612b9f57600080fd5b612bab888289016129c6565b9150509295509295909350565b600060208284031215612bca57600080fd5b6000612a8f84846129a5565b600060208284031215612be857600080fd5b6000612a8f84846129bb565b600060208284031215612c0657600080fd5b81516001600160401b03811115612c1c57600080fd5b612a8f84828501612a15565b600060208284031215612c3a57600080fd5b6000612a8f84846129b0565b60008060408385031215612c5957600080fd5b6000612c6585856129b0565b9250506020612ac7858286016127e6565b60008060408385031215612c8957600080fd5b6000612c9585856129b0565b9250506020612ac78582860161299a565b600080600080600060a08688031215612cbe57600080fd5b6000612cca88886129b0565b9550506020612cdb8882890161299a565b9450506040612cec88828901612a5b565b9350506060612cfd888289016129b0565b9250506080612bab888289016129b0565b600060208284031215612d2057600080fd5b6000612a8f8484612a66565b6000612d388383612d67565b505060200190565b600061220e8383612f09565b6000612d388383612eef565b612d6181613fa9565b82525050565b612d6181613f5c565b6000612d7b82613f4f565b612d858185613f53565b9350612d9083613f3d565b8060005b83811015612dbe578151612da88882612d2c565b9750612db383613f3d565b925050600101612d94565b509495945050505050565b6000612dd482613f4f565b612dde8185613f53565b935083602082028501612df085613f3d565b8060005b85811015612e2a5784840389528151612e0d8582612d40565b9450612e1883613f3d565b60209a909a0199925050600101612df4565b5091979650505050505050565b6000612e4282613f4f565b612e4c8185613f53565b935083602082028501612e5e85613f3d565b8060005b85811015612e2a5784840389528151612e7b8582612d40565b9450612e8683613f3d565b60209a909a0199925050600101612e62565b6000612ea382613f4f565b612ead8185613f53565b9350612eb883613f3d565b8060005b83811015612dbe578151612ed08882612d4c565b9750612edb83613f3d565b925050600101612ebc565b612d6181613f67565b612d61816105dc565b612d61612f04826105dc565b6105dc565b6000612f1482613f4f565b612f1e8185613f53565b9350612f2e818560208601613ffe565b612f378161402a565b9093019392505050565b600081546001811660008114612f5e5760018114612f8457612fc3565b607f6002830416612f6f8187613f53565b60ff1984168152955050602085019250612fc3565b60028204612f928187613f53565b9550612f9d85613f43565b60005b82811015612fbc57815488820152600190910190602001612fa0565b8701945050505b505092915050565b612d6181613fb0565b612d6181613fbb565b612d6181613fc6565b6000612ff3603983613f53565b7f476f7665726e6f72416c7068613a3a5f5f61636365707441646d696e3a20736581527f6e646572206d75737420626520676f7620677561726469616e00000000000000602082015260400192915050565b6000613052604483613f53565b7f476f7665726e6f72416c7068613a3a71756575653a2070726f706f73616c206381527f616e206f6e6c79206265207175657565642069662069742069732073756363656020820152631959195960e21b604082015260600192915050565b60006130be604583613f53565b7f476f7665726e6f72416c7068613a3a657865637574653a2070726f706f73616c81527f2063616e206f6e6c7920626520657865637574656420696620697420697320716020820152641d595d595960da1b604082015260600192915050565b600061312b600283610d1c565b61190160f01b815260020192915050565b6000613149604c83613f53565b7f476f7665726e6f72416c7068613a3a5f5f6578656375746553657454696d656c81527f6f636b50656e64696e6741646d696e3a2073656e646572206d7573742062652060208201526b33b7bb1033bab0b93234b0b760a11b604082015260600192915050565b60006131bd601883613f53565b7f73657450656e64696e6741646d696e2861646472657373290000000000000000815260200192915050565b60006131f6602983613f53565b7f476f7665726e6f72416c7068613a3a73746174653a20696e76616c69642070728152681bdc1bdcd85b081a5960ba1b602082015260400192915050565b6000613241602d83613f53565b7f476f7665726e6f72416c7068613a3a5f63617374566f74653a20766f7465722081526c185b1c9958591e481d9bdd1959609a1b602082015260400192915050565b6000613290605983613f53565b7f476f7665726e6f72416c7068613a3a70726f706f73653a206f6e65206c69766581527f2070726f706f73616c207065722070726f706f7365722c20666f756e6420616e60208201527f20616c72656164792070656e64696e672070726f706f73616c00000000000000604082015260600192915050565b6000613315604a83613f53565b7f476f7665726e6f72416c7068613a3a5f5f717565756553657454696d656c6f6381527f6b50656e64696e6741646d696e3a2073656e646572206d75737420626520676f6020820152693b1033bab0b93234b0b760b11b604082015260600192915050565b6000613387602883613f53565b7f476f7665726e6f72416c7068613a3a70726f706f73653a20746f6f206d616e7981526720616374696f6e7360c01b602082015260400192915050565b60006133d1601183613f53565b706164646974696f6e206f766572666c6f7760781b815260200192915050565b60006133fe604383610d1c565b7f454950373132446f6d61696e28737472696e67206e616d652c75696e7432353681527f20636861696e49642c6164647265737320766572696679696e67436f6e74726160208201526263742960e81b604082015260430192915050565b6000613469602783610d1c565b7f42616c6c6f742875696e743235362070726f706f73616c49642c626f6f6c20738152667570706f72742960c81b602082015260270192915050565b60006134b2604483613f53565b7f476f7665726e6f72416c7068613a3a70726f706f73653a2070726f706f73616c81527f2066756e6374696f6e20696e666f726d6174696f6e206172697479206d69736d6020820152630c2e8c6d60e31b604082015260600192915050565b600061351e602e83613f53565b7f476f7665726e6f72416c7068613a3a63616e63656c3a2073656e64657220697381526d3713ba10309033bab0b93234b0b760911b602082015260400192915050565b600061356e604483613f53565b7f476f7665726e6f72416c7068613a3a5f71756575654f725265766572743a207081527f726f706f73616c20616374696f6e20616c7265616479207175657565642061746020820152632065746160e01b604082015260600192915050565b60006135da602c83613f53565b7f476f7665726e6f72416c7068613a3a70726f706f73653a206d7573742070726f81526b7669646520616374696f6e7360a01b602082015260400192915050565b6000613628603f83613f53565b7f476f7665726e6f72416c7068613a3a70726f706f73653a2070726f706f73657281527f20766f7465732062656c6f772070726f706f73616c207468726573686f6c6400602082015260400192915050565b6000613687602f83613f53565b7f476f7665726e6f72416c7068613a3a63617374566f746542795369673a20696e81526e76616c6964207369676e617475726560881b602082015260400192915050565b60006136d8605883613f53565b7f476f7665726e6f72416c7068613a3a70726f706f73653a206f6e65206c69766581527f2070726f706f73616c207065722070726f706f7365722c20666f756e6420616e60208201527f20616c7265616479206163746976652070726f706f73616c0000000000000000604082015260600192915050565b600061375d603683613f53565b7f476f7665726e6f72416c7068613a3a63616e63656c3a2063616e6e6f742063618152751b98d95b08195e1958dd5d1959081c1c9bdc1bdcd85b60521b602082015260400192915050565b60006137b5602a83613f53565b7f476f7665726e6f72416c7068613a3a5f63617374566f74653a20766f74696e67815269081a5cc818db1bdcd95960b21b602082015260400192915050565b6000613801601583613f53565b747375627472616374696f6e20756e646572666c6f7760581b815260200192915050565b6000613832603683613f53565b7f476f7665726e6f72416c7068613a3a5f5f61626469636174653a2073656e6465815275391036bab9ba1031329033b7bb1033bab0b93234b0b760511b602082015260400192915050565b8051606083019061388e8482612ee6565b5060208201516138a16020850182612ee6565b50604082015161134c60408501826138ea565b612d6181613fd1565b612d6181613f82565b612d6181613fdc565b612d6181613f8b565b612d6181613f97565b612d6181613fe7565b612d6181613f9d565b60006138fe8261311e565b915061390a8285612ef8565b60208201915061391a8284612ef8565b5060200192915050565b6000611d13826133f1565b6000611d138261345c565b60208101611d138284612d67565b606081016139568286612d58565b6139636020830185612eef565b612a8f6040830184612eef565b60a0810161397e8287612d67565b61398b6020830186612fdd565b818103604083015261399c816131b0565b905081810360608301526139b08185612f09565b90506119e56080830184612eef565b608081016139cd8287612d67565b6139da6020830186612eef565b6139e76040830185612ee6565b6119e560608301846138e1565b60a08101613a028288612d67565b613a0f6020830187612eef565b8181036040830152613a218186612f09565b90508181036060830152613a358185612f09565b9050613a446080830184612eef565b9695505050505050565b60a08101613a5c8288612d67565b613a696020830187612eef565b8181036040830152613a7b8186612f41565b90508181036060830152613a8f8185612f41565b9050613a4460808301846138c6565b60608101613aac8286612d67565b613ab960208301856138b4565b612a8f60408301846138c6565b60808082528101613ad78187612d70565b90508181036020830152613aeb8186612e98565b90508181036040830152613aff8185612e37565b90508181036060830152613a448184612dc9565b60208101611d138284612eef565b60808101613b2f8287612eef565b613b3c6020830186612eef565b613b496040830185612eef565b6119e56060830184612d67565b60608101613b648286612eef565b613b716020830185612eef565b612a8f6040830184612ee6565b60808101613b8c8287612eef565b613b9960208301866138d8565b613ba66040830185612eef565b6119e56060830184612eef565b60208101611d138284612fcb565b60208101611d138284612fd4565b6020808252810161220e8184612f09565b60208082528101611d1381612fe6565b60208082528101611d1381613045565b60208082528101611d13816130b1565b60208082528101611d138161313c565b60208082528101611d13816131e9565b60208082528101611d1381613234565b60208082528101611d1381613283565b60208082528101611d1381613308565b60208082528101611d138161337a565b60208082528101611d13816133c4565b60208082528101611d13816134a5565b60208082528101611d1381613511565b60208082528101611d1381613561565b60208082528101611d13816135cd565b60208082528101611d138161361b565b60208082528101611d138161367a565b60208082528101611d13816136cb565b60208082528101611d1381613750565b60208082528101611d13816137a8565b60208082528101611d13816137f4565b60208082528101611d1381613825565b60608101611d13828461387d565b6101208101613d4d828c612eef565b613d5a602083018b612d58565b8181036040830152613d6c818a612d70565b90508181036060830152613d808189612e98565b90508181036080830152613d948188612e37565b905081810360a0830152613da88187612dc9565b9050613db760c0830186612eef565b613dc460e0830185612eef565b818103610100830152613dd78184612f09565b9b9a5050505050505050505050565b60408101613df48285612eef565b61220e6020830184612eef565b6101808101613e10828f612eef565b613e1d602083018e6138bd565b613e2a604083018d6138bd565b613e37606083018c6138ea565b613e44608083018b6138ea565b613e5160a083018a6138ea565b613e5e60c08301896138ea565b613e6b60e08301886138cf565b613e796101008301876138cf565b613e87610120830186612ee6565b613e95610140830185612ee6565b613ea3610160830184612d67565b9d9c50505050505050505050505050565b60408101613df482856138bd565b60208101611d1382846138ea565b6040518181016001600160401b0381118282101715613eee57600080fd5b604052919050565b60006001600160401b03821115613f0c57600080fd5b5060209081020190565b60006001600160401b03821115613f2c57600080fd5b506020601f91909101601f19160190565b60200190565b60009081526020902090565b5190565b90815260200190565b6000611d1382613f76565b151590565b80610d1c81614034565b6001600160a01b031690565b63ffffffff1690565b6001600160401b031690565b60ff1690565b6001600160601b031690565b6000611d13825b6000611d1382613f5c565b6000611d1382613f6c565b6000611d13826105dc565b6000611d1382613f82565b6000611d1382613f8b565b6000611d1382613f9d565b82818337506000910152565b60005b83811015614019578181015183820152602001614001565b8381111561134c5750506000910152565b601f01601f191690565b600881106127e357fe5b61404781613f5c565b81146127e357600080fd5b61404781613f67565b614047816105dc565b61404781613f97565b61404781613f9d56fe476f7665726e6f72416c7068613a3a70726f706f73653a206f766572666c6f77206f6e2071756f72756d20636f6d7075746174696f6e476f7665726e6f72416c7068613a3a2073746174653a20746f74616c566f746573202a206d616a6f7269747950657263656e74616765203e2075696e743936476f7665726e6f72416c7068613a3a5f63617374566f74653a20766f7465206f766572666c6f77476f7665726e6f72416c7068613a3a70726f706f73653a20656e6420626c6f636b206e756d626572206f766572666c6f77476f7665726e6f72416c7068613a3a71756f72756d566f7465733a20626c6f636b206e756d626572206f766572666c6f77476f7665726e6f72416c7068613a3a71756f72756d566f7465733a6d756c7469706c69636174696f6e206f766572666c6f77476f7665726e6f72416c7068613a3a71756575653a20455441206f766572666c6f77476f7665726e6f72416c7068613a3a2073746174653a20666f72566f746573202b20616761696e7374566f746573203e2075696e743936476f7665726e6f72416c7068613a3a70726f706f73653a206f766572666c6f77206f6e206d616a6f7269747950657263656e7461676520636f6d7075746174696f6e476f7665726e6f72416c7068613a3a2073746174653a206469766973696f6e206572726f72476f7665726e6f72416c7068613a3a70726f706f73653a20737461727420626c6f636b206e756d626572206f766572666c6f77476f7665726e6f72416c7068613a3a70726f706f73616c5468726573686f6c643a20626c6f636b206e756d626572206f766572666c6f77476f7665726e6f72416c7068613a3a70726f706f73653a20737461727454696d65206f766572666c6f77a365627a7a72315820e446afd420c50be30db6eea2e270207120a4475f0b07c3e4e59be8b7240258aa6c6578706572696d656e74616cf564736f6c63430005110040000000000000000000000000967c84b731679e36a344002b8e3ce50620a7f69f0000000000000000000000005684a06cab22db16d901fee2a5c081b4c91ea40e000000000000000000000000924f5ad34698fd20c90fe5d5a8a0abd3b42dc71100000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000046","external_libraries":[],"proxy_type":null,"implementations":[],"verified_at":"2021-06-02T05:20:02.603527Z","is_verified_via_verifier_alliance":true,"compiler_version":"0.5.17+commit.d19bba13","decoded_constructor_args":[["0x967c84B731679E36A344002B8e3Ce50620A7f69F",{"internalType":"address","name":"timelock_","type":"address"}],["0x5684A06CaB22Db16D901FEe2a5c081b4C91eA40e",{"internalType":"address","name":"staking_","type":"address"}],["0x924f5Ad34698fD20C90fe5d5a8A0ABD3b42dC711",{"internalType":"address","name":"guardian_","type":"address"}],["20",{"internalType":"uint96","name":"_quorumPercentageVotes","type":"uint96"}],["70",{"internalType":"uint96","name":"_majorityPercentageVotes","type":"uint96"}]],"sourcify_repo_url":null,"optimization_runs":200,"compiler_settings":{"optimizer":{"enabled":true,"runs":200}},"is_verified":true,"verified_twin_address_hash":null,"optimization_enabled":true,"deployed_bytecode":"0x6080604052600436106101c25760003560e01c8063760fbc13116100f7578063d33219b411610095578063deaaa7cc11610064578063deaaa7cc146104ce578063e23a9a52146104e3578063e265379014610510578063fe0d94c114610525576101c2565b8063d33219b414610464578063da35c66414610479578063da95691a1461048e578063ddf0b009146104ae576101c2565b8063a3f4df7e116100d1578063a3f4df7e14610403578063b2b0d91f14610425578063b58131b01461043a578063b9a619611461044f576101c2565b8063760fbc13146103b95780637bdbe4d0146103ce57806391500671146103e3576101c2565b8063328dd9821161016457806340e58ee51161013e57806340e58ee514610335578063452a9320146103555780634634c61f146103775780634cf088d914610397576101c2565b8063328dd982146102c35780633932abb1146102f35780633e4f49e614610308576101c2565b806317977c61116101a057806317977c611461024c57806320606b701461026c57806321f43e421461028157806324bc1a64146102a1576101c2565b8063013cf08b146101c757806302a251a31461020857806315373e3d1461022a575b600080fd5b3480156101d357600080fd5b506101e76101e2366004612c28565b610538565b6040516101ff9c9b9a99989796959493929190613e01565b60405180910390f35b34801561021457600080fd5b5061021d6105d8565b6040516101ff9190613b13565b34801561023657600080fd5b5061024a610245366004612c76565b6105df565b005b34801561025857600080fd5b5061021d610267366004612a71565b6105ee565b34801561027857600080fd5b5061021d610600565b34801561028d57600080fd5b5061024a61029c366004612a97565b610617565b3480156102ad57600080fd5b506102b66106fe565b6040516101ff9190613ec2565b3480156102cf57600080fd5b506102e36102de366004612c28565b610805565b6040516101ff9493929190613ac6565b3480156102ff57600080fd5b5061021d610a94565b34801561031457600080fd5b50610328610323366004612c28565b610a99565b6040516101ff9190613bc1565b34801561034157600080fd5b5061024a610350366004612c28565b610d21565b34801561036157600080fd5b5061036a610ef9565b6040516101ff919061393a565b34801561038357600080fd5b5061024a610392366004612ca6565b610f08565b3480156103a357600080fd5b506103ac61109b565b6040516101ff9190613bb3565b3480156103c557600080fd5b5061024a6110aa565b3480156103da57600080fd5b5061021d6110e6565b3480156103ef57600080fd5b5061024a6103fe366004612a97565b6110eb565b34801561040f57600080fd5b506104186111c0565b6040516101ff9190613bcf565b34801561043157600080fd5b506102b66111f1565b34801561044657600080fd5b506102b6611200565b34801561045b57600080fd5b5061024a6112cd565b34801561047057600080fd5b506103ac611352565b34801561048557600080fd5b5061021d611361565b34801561049a57600080fd5b5061021d6104a9366004612ad1565b611367565b3480156104ba57600080fd5b5061024a6104c9366004612c28565b6119ee565b3480156104da57600080fd5b5061021d611c9e565b3480156104ef57600080fd5b506105036104fe366004612c46565b611caa565b6040516101ff9190613d30565b34801561051c57600080fd5b506102b6611d19565b61024a610533366004612c28565b611d2f565b6005602052600090815260409020805460018201546002830154600390930154919263ffffffff808316936401000000008404909116926001600160601b03600160401b808304821694600160a01b90930482169383831693600160601b8104909316926001600160401b03600160c01b9091048116929082169160ff918104821691600160481b820416906001600160a01b03600160501b909104168c565b610b405b90565b6105ea338383611f11565b5050565b60066020526000908152604090205481565b60405161060c90613924565b604051809103902081565b6002546001600160a01b0316331461064a5760405162461bcd60e51b815260040161064190613c10565b60405180910390fd5b600080546040516001600160a01b0390911691630825f38f9183919061067490879060200161393a565b604051602081830303815290604052856040518563ffffffff1660e01b81526004016106a39493929190613970565b600060405180830381600087803b1580156106bd57600080fd5b505af11580156106d1573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526106f99190810190612bf4565b505050565b600080600160009054906101000a90046001600160a01b03166001600160a01b0316632522d7ba61074a600143036040518060600160405280603181526020016141446031913961217c565b426040518363ffffffff1660e01b8152600401610768929190613eb4565b60206040518083038186803b15801561078057600080fd5b505afa158015610794573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506107b89190810190612d0e565b600454604080516060810190915260328082529293506064926107ee926001600160601b031691859161417560208301396121ac565b6001600160601b0316816107fe57fe5b0491505090565b6060806060806000600560008781526020019081526020016000209050806004018160050182600601836007018380548060200260200160405190810160405280929190818152602001828054801561088757602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610869575b50505050509350828054806020026020016040519081016040528092919081815260200182805480156108d957602002820191906000526020600020905b8154815260200190600101908083116108c5575b5050505050925081805480602002602001604051908101604052809291908181526020016000905b828210156109ac5760008481526020908190208301805460408051601f60026000196101006001871615020190941693909304928301859004850281018501909152818152928301828280156109985780601f1061096d57610100808354040283529160200191610998565b820191906000526020600020905b81548152906001019060200180831161097b57829003601f168201915b505050505081526020019060010190610901565b50505050915080805480602002602001604051908101604052809291908181526020016000905b82821015610a7e5760008481526020908190208301805460408051601f6002600019610100600187161502019094169390930492830185900485028101850190915281815292830182828015610a6a5780601f10610a3f57610100808354040283529160200191610a6a565b820191906000526020600020905b815481529060010190602001808311610a4d57829003601f168201915b5050505050815260200190600101906109d3565b5050505090509450945094509450509193509193565b600190565b60008160035410158015610aad5750600082115b610ac95760405162461bcd60e51b815260040161064190613c20565b60008281526005602052604090206003810154600160401b900460ff1615610af5576002915050610d1c565b600181015463ffffffff164311610b10576000915050610d1c565b6001810154640100000000900463ffffffff164311610b33576001915050610d1c565b600181015460408051606081019091526037808252600092610b78926001600160601b03600160401b8304811693600160a01b90930416916141c96020830139612215565b90506000610ba082606460405180606001604052806025815260200161424260259139612248565b9050610bda816004600c9054906101000a90046001600160601b03166040518060600160405280603f81526020016140ad603f91396121ac565b60018401549091506001600160601b03808316600160401b90920416111580610c13575060028301546001600160601b03908116908316105b15610c245760039350505050610d1c565b6002830154600160c01b90046001600160401b0316610c495760049350505050610d1c565b6003830154600160481b900460ff1615610c695760079350505050610d1c565b6002830154600054604080516360d143f160e11b81529051610d0293600160c01b90046001600160401b0316926001600160a01b03169163c1a287e2916004808301926020929190829003018186803b158015610cc557600080fd5b505afa158015610cd9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610cfd9190810190612bd6565b61229a565b4210610d145760069350505050610d1c565b600593505050505b919050565b6000610d2c82610a99565b90506007816007811115610d3c57fe5b1415610d5a5760405162461bcd60e51b815260040161064190613cf0565b60008281526005602052604090206002546001600160a01b03163314610d925760405162461bcd60e51b815260040161064190613c90565b60038101805468ff00000000000000001916600160401b17905560005b6004820154811015610ebc576000546004830180546001600160a01b039092169163591fcdfe919084908110610de157fe5b6000918252602090912001546005850180546001600160a01b039092169185908110610e0957fe5b9060005260206000200154856006018581548110610e2357fe5b90600052602060002001866007018681548110610e3c57fe5b906000526020600020018760020160189054906101000a90046001600160401b03166040518663ffffffff1660e01b8152600401610e7e959493929190613a4e565b600060405180830381600087803b158015610e9857600080fd5b505af1158015610eac573d6000803e3d6000fd5b505060019092019150610daf9050565b507f789cf55be980739dad1d0699b93b58e806b51c9d96619bfa8fe0a28abaa7b30c83604051610eec9190613b13565b60405180910390a1505050565b6002546001600160a01b031681565b6000604051610f1690613924565b604080519182900382208282019091526015825274536f7672796e20476f7665726e6f7220416c70686160581b6020909201919091527fddf6fbf241d6c602c276b8332aecac376ff7e0ef2276d109c25930e6911ca2bd610f756122bf565b30604051602001610f899493929190613b21565b6040516020818303038152906040528051906020012090506000604051610faf9061392f565b604051908190038120610fc89189908990602001613b56565b60405160208183030381529060405280519060200120905060008282604051602001610ff59291906138f3565b6040516020818303038152906040528051906020012090506000600182888888604051600081526020016040526040516110329493929190613b7e565b6020604051602081039080840390855afa158015611054573d6000803e3d6000fd5b505050602060405103519050611069816122c3565b6110855760405162461bcd60e51b815260040161064190613cd0565b611090818a8a611f11565b505050505050505050565b6001546001600160a01b031681565b6002546001600160a01b031633146110d45760405162461bcd60e51b815260040161064190613d20565b600280546001600160a01b0319169055565b600a90565b6002546001600160a01b031633146111155760405162461bcd60e51b815260040161064190613c50565b600080546040516001600160a01b0390911691633a66f9019183919061113f90879060200161393a565b604051602081830303815290604052856040518563ffffffff1660e01b815260040161116e9493929190613970565b602060405180830381600087803b15801561118857600080fd5b505af115801561119c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506106f99190810190612bd6565b60405180604001604052806015815260200174536f7672796e20476f7665726e6f7220416c70686160581b81525081565b6004546001600160601b031681565b600080600160009054906101000a90046001600160a01b03166001600160a01b0316632522d7ba61124c6001430360405180606001604052806037815260200161429a6037913961217c565b426040518363ffffffff1660e01b815260040161126a929190613eb4565b60206040518083038186803b15801561128257600080fd5b505afa158015611296573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506112ba9190810190612d0e565b905060646001600160601b0382166107fe565b6002546001600160a01b031633146112f75760405162461bcd60e51b815260040161064190613be0565b6000805460408051630e18b68160e01b815290516001600160a01b0390921692630e18b6819260048084019382900301818387803b15801561133857600080fd5b505af115801561134c573d6000803e3d6000fd5b50505050565b6000546001600160a01b031681565b60035481565b600080611372611200565b600180549192506001600160601b038316916001600160a01b03169063836eebee9033906113a19043906122fc565b426040518463ffffffff1660e01b81526004016113c093929190613948565b60206040518083038186803b1580156113d857600080fd5b505afa1580156113ec573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506114109190810190612d0e565b6001600160601b0316116114365760405162461bcd60e51b815260040161064190613cc0565b85518751148015611448575084518751145b8015611455575083518751145b6114715760405162461bcd60e51b815260040161064190613c80565b865161148f5760405162461bcd60e51b815260040161064190613cb0565b6114976110e6565b875111156114b75760405162461bcd60e51b815260040161064190613c60565b3360009081526006602052604090205480156115345760006114d882610a99565b905060018160078111156114e857fe5b14156115065760405162461bcd60e51b815260040161064190613ce0565b600081600781111561151457fe5b14156115325760405162461bcd60e51b815260040161064190613c40565b505b600061154243610cfd610a94565b9050600061155282610cfd6105d8565b60038054600101905590506115656124aa565b604051806102000160405280600354815260200161159b856040518060600160405280603381526020016142676033913961217c565b63ffffffff1681526020016115c8846040518060600160405280603181526020016141136031913961217c565b63ffffffff16815260200160006001600160601b0316815260200160006001600160601b0316815260200161162b600460009054906101000a90046001600160601b031688604051806060016040528060368152602001614077603691396121ac565b6001600160601b031681526020016116716004600c9054906101000a90046001600160601b031688604051806080016040528060428152602001614200604291396121ac565b6001600160601b0316815260200160006001600160401b031681526020016116b1426040518060600160405280602a81526020016142d1602a9139612324565b6001600160401b03168152602001600015158152602001600015158152602001336001600160a01b031681526020018c81526020018b81526020018a81526020018981525090508060056000836000015181526020019081526020016000206000820151816000015560208201518160010160006101000a81548163ffffffff021916908363ffffffff16021790555060408201518160010160046101000a81548163ffffffff021916908363ffffffff16021790555060608201518160010160086101000a8154816001600160601b0302191690836001600160601b0316021790555060808201518160010160146101000a8154816001600160601b0302191690836001600160601b0316021790555060a08201518160020160006101000a8154816001600160601b0302191690836001600160601b0316021790555060c082015181600201600c6101000a8154816001600160601b0302191690836001600160601b0316021790555060e08201518160020160186101000a8154816001600160401b0302191690836001600160401b031602179055506101008201518160030160006101000a8154816001600160401b0302191690836001600160401b031602179055506101208201518160030160086101000a81548160ff0219169083151502179055506101408201518160030160096101000a81548160ff02191690831515021790555061016082015181600301600a6101000a8154816001600160a01b0302191690836001600160a01b03160217905550610180820151816004019080519060200190611904929190612530565b506101a08201518051611921916005840191602090910190612595565b506101c0820151805161193e9160068401916020909101906125dc565b506101e0820151805161195b916007840191602090910190612635565b509050508060000151600660008361016001516001600160a01b03166001600160a01b03168152602001908152602001600020819055507f7d84a6263ae0d98d3329bd7b46bb4e8d6f98cd35a7adb45c274c8b7fd5ebd5e08160000151338d8d8d8d89898f6040516119d599989796959493929190613d3e565b60405180910390a1519450505050505b95945050505050565b60046119f982610a99565b6007811115611a0457fe5b14611a215760405162461bcd60e51b815260040161064190613bf0565b600081815260056020908152604080832083548251630d48571f60e31b81529251919493611a7a9342936001600160a01b0390931692636a42b8f892600480840193919291829003018186803b158015610cc557600080fd5b905060005b6004830154811015611c2257611c1a836004018281548110611a9d57fe5b6000918252602090912001546005850180546001600160a01b039092169184908110611ac557fe5b9060005260206000200154856006018481548110611adf57fe5b600091825260209182902001805460408051601f6002600019610100600187161502019094169390930492830185900485028101850190915281815292830182828015611b6d5780601f10611b4257610100808354040283529160200191611b6d565b820191906000526020600020905b815481529060010190602001808311611b5057829003601f168201915b5050505050866007018581548110611b8157fe5b600091825260209182902001805460408051601f6002600019610100600187161502019094169390930492830185900485028101850190915281815292830182828015611c0f5780601f10611be457610100808354040283529160200191611c0f565b820191906000526020600020905b815481529060010190602001808311611bf257829003601f168201915b50505050508661234b565b600101611a7f565b50611c45816040518060600160405280602281526020016141a760229139612324565b8260020160186101000a8154816001600160401b0302191690836001600160401b031602179055507f9a2e42fd6722813d69113e7d0079d3d940171428df7373df9c7f7617cfda28928382604051610eec929190613de6565b60405161060c9061392f565b611cb261268e565b5060008281526005602090815260408083206001600160a01b03851684526008018252918290208251606081018452905460ff80821615158352610100820416151592820192909252620100009091046001600160601b0316918101919091525b92915050565b600454600160601b90046001600160601b031681565b6005611d3a82610a99565b6007811115611d4557fe5b14611d625760405162461bcd60e51b815260040161064190613c00565b600081815260056020526040812060038101805469ff0000000000000000001916600160481b179055905b6004820154811015611ed5576000546005830180546001600160a01b0390921691630825f38f919084908110611dbf57fe5b9060005260206000200154846004018481548110611dd957fe5b6000918252602090912001546005860180546001600160a01b039092169186908110611e0157fe5b9060005260206000200154866006018681548110611e1b57fe5b90600052602060002001876007018781548110611e3457fe5b906000526020600020018860020160189054906101000a90046001600160401b03166040518763ffffffff1660e01b8152600401611e76959493929190613a4e565b6000604051808303818588803b158015611e8f57600080fd5b505af1158015611ea3573d6000803e3d6000fd5b50505050506040513d6000823e601f3d908101601f19168201604052611ecc9190810190612bf4565b50600101611d8d565b507f712ae1383f79ac853f8d882153778e0260ef8f03b504e2866e0593e04d2b291f82604051611f059190613b13565b60405180910390a15050565b6001611f1c83610a99565b6007811115611f2757fe5b14611f445760405162461bcd60e51b815260040161064190613d00565b60008281526005602090815260408083206001600160a01b038716845260088101909252909120805460ff1615611f8d5760405162461bcd60e51b815260040161064190613c30565b600180549083015460038401546040516341b775f760e11b81526000936001600160a01b03169263836eebee92611fd9928b9263ffffffff16916001600160401b031690600401613a9e565b60206040518083038186803b158015611ff157600080fd5b505afa158015612005573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506120299190810190612d0e565b905083156120985761206b8360010160089054906101000a90046001600160601b0316826040518060600160405280602781526020016140ec60279139612215565b8360010160086101000a8154816001600160601b0302191690836001600160601b031602179055506120fb565b6120d28360010160149054906101000a90046001600160601b0316826040518060600160405280602781526020016140ec60279139612215565b8360010160146101000a8154816001600160601b0302191690836001600160601b031602179055505b8154600160ff199091161761ff00191661010085151502176dffffffffffffffffffffffff00001916620100006001600160601b038316021782556040517f877856338e13f63d0c36822ff0ef736b80934cd90574a3a5bc9262c39d217c469061216c9088908890889086906139bf565b60405180910390a1505050505050565b60008164010000000084106121a45760405162461bcd60e51b81526004016106419190613bcf565b509192915050565b60006001600160601b0384166121c45750600061220e565b8383026001600160601b0380851690808716908316816121e057fe5b046001600160601b031614839061220a5760405162461bcd60e51b81526004016106419190613bcf565b5090505b9392505050565b6000838301826001600160601b03808716908316101561220a5760405162461bcd60e51b81526004016106419190613bcf565b6000816001600160601b0384166122725760405162461bcd60e51b81526004016106419190613bcf565b506000836001600160601b0316856001600160601b03168161229057fe5b0495945050505050565b60008282018381101561220e5760405162461bcd60e51b815260040161064190613c70565b4690565b600073dcc703c0e500b653ca82273b7bfad8045d85a4706001600160a01b03831614801590611d135750506001600160a01b0316151590565b60008282111561231e5760405162461bcd60e51b815260040161064190613d10565b50900390565b600081600160401b84106121a45760405162461bcd60e51b81526004016106419190613bcf565b6000546040516001600160a01b039091169063f2b065379061237990889088908890889088906020016139f4565b604051602081830303815290604052805190602001206040518263ffffffff1660e01b81526004016123ab9190613b13565b60206040518083038186803b1580156123c357600080fd5b505afa1580156123d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506123fb9190810190612bb8565b156124185760405162461bcd60e51b815260040161064190613ca0565b600054604051633a66f90160e01b81526001600160a01b0390911690633a66f9019061245090889088908890889088906004016139f4565b602060405180830381600087803b15801561246a57600080fd5b505af115801561247e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506124a29190810190612bd6565b505050505050565b604080516102008101825260008082526020820181905291810182905260608082018390526080820183905260a0820183905260c0820183905260e0820183905261010082018390526101208201839052610140820183905261016082019290925261018081018290526101a081018290526101c081018290526101e081019190915290565b828054828255906000526020600020908101928215612585579160200282015b8281111561258557825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190612550565b506125919291506126ae565b5090565b8280548282559060005260206000209081019282156125d0579160200282015b828111156125d05782518255916020019190600101906125b5565b506125919291506126d2565b828054828255906000526020600020908101928215612629579160200282015b8281111561262957825180516126199184916020909101906126ec565b50916020019190600101906125fc565b50612591929150612759565b828054828255906000526020600020908101928215612682579160200282015b8281111561268257825180516126729184916020909101906126ec565b5091602001919060010190612655565b5061259192915061277c565b604080516060810182526000808252602082018190529181019190915290565b6105dc91905b808211156125915780546001600160a01b03191681556001016126b4565b6105dc91905b8082111561259157600081556001016126d8565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061272d57805160ff19168380011785556125d0565b828001600101855582156125d057918201828111156125d05782518255916020019190600101906125b5565b6105dc91905b80821115612591576000612773828261279f565b5060010161275f565b6105dc91905b80821115612591576000612796828261279f565b50600101612782565b50805460018160011615610100020316600290046000825580601f106127c557506127e3565b601f0160209004906000526020600020908101906127e391906126d2565b50565b8035611d138161403e565b600082601f83011261280257600080fd5b813561281561281082613ef6565b613ed0565b9150818183526020840193506020810190508385602084028201111561283a57600080fd5b60005b83811015612866578161285088826127e6565b845250602092830192919091019060010161283d565b5050505092915050565b600082601f83011261288157600080fd5b813561288f61281082613ef6565b81815260209384019390925082018360005b8381101561286657813586016128b788826129c6565b84525060209283019291909101906001016128a1565b600082601f8301126128de57600080fd5b81356128ec61281082613ef6565b81815260209384019390925082018360005b83811015612866578135860161291488826129c6565b84525060209283019291909101906001016128fe565b600082601f83011261293b57600080fd5b813561294961281082613ef6565b9150818183526020840193506020810190508385602084028201111561296e57600080fd5b60005b83811015612866578161298488826129b0565b8452506020928301929190910190600101612971565b8035611d1381614052565b8051611d1381614052565b8035611d138161405b565b8051611d138161405b565b600082601f8301126129d757600080fd5b81356129e561281082613f16565b91508082526020830160208301858383011115612a0157600080fd5b612a0c838284613ff2565b50505092915050565b600082601f830112612a2657600080fd5b8151612a3461281082613f16565b91508082526020830160208301858383011115612a5057600080fd5b612a0c838284613ffe565b8035611d1381614064565b8051611d138161406d565b600060208284031215612a8357600080fd5b6000612a8f84846127e6565b949350505050565b60008060408385031215612aaa57600080fd5b6000612ab685856127e6565b9250506020612ac7858286016129b0565b9150509250929050565b600080600080600060a08688031215612ae957600080fd5b85356001600160401b03811115612aff57600080fd5b612b0b888289016127f1565b95505060208601356001600160401b03811115612b2757600080fd5b612b338882890161292a565b94505060408601356001600160401b03811115612b4f57600080fd5b612b5b888289016128cd565b93505060608601356001600160401b03811115612b7757600080fd5b612b8388828901612870565b92505060808601356001600160401b03811115612b9f57600080fd5b612bab888289016129c6565b9150509295509295909350565b600060208284031215612bca57600080fd5b6000612a8f84846129a5565b600060208284031215612be857600080fd5b6000612a8f84846129bb565b600060208284031215612c0657600080fd5b81516001600160401b03811115612c1c57600080fd5b612a8f84828501612a15565b600060208284031215612c3a57600080fd5b6000612a8f84846129b0565b60008060408385031215612c5957600080fd5b6000612c6585856129b0565b9250506020612ac7858286016127e6565b60008060408385031215612c8957600080fd5b6000612c9585856129b0565b9250506020612ac78582860161299a565b600080600080600060a08688031215612cbe57600080fd5b6000612cca88886129b0565b9550506020612cdb8882890161299a565b9450506040612cec88828901612a5b565b9350506060612cfd888289016129b0565b9250506080612bab888289016129b0565b600060208284031215612d2057600080fd5b6000612a8f8484612a66565b6000612d388383612d67565b505060200190565b600061220e8383612f09565b6000612d388383612eef565b612d6181613fa9565b82525050565b612d6181613f5c565b6000612d7b82613f4f565b612d858185613f53565b9350612d9083613f3d565b8060005b83811015612dbe578151612da88882612d2c565b9750612db383613f3d565b925050600101612d94565b509495945050505050565b6000612dd482613f4f565b612dde8185613f53565b935083602082028501612df085613f3d565b8060005b85811015612e2a5784840389528151612e0d8582612d40565b9450612e1883613f3d565b60209a909a0199925050600101612df4565b5091979650505050505050565b6000612e4282613f4f565b612e4c8185613f53565b935083602082028501612e5e85613f3d565b8060005b85811015612e2a5784840389528151612e7b8582612d40565b9450612e8683613f3d565b60209a909a0199925050600101612e62565b6000612ea382613f4f565b612ead8185613f53565b9350612eb883613f3d565b8060005b83811015612dbe578151612ed08882612d4c565b9750612edb83613f3d565b925050600101612ebc565b612d6181613f67565b612d61816105dc565b612d61612f04826105dc565b6105dc565b6000612f1482613f4f565b612f1e8185613f53565b9350612f2e818560208601613ffe565b612f378161402a565b9093019392505050565b600081546001811660008114612f5e5760018114612f8457612fc3565b607f6002830416612f6f8187613f53565b60ff1984168152955050602085019250612fc3565b60028204612f928187613f53565b9550612f9d85613f43565b60005b82811015612fbc57815488820152600190910190602001612fa0565b8701945050505b505092915050565b612d6181613fb0565b612d6181613fbb565b612d6181613fc6565b6000612ff3603983613f53565b7f476f7665726e6f72416c7068613a3a5f5f61636365707441646d696e3a20736581527f6e646572206d75737420626520676f7620677561726469616e00000000000000602082015260400192915050565b6000613052604483613f53565b7f476f7665726e6f72416c7068613a3a71756575653a2070726f706f73616c206381527f616e206f6e6c79206265207175657565642069662069742069732073756363656020820152631959195960e21b604082015260600192915050565b60006130be604583613f53565b7f476f7665726e6f72416c7068613a3a657865637574653a2070726f706f73616c81527f2063616e206f6e6c7920626520657865637574656420696620697420697320716020820152641d595d595960da1b604082015260600192915050565b600061312b600283610d1c565b61190160f01b815260020192915050565b6000613149604c83613f53565b7f476f7665726e6f72416c7068613a3a5f5f6578656375746553657454696d656c81527f6f636b50656e64696e6741646d696e3a2073656e646572206d7573742062652060208201526b33b7bb1033bab0b93234b0b760a11b604082015260600192915050565b60006131bd601883613f53565b7f73657450656e64696e6741646d696e2861646472657373290000000000000000815260200192915050565b60006131f6602983613f53565b7f476f7665726e6f72416c7068613a3a73746174653a20696e76616c69642070728152681bdc1bdcd85b081a5960ba1b602082015260400192915050565b6000613241602d83613f53565b7f476f7665726e6f72416c7068613a3a5f63617374566f74653a20766f7465722081526c185b1c9958591e481d9bdd1959609a1b602082015260400192915050565b6000613290605983613f53565b7f476f7665726e6f72416c7068613a3a70726f706f73653a206f6e65206c69766581527f2070726f706f73616c207065722070726f706f7365722c20666f756e6420616e60208201527f20616c72656164792070656e64696e672070726f706f73616c00000000000000604082015260600192915050565b6000613315604a83613f53565b7f476f7665726e6f72416c7068613a3a5f5f717565756553657454696d656c6f6381527f6b50656e64696e6741646d696e3a2073656e646572206d75737420626520676f6020820152693b1033bab0b93234b0b760b11b604082015260600192915050565b6000613387602883613f53565b7f476f7665726e6f72416c7068613a3a70726f706f73653a20746f6f206d616e7981526720616374696f6e7360c01b602082015260400192915050565b60006133d1601183613f53565b706164646974696f6e206f766572666c6f7760781b815260200192915050565b60006133fe604383610d1c565b7f454950373132446f6d61696e28737472696e67206e616d652c75696e7432353681527f20636861696e49642c6164647265737320766572696679696e67436f6e74726160208201526263742960e81b604082015260430192915050565b6000613469602783610d1c565b7f42616c6c6f742875696e743235362070726f706f73616c49642c626f6f6c20738152667570706f72742960c81b602082015260270192915050565b60006134b2604483613f53565b7f476f7665726e6f72416c7068613a3a70726f706f73653a2070726f706f73616c81527f2066756e6374696f6e20696e666f726d6174696f6e206172697479206d69736d6020820152630c2e8c6d60e31b604082015260600192915050565b600061351e602e83613f53565b7f476f7665726e6f72416c7068613a3a63616e63656c3a2073656e64657220697381526d3713ba10309033bab0b93234b0b760911b602082015260400192915050565b600061356e604483613f53565b7f476f7665726e6f72416c7068613a3a5f71756575654f725265766572743a207081527f726f706f73616c20616374696f6e20616c7265616479207175657565642061746020820152632065746160e01b604082015260600192915050565b60006135da602c83613f53565b7f476f7665726e6f72416c7068613a3a70726f706f73653a206d7573742070726f81526b7669646520616374696f6e7360a01b602082015260400192915050565b6000613628603f83613f53565b7f476f7665726e6f72416c7068613a3a70726f706f73653a2070726f706f73657281527f20766f7465732062656c6f772070726f706f73616c207468726573686f6c6400602082015260400192915050565b6000613687602f83613f53565b7f476f7665726e6f72416c7068613a3a63617374566f746542795369673a20696e81526e76616c6964207369676e617475726560881b602082015260400192915050565b60006136d8605883613f53565b7f476f7665726e6f72416c7068613a3a70726f706f73653a206f6e65206c69766581527f2070726f706f73616c207065722070726f706f7365722c20666f756e6420616e60208201527f20616c7265616479206163746976652070726f706f73616c0000000000000000604082015260600192915050565b600061375d603683613f53565b7f476f7665726e6f72416c7068613a3a63616e63656c3a2063616e6e6f742063618152751b98d95b08195e1958dd5d1959081c1c9bdc1bdcd85b60521b602082015260400192915050565b60006137b5602a83613f53565b7f476f7665726e6f72416c7068613a3a5f63617374566f74653a20766f74696e67815269081a5cc818db1bdcd95960b21b602082015260400192915050565b6000613801601583613f53565b747375627472616374696f6e20756e646572666c6f7760581b815260200192915050565b6000613832603683613f53565b7f476f7665726e6f72416c7068613a3a5f5f61626469636174653a2073656e6465815275391036bab9ba1031329033b7bb1033bab0b93234b0b760511b602082015260400192915050565b8051606083019061388e8482612ee6565b5060208201516138a16020850182612ee6565b50604082015161134c60408501826138ea565b612d6181613fd1565b612d6181613f82565b612d6181613fdc565b612d6181613f8b565b612d6181613f97565b612d6181613fe7565b612d6181613f9d565b60006138fe8261311e565b915061390a8285612ef8565b60208201915061391a8284612ef8565b5060200192915050565b6000611d13826133f1565b6000611d138261345c565b60208101611d138284612d67565b606081016139568286612d58565b6139636020830185612eef565b612a8f6040830184612eef565b60a0810161397e8287612d67565b61398b6020830186612fdd565b818103604083015261399c816131b0565b905081810360608301526139b08185612f09565b90506119e56080830184612eef565b608081016139cd8287612d67565b6139da6020830186612eef565b6139e76040830185612ee6565b6119e560608301846138e1565b60a08101613a028288612d67565b613a0f6020830187612eef565b8181036040830152613a218186612f09565b90508181036060830152613a358185612f09565b9050613a446080830184612eef565b9695505050505050565b60a08101613a5c8288612d67565b613a696020830187612eef565b8181036040830152613a7b8186612f41565b90508181036060830152613a8f8185612f41565b9050613a4460808301846138c6565b60608101613aac8286612d67565b613ab960208301856138b4565b612a8f60408301846138c6565b60808082528101613ad78187612d70565b90508181036020830152613aeb8186612e98565b90508181036040830152613aff8185612e37565b90508181036060830152613a448184612dc9565b60208101611d138284612eef565b60808101613b2f8287612eef565b613b3c6020830186612eef565b613b496040830185612eef565b6119e56060830184612d67565b60608101613b648286612eef565b613b716020830185612eef565b612a8f6040830184612ee6565b60808101613b8c8287612eef565b613b9960208301866138d8565b613ba66040830185612eef565b6119e56060830184612eef565b60208101611d138284612fcb565b60208101611d138284612fd4565b6020808252810161220e8184612f09565b60208082528101611d1381612fe6565b60208082528101611d1381613045565b60208082528101611d13816130b1565b60208082528101611d138161313c565b60208082528101611d13816131e9565b60208082528101611d1381613234565b60208082528101611d1381613283565b60208082528101611d1381613308565b60208082528101611d138161337a565b60208082528101611d13816133c4565b60208082528101611d13816134a5565b60208082528101611d1381613511565b60208082528101611d1381613561565b60208082528101611d13816135cd565b60208082528101611d138161361b565b60208082528101611d138161367a565b60208082528101611d13816136cb565b60208082528101611d1381613750565b60208082528101611d13816137a8565b60208082528101611d13816137f4565b60208082528101611d1381613825565b60608101611d13828461387d565b6101208101613d4d828c612eef565b613d5a602083018b612d58565b8181036040830152613d6c818a612d70565b90508181036060830152613d808189612e98565b90508181036080830152613d948188612e37565b905081810360a0830152613da88187612dc9565b9050613db760c0830186612eef565b613dc460e0830185612eef565b818103610100830152613dd78184612f09565b9b9a5050505050505050505050565b60408101613df48285612eef565b61220e6020830184612eef565b6101808101613e10828f612eef565b613e1d602083018e6138bd565b613e2a604083018d6138bd565b613e37606083018c6138ea565b613e44608083018b6138ea565b613e5160a083018a6138ea565b613e5e60c08301896138ea565b613e6b60e08301886138cf565b613e796101008301876138cf565b613e87610120830186612ee6565b613e95610140830185612ee6565b613ea3610160830184612d67565b9d9c50505050505050505050505050565b60408101613df482856138bd565b60208101611d1382846138ea565b6040518181016001600160401b0381118282101715613eee57600080fd5b604052919050565b60006001600160401b03821115613f0c57600080fd5b5060209081020190565b60006001600160401b03821115613f2c57600080fd5b506020601f91909101601f19160190565b60200190565b60009081526020902090565b5190565b90815260200190565b6000611d1382613f76565b151590565b80610d1c81614034565b6001600160a01b031690565b63ffffffff1690565b6001600160401b031690565b60ff1690565b6001600160601b031690565b6000611d13825b6000611d1382613f5c565b6000611d1382613f6c565b6000611d13826105dc565b6000611d1382613f82565b6000611d1382613f8b565b6000611d1382613f9d565b82818337506000910152565b60005b83811015614019578181015183820152602001614001565b8381111561134c5750506000910152565b601f01601f191690565b600881106127e357fe5b61404781613f5c565b81146127e357600080fd5b61404781613f67565b614047816105dc565b61404781613f97565b61404781613f9d56fe476f7665726e6f72416c7068613a3a70726f706f73653a206f766572666c6f77206f6e2071756f72756d20636f6d7075746174696f6e476f7665726e6f72416c7068613a3a2073746174653a20746f74616c566f746573202a206d616a6f7269747950657263656e74616765203e2075696e743936476f7665726e6f72416c7068613a3a5f63617374566f74653a20766f7465206f766572666c6f77476f7665726e6f72416c7068613a3a70726f706f73653a20656e6420626c6f636b206e756d626572206f766572666c6f77476f7665726e6f72416c7068613a3a71756f72756d566f7465733a20626c6f636b206e756d626572206f766572666c6f77476f7665726e6f72416c7068613a3a71756f72756d566f7465733a6d756c7469706c69636174696f6e206f766572666c6f77476f7665726e6f72416c7068613a3a71756575653a20455441206f766572666c6f77476f7665726e6f72416c7068613a3a2073746174653a20666f72566f746573202b20616761696e7374566f746573203e2075696e743936476f7665726e6f72416c7068613a3a70726f706f73653a206f766572666c6f77206f6e206d616a6f7269747950657263656e7461676520636f6d7075746174696f6e476f7665726e6f72416c7068613a3a2073746174653a206469766973696f6e206572726f72476f7665726e6f72416c7068613a3a70726f706f73653a20737461727420626c6f636b206e756d626572206f766572666c6f77476f7665726e6f72416c7068613a3a70726f706f73616c5468726573686f6c643a20626c6f636b206e756d626572206f766572666c6f77476f7665726e6f72416c7068613a3a70726f706f73653a20737461727454696d65206f766572666c6f77a365627a7a72315820e446afd420c50be30db6eea2e270207120a4475f0b07c3e4e59be8b7240258aa6c6578706572696d656e74616cf564736f6c63430005110040","source_code":"pragma solidity ^0.5.17;\r\npragma experimental ABIEncoderV2;\r\n\r\ninterface TimelockInterface {\r\n    function delay() external view returns (uint256);\r\n\r\n    function GRACE_PERIOD() external view returns (uint256);\r\n\r\n    function acceptAdmin() external;\r\n\r\n    function queuedTransactions(bytes32 hash) external view returns (bool);\r\n\r\n    function queueTransaction(\r\n        address target,\r\n        uint256 value,\r\n        string calldata signature,\r\n        bytes calldata data,\r\n        uint256 eta\r\n    ) external returns (bytes32);\r\n\r\n    function cancelTransaction(\r\n        address target,\r\n        uint256 value,\r\n        string calldata signature,\r\n        bytes calldata data,\r\n        uint256 eta\r\n    ) external;\r\n\r\n    function executeTransaction(\r\n        address target,\r\n        uint256 value,\r\n        string calldata signature,\r\n        bytes calldata data,\r\n        uint256 eta\r\n    ) external payable returns (bytes memory);\r\n}\r\n\r\ninterface StakingInterface {\r\n    function getPriorVotes(\r\n        address account,\r\n        uint256 blockNumber,\r\n        uint256 date\r\n    ) external view returns (uint96);\r\n\r\n    function getPriorTotalVotingPower(uint32 blockNumber, uint256 time)\r\n        external\r\n        view\r\n        returns (uint96);\r\n}\r\n\r\ninterface IFeeSharingProxy {\r\n    function withdrawFees(address _token) external;\r\n\r\n    function transferTokens(address _token, uint96 _amount) external;\r\n\r\n    function withdraw(\r\n        address _loanPoolToken,\r\n        uint32 _maxCheckpoints,\r\n        address _receiver\r\n    ) external;\r\n}\r\n\r\n/**\r\n * Copyright 2017-2020, bZeroX, LLC. All Rights Reserved.\r\n * Licensed under the Apache License, Version 2.0.\r\n */\r\n\r\ncontract IERC20 {\r\n    string public name;\r\n    uint8 public decimals;\r\n    string public symbol;\r\n\r\n    function totalSupply() public view returns (uint256);\r\n\r\n    function balanceOf(address _who) public view returns (uint256);\r\n\r\n    function transfer(address _to, uint256 _value) public returns (bool);\r\n\r\n    function allowance(address _owner, address _spender)\r\n        public\r\n        view\r\n        returns (uint256);\r\n\r\n    function transferFrom(\r\n        address _from,\r\n        address _to,\r\n        uint256 _value\r\n    ) public returns (bool);\r\n\r\n    function approve(address _spender, uint256 _value) public returns (bool);\r\n\r\n    event Transfer(address indexed from, address indexed to, uint256 value);\r\n    event Approval(\r\n        address indexed owner,\r\n        address indexed spender,\r\n        uint256 value\r\n    );\r\n}\r\n\r\n/*\r\n * @dev Provides information about the current execution context, including the\r\n * sender of the transaction and its data. While these are generally available\r\n * via msg.sender and msg.data, they should not be accessed in such a direct\r\n * manner, since when dealing with GSN meta-transactions the account sending and\r\n * paying for execution may not be the actual sender (as far as an application\r\n * is concerned).\r\n *\r\n * This contract is only required for intermediate, library-like contracts.\r\n */\r\ncontract Context {\r\n    // Empty internal constructor, to prevent people from mistakenly deploying\r\n    // an instance of this contract, which should be used via inheritance.\r\n    constructor() internal {}\r\n\r\n    // solhint-disable-previous-line no-empty-blocks\r\n\r\n    function _msgSender() internal view returns (address payable) {\r\n        return msg.sender;\r\n    }\r\n\r\n    function _msgData() internal view returns (bytes memory) {\r\n        this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691\r\n        return msg.data;\r\n    }\r\n}\r\n\r\n/**\r\n * @dev Contract module which provides a basic access control mechanism, where\r\n * there is an account (an owner) that can be granted exclusive access to\r\n * specific functions.\r\n *\r\n * This module is used through inheritance. It will make available the modifier\r\n * `onlyOwner`, which can be applied to your functions to restrict their use to\r\n * the owner.\r\n */\r\ncontract Ownable is Context {\r\n    address private _owner;\r\n\r\n    event OwnershipTransferred(\r\n        address indexed previousOwner,\r\n        address indexed newOwner\r\n    );\r\n\r\n    /**\r\n     * @dev Initializes the contract setting the deployer as the initial owner.\r\n     */\r\n    constructor() internal {\r\n        address msgSender = _msgSender();\r\n        _owner = msgSender;\r\n        emit OwnershipTransferred(address(0), msgSender);\r\n    }\r\n\r\n    /**\r\n     * @dev Returns the address of the current owner.\r\n     */\r\n    function owner() public view returns (address) {\r\n        return _owner;\r\n    }\r\n\r\n    /**\r\n     * @dev Throws if called by any account other than the owner.\r\n     */\r\n    modifier onlyOwner() {\r\n        require(isOwner(), \"unauthorized\");\r\n        _;\r\n    }\r\n\r\n    /**\r\n     * @dev Returns true if the caller is the current owner.\r\n     */\r\n    function isOwner() public view returns (bool) {\r\n        return _msgSender() == _owner;\r\n    }\r\n\r\n    /**\r\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\r\n     * Can only be called by the current owner.\r\n     */\r\n    function transferOwnership(address newOwner) public onlyOwner {\r\n        _transferOwnership(newOwner);\r\n    }\r\n\r\n    /**\r\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\r\n     */\r\n    function _transferOwnership(address newOwner) internal {\r\n        require(\r\n            newOwner != address(0),\r\n            \"Ownable: new owner is the zero address\"\r\n        );\r\n        emit OwnershipTransferred(_owner, newOwner);\r\n        _owner = newOwner;\r\n    }\r\n}\r\n\r\ncontract StakingStorage is Ownable {\r\n    ///@notice 2 weeks in seconds\r\n    uint256 constant TWO_WEEKS = 1209600;\r\n\r\n    ///@notice the maximum possible voting weight before adding +1 (actually 10, but need 9 for computation)\r\n    uint96 public constant MAX_VOTING_WEIGHT = 9;\r\n\r\n    ///@notice weight is multiplied with this factor (for allowing decimals, like 1.2x)\r\n    ///@dev MAX_VOTING_WEIGHT * WEIGHT_FACTOR needs to be < 792, because there are 100,000,000 SOV with 18 decimals\r\n    uint96 public constant WEIGHT_FACTOR = 10;\r\n\r\n    /// @notice the maximum duration to stake tokens for\r\n    uint256 public constant MAX_DURATION = 1092 days;\r\n\r\n    ///@notice the maximum duration ^2\r\n    uint96 constant MAX_DURATION_POW_2 = 1092 * 1092;\r\n\r\n    ///@notice default weight scaling\r\n    uint96 constant DEFAULT_WEIGHT_SCALING = 3;\r\n\r\n    ///@notice range for weight scaling\r\n    uint96 constant MIN_WEIGHT_SCALING = 1;\r\n    uint96 constant MAX_WEIGHT_SCALING = 9;\r\n\r\n    ///@notice the timestamp of contract creation. base for the staking period calculation\r\n    uint256 public kickoffTS;\r\n\r\n    string name = \"SOVStaking\";\r\n\r\n    /// @notice the token to be staked\r\n    IERC20 public SOVToken;\r\n\r\n    /// @notice A record of each accounts delegate\r\n    mapping(address => mapping(uint256 => address)) public delegates;\r\n\r\n    /// @notice if this flag is set to true, all tokens are unlocked immediately\r\n    bool public allUnlocked = false;\r\n\r\n    /// @notice The EIP-712 typehash for the contract's domain\r\n    bytes32 public constant DOMAIN_TYPEHASH =\r\n        keccak256(\r\n            \"EIP712Domain(string name,uint256 chainId,address verifyingContract)\"\r\n        );\r\n\r\n    /// @notice The EIP-712 typehash for the delegation struct used by the contract\r\n    bytes32 public constant DELEGATION_TYPEHASH =\r\n        keccak256(\r\n            \"Delegation(address delegatee,uint256 lockDate,uint256 nonce,uint256 expiry)\"\r\n        );\r\n\r\n    /// @notice used for stake migrations to a new staking contract with a different storage structure\r\n    address public newStakingContract;\r\n\r\n    /*************************** Checkpoints *******************************/\r\n\r\n    /// @notice A checkpoint for marking the stakes from a given block\r\n    struct Checkpoint {\r\n        uint32 fromBlock;\r\n        uint96 stake;\r\n    }\r\n\r\n    /// @notice A record of tokens to be unstaked at a given time in total\r\n    /// for total voting power computation. voting weights get adjusted bi-weekly\r\n\r\n    mapping(uint256 => mapping(uint32 => Checkpoint))\r\n        public totalStakingCheckpoints;\r\n\r\n    ///@notice The number of total staking checkpoints for each date\r\n    mapping(uint256 => uint32) public numTotalStakingCheckpoints;\r\n\r\n    /// @notice A record of tokens to be unstaked at a given time which were delegated to a certain address\r\n    /// for delegatee voting power computation. voting weights get adjusted bi-weekly\r\n    mapping(address => mapping(uint256 => mapping(uint32 => Checkpoint)))\r\n        public delegateStakingCheckpoints;\r\n\r\n    ///@notice The number of total staking checkpoints for each date per delegate\r\n    mapping(address => mapping(uint256 => uint32))\r\n        public numDelegateStakingCheckpoints;\r\n\r\n    /// @notice A record of tokens to be unstaked at a given time which per user address (address -> lockDate -> stake checkpoint)\r\n    mapping(address => mapping(uint256 => mapping(uint32 => Checkpoint)))\r\n        public userStakingCheckpoints;\r\n\r\n    ///@notice The number of total staking checkpoints for each date per user\r\n    mapping(address => mapping(uint256 => uint32))\r\n        public numUserStakingCheckpoints;\r\n\r\n    /// @notice A record of states for signing / validating signatures\r\n    mapping(address => uint256) public nonces;\r\n\r\n    /*************************** Slashing *******************************/\r\n\r\n    /// @notice the address of FeeSharingProxy contract, we need it for unstaking with slashing\r\n    IFeeSharingProxy public feeSharing;\r\n\r\n    // @notice used for weight scaling when unstaking with slashing\r\n    uint96 public weightScaling = DEFAULT_WEIGHT_SCALING;\r\n\r\n    // @notice list of Vesting contracts, tokens for these contracts won't be slashed if unstaked by governance\r\n    mapping(address => bool) public vestingWhitelist;\r\n}\r\n\r\ncontract SafeMath96 {\r\n    function safe32(uint256 n, string memory errorMessage)\r\n        internal\r\n        pure\r\n        returns (uint32)\r\n    {\r\n        require(n < 2**32, errorMessage);\r\n        return uint32(n);\r\n    }\r\n\r\n    function safe64(uint256 n, string memory errorMessage)\r\n        internal\r\n        pure\r\n        returns (uint64)\r\n    {\r\n        require(n < 2**64, errorMessage);\r\n        return uint64(n);\r\n    }\r\n\r\n    function safe96(uint256 n, string memory errorMessage)\r\n        internal\r\n        pure\r\n        returns (uint96)\r\n    {\r\n        require(n < 2**96, errorMessage);\r\n        return uint96(n);\r\n    }\r\n\r\n    function add96(\r\n        uint96 a,\r\n        uint96 b,\r\n        string memory errorMessage\r\n    ) internal pure returns (uint96) {\r\n        uint96 c = a + b;\r\n        require(c >= a, errorMessage);\r\n        return c;\r\n    }\r\n\r\n    function sub96(\r\n        uint96 a,\r\n        uint96 b,\r\n        string memory errorMessage\r\n    ) internal pure returns (uint96) {\r\n        require(b <= a, errorMessage);\r\n        return a - b;\r\n    }\r\n\r\n    function mul96(\r\n        uint96 a,\r\n        uint96 b,\r\n        string memory errorMessage\r\n    ) internal pure returns (uint96) {\r\n        if (a == 0) {\r\n            return 0;\r\n        }\r\n\r\n        uint96 c = a * b;\r\n        require(c / a == b, errorMessage);\r\n\r\n        return c;\r\n    }\r\n\r\n    function div96(\r\n        uint96 a,\r\n        uint96 b,\r\n        string memory errorMessage\r\n    ) internal pure returns (uint96) {\r\n        // Solidity only automatically asserts when dividing by 0\r\n        require(b > 0, errorMessage);\r\n        uint96 c = a / b;\r\n        // assert(a == b * c + a % b); // There is no case in which this doesn't hold\r\n\r\n        return c;\r\n    }\r\n}\r\n\r\ncontract ErrorDecoder {\r\n    //4 bytes - 0x08c379a0 - method id\r\n    //32 bytes - 2 parameters\r\n    //32 bytes - bool, result\r\n    //32 ... bytes - string, error message\r\n    uint256 constant ERROR_MESSAGE_SHIFT = 68;\r\n\r\n    function _addErrorMessage(string memory str1, string memory str2)\r\n        internal\r\n        pure\r\n        returns (string memory)\r\n    {\r\n        bytes memory bytesStr1 = bytes(str1);\r\n        bytes memory bytesStr2 = bytes(str2);\r\n        string memory str12 =\r\n            new string(\r\n                bytesStr1.length + bytesStr2.length - ERROR_MESSAGE_SHIFT\r\n            );\r\n        bytes memory bytesStr12 = bytes(str12);\r\n        uint256 j = 0;\r\n        for (uint256 i = 0; i < bytesStr1.length; i++) {\r\n            bytesStr12[j++] = bytesStr1[i];\r\n        }\r\n        for (uint256 i = ERROR_MESSAGE_SHIFT; i < bytesStr2.length; i++) {\r\n            bytesStr12[j++] = bytesStr2[i];\r\n        }\r\n        return string(bytesStr12);\r\n    }\r\n}\r\n\r\ninterface IApproveAndCall {\r\n    /**\r\n     * @notice receives approval from SOV token\r\n     * @param _sender the sender of SOV.approveAndCall function\r\n     * @param _amount the amount was approved\r\n     * @param _token the address of token\r\n     * @param _data the data will be used for low level call\r\n     */\r\n    function receiveApproval(\r\n        address _sender,\r\n        uint256 _amount,\r\n        address _token,\r\n        bytes calldata _data\r\n    ) external;\r\n}\r\n\r\ninterface ITeamVesting {\r\n    function governanceWithdrawTokens(address receiver) external;\r\n}\r\n\r\n// SPDX-License-Identifier:MIT\r\n\r\nlibrary RSKAddrValidator {\r\n    /*\r\n     * @param addr it is an address to check that it does not originates from\r\n     * signing with PK = ZERO. RSK has a small difference in which @ZERO_PK_ADDR is\r\n     * also an address from PK = ZERO. So we check for both of them.\r\n     */\r\n    function checkPKNotZero(address addr) internal pure returns (bool) {\r\n        return (addr != 0xdcc703c0E500B653Ca82273B7BFAd8045D85a470 &&\r\n            addr != address(0));\r\n    }\r\n\r\n    /*\r\n     * Safely compares two addresses, checking they do not originate from\r\n     * a zero private key\r\n     */\r\n    function safeEquals(address addr1, address addr2)\r\n        internal\r\n        pure\r\n        returns (bool)\r\n    {\r\n        return (addr1 == addr2 &&\r\n            addr1 != 0xdcc703c0E500B653Ca82273B7BFAd8045D85a470 &&\r\n            addr1 != address(0));\r\n    }\r\n}\r\n\r\ninterface IStaking {\r\n    function stakesBySchedule(\r\n        uint256 amount,\r\n        uint256 cliff,\r\n        uint256 duration,\r\n        uint256 intervalLength,\r\n        address stakeFor,\r\n        address delegatee\r\n    ) external;\r\n\r\n    function stake(\r\n        uint96 amount,\r\n        uint256 until,\r\n        address stakeFor,\r\n        address delegatee\r\n    ) external;\r\n\r\n    function getPriorVotes(\r\n        address account,\r\n        uint256 blockNumber,\r\n        uint256 date\r\n    ) external view returns (uint96);\r\n\r\n    function getPriorTotalVotingPower(uint32 blockNumber, uint256 time)\r\n        external\r\n        view\r\n        returns (uint96);\r\n\r\n    function getPriorWeightedStake(\r\n        address account,\r\n        uint256 blockNumber,\r\n        uint256 date\r\n    ) external view returns (uint96);\r\n\r\n    function timestampToLockDate(uint256 timestamp)\r\n        external\r\n        view\r\n        returns (uint256 lockDate);\r\n}\r\n\r\n/**\r\n * @dev Wrappers over Solidity's arithmetic operations with added overflow\r\n * checks.\r\n *\r\n * Arithmetic operations in Solidity wrap on overflow. This can easily result\r\n * in bugs, because programmers usually assume that an overflow raises an\r\n * error, which is the standard behavior in high level programming languages.\r\n * `SafeMath` restores this intuition by reverting the transaction when an\r\n * operation overflows.\r\n *\r\n * Using this library instead of the unchecked operations eliminates an entire\r\n * class of bugs, so it's recommended to use it always.\r\n */\r\nlibrary SafeMath {\r\n    /**\r\n     * @dev Returns the addition of two unsigned integers, reverting on\r\n     * overflow.\r\n     *\r\n     * Counterpart to Solidity's `+` operator.\r\n     *\r\n     * Requirements:\r\n     * - Addition cannot overflow.\r\n     */\r\n    function add(uint256 a, uint256 b) internal pure returns (uint256) {\r\n        uint256 c = a + b;\r\n        require(c >= a, \"SafeMath: addition overflow\");\r\n\r\n        return c;\r\n    }\r\n\r\n    /**\r\n     * @dev Returns the subtraction of two unsigned integers, reverting on\r\n     * overflow (when the result is negative).\r\n     *\r\n     * Counterpart to Solidity's `-` operator.\r\n     *\r\n     * Requirements:\r\n     * - Subtraction cannot overflow.\r\n     */\r\n    function sub(uint256 a, uint256 b) internal pure returns (uint256) {\r\n        return sub(a, b, \"SafeMath: subtraction overflow\");\r\n    }\r\n\r\n    /**\r\n     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\r\n     * overflow (when the result is negative).\r\n     *\r\n     * Counterpart to Solidity's `-` operator.\r\n     *\r\n     * Requirements:\r\n     * - Subtraction cannot overflow.\r\n     *\r\n     * _Available since v2.4.0._\r\n     */\r\n    function sub(\r\n        uint256 a,\r\n        uint256 b,\r\n        string memory errorMessage\r\n    ) internal pure returns (uint256) {\r\n        require(b <= a, errorMessage);\r\n        uint256 c = a - b;\r\n\r\n        return c;\r\n    }\r\n\r\n    /**\r\n     * @dev Returns the multiplication of two unsigned integers, reverting on\r\n     * overflow.\r\n     *\r\n     * Counterpart to Solidity's `*` operator.\r\n     *\r\n     * Requirements:\r\n     * - Multiplication cannot overflow.\r\n     */\r\n    function mul(uint256 a, uint256 b) internal pure returns (uint256) {\r\n        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\r\n        // benefit is lost if 'b' is also tested.\r\n        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\r\n        if (a == 0) {\r\n            return 0;\r\n        }\r\n\r\n        uint256 c = a * b;\r\n        require(c / a == b, \"SafeMath: multiplication overflow\");\r\n\r\n        return c;\r\n    }\r\n\r\n    /**\r\n     * @dev Returns the integer division of two unsigned integers. Reverts on\r\n     * division by zero. The result is rounded towards zero.\r\n     *\r\n     * Counterpart to Solidity's `/` operator. Note: this function uses a\r\n     * `revert` opcode (which leaves remaining gas untouched) while Solidity\r\n     * uses an invalid opcode to revert (consuming all remaining gas).\r\n     *\r\n     * Requirements:\r\n     * - The divisor cannot be zero.\r\n     */\r\n    function div(uint256 a, uint256 b) internal pure returns (uint256) {\r\n        return div(a, b, \"SafeMath: division by zero\");\r\n    }\r\n\r\n    /**\r\n     * @dev Returns the integer division of two unsigned integers. Reverts with custom message on\r\n     * division by zero. The result is rounded towards zero.\r\n     *\r\n     * Counterpart to Solidity's `/` operator. Note: this function uses a\r\n     * `revert` opcode (which leaves remaining gas untouched) while Solidity\r\n     * uses an invalid opcode to revert (consuming all remaining gas).\r\n     *\r\n     * Requirements:\r\n     * - The divisor cannot be zero.\r\n     *\r\n     * _Available since v2.4.0._\r\n     */\r\n    function div(\r\n        uint256 a,\r\n        uint256 b,\r\n        string memory errorMessage\r\n    ) internal pure returns (uint256) {\r\n        // Solidity only automatically asserts when dividing by 0\r\n        require(b > 0, errorMessage);\r\n        uint256 c = a / b;\r\n        // assert(a == b * c + a % b); // There is no case in which this doesn't hold\r\n\r\n        return c;\r\n    }\r\n\r\n    /**\r\n     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\r\n     * Reverts when dividing by zero.\r\n     *\r\n     * Counterpart to Solidity's `%` operator. This function uses a `revert`\r\n     * opcode (which leaves remaining gas untouched) while Solidity uses an\r\n     * invalid opcode to revert (consuming all remaining gas).\r\n     *\r\n     * Requirements:\r\n     * - The divisor cannot be zero.\r\n     */\r\n    function mod(uint256 a, uint256 b) internal pure returns (uint256) {\r\n        return mod(a, b, \"SafeMath: modulo by zero\");\r\n    }\r\n\r\n    /**\r\n     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\r\n     * Reverts with custom message when dividing by zero.\r\n     *\r\n     * Counterpart to Solidity's `%` operator. This function uses a `revert`\r\n     * opcode (which leaves remaining gas untouched) while Solidity uses an\r\n     * invalid opcode to revert (consuming all remaining gas).\r\n     *\r\n     * Requirements:\r\n     * - The divisor cannot be zero.\r\n     *\r\n     * _Available since v2.4.0._\r\n     */\r\n    function mod(\r\n        uint256 a,\r\n        uint256 b,\r\n        string memory errorMessage\r\n    ) internal pure returns (uint256) {\r\n        require(b != 0, errorMessage);\r\n        return a % b;\r\n    }\r\n\r\n    function min256(uint256 _a, uint256 _b) internal pure returns (uint256) {\r\n        return _a < _b ? _a : _b;\r\n    }\r\n}\r\n\r\ninterface ITimelock {\r\n    function delay() external view returns (uint256);\r\n\r\n    function GRACE_PERIOD() external view returns (uint256);\r\n\r\n    function acceptAdmin() external;\r\n\r\n    function queuedTransactions(bytes32 hash) external view returns (bool);\r\n\r\n    function queueTransaction(\r\n        address target,\r\n        uint256 value,\r\n        string calldata signature,\r\n        bytes calldata data,\r\n        uint256 eta\r\n    ) external returns (bytes32);\r\n\r\n    function cancelTransaction(\r\n        address target,\r\n        uint256 value,\r\n        string calldata signature,\r\n        bytes calldata data,\r\n        uint256 eta\r\n    ) external;\r\n\r\n    function executeTransaction(\r\n        address target,\r\n        uint256 value,\r\n        string calldata signature,\r\n        bytes calldata data,\r\n        uint256 eta\r\n    ) external payable returns (bytes memory);\r\n}\r\n\r\ncontract Timelock is ErrorDecoder, ITimelock {\r\n    using SafeMath for uint256;\r\n\r\n    uint256 public constant GRACE_PERIOD = 14 days;\r\n    uint256 public constant MINIMUM_DELAY = 3 hours;\r\n    uint256 public constant MAXIMUM_DELAY = 30 days;\r\n\r\n    address public admin;\r\n    address public pendingAdmin;\r\n    uint256 public delay;\r\n\r\n    mapping(bytes32 => bool) public queuedTransactions;\r\n\r\n    event NewAdmin(address indexed newAdmin);\r\n    event NewPendingAdmin(address indexed newPendingAdmin);\r\n    event NewDelay(uint256 indexed newDelay);\r\n    event CancelTransaction(\r\n        bytes32 indexed txHash,\r\n        address indexed target,\r\n        uint256 value,\r\n        string signature,\r\n        bytes data,\r\n        uint256 eta\r\n    );\r\n    event ExecuteTransaction(\r\n        bytes32 indexed txHash,\r\n        address indexed target,\r\n        uint256 value,\r\n        string signature,\r\n        bytes data,\r\n        uint256 eta\r\n    );\r\n    event QueueTransaction(\r\n        bytes32 indexed txHash,\r\n        address indexed target,\r\n        uint256 value,\r\n        string signature,\r\n        bytes data,\r\n        uint256 eta\r\n    );\r\n\r\n    constructor(address admin_, uint256 delay_) public {\r\n        require(\r\n            delay_ >= MINIMUM_DELAY,\r\n            \"Timelock::constructor: Delay must exceed minimum delay.\"\r\n        );\r\n        require(\r\n            delay_ <= MAXIMUM_DELAY,\r\n            \"Timelock::setDelay: Delay must not exceed maximum delay.\"\r\n        );\r\n\r\n        admin = admin_;\r\n        delay = delay_;\r\n    }\r\n\r\n    function() external payable {}\r\n\r\n    function setDelay(uint256 delay_) public {\r\n        require(\r\n            msg.sender == address(this),\r\n            \"Timelock::setDelay: Call must come from Timelock.\"\r\n        );\r\n        require(\r\n            delay_ >= MINIMUM_DELAY,\r\n            \"Timelock::setDelay: Delay must exceed minimum delay.\"\r\n        );\r\n        require(\r\n            delay_ <= MAXIMUM_DELAY,\r\n            \"Timelock::setDelay: Delay must not exceed maximum delay.\"\r\n        );\r\n        delay = delay_;\r\n\r\n        emit NewDelay(delay);\r\n    }\r\n\r\n    function acceptAdmin() public {\r\n        require(\r\n            msg.sender == pendingAdmin,\r\n            \"Timelock::acceptAdmin: Call must come from pendingAdmin.\"\r\n        );\r\n        admin = msg.sender;\r\n        pendingAdmin = address(0);\r\n\r\n        emit NewAdmin(admin);\r\n    }\r\n\r\n    function setPendingAdmin(address pendingAdmin_) public {\r\n        require(\r\n            msg.sender == address(this),\r\n            \"Timelock::setPendingAdmin: Call must come from Timelock.\"\r\n        );\r\n        pendingAdmin = pendingAdmin_;\r\n\r\n        emit NewPendingAdmin(pendingAdmin);\r\n    }\r\n\r\n    function queueTransaction(\r\n        address target,\r\n        uint256 value,\r\n        string memory signature,\r\n        bytes memory data,\r\n        uint256 eta\r\n    ) public returns (bytes32) {\r\n        require(\r\n            msg.sender == admin,\r\n            \"Timelock::queueTransaction: Call must come from admin.\"\r\n        );\r\n        require(\r\n            eta >= getBlockTimestamp().add(delay),\r\n            \"Timelock::queueTransaction: Estimated execution block must satisfy delay.\"\r\n        );\r\n\r\n        bytes32 txHash =\r\n            keccak256(abi.encode(target, value, signature, data, eta));\r\n        queuedTransactions[txHash] = true;\r\n\r\n        emit QueueTransaction(txHash, target, value, signature, data, eta);\r\n        return txHash;\r\n    }\r\n\r\n    function cancelTransaction(\r\n        address target,\r\n        uint256 value,\r\n        string memory signature,\r\n        bytes memory data,\r\n        uint256 eta\r\n    ) public {\r\n        require(\r\n            msg.sender == admin,\r\n            \"Timelock::cancelTransaction: Call must come from admin.\"\r\n        );\r\n\r\n        bytes32 txHash =\r\n            keccak256(abi.encode(target, value, signature, data, eta));\r\n        queuedTransactions[txHash] = false;\r\n\r\n        emit CancelTransaction(txHash, target, value, signature, data, eta);\r\n    }\r\n\r\n    function executeTransaction(\r\n        address target,\r\n        uint256 value,\r\n        string memory signature,\r\n        bytes memory data,\r\n        uint256 eta\r\n    ) public payable returns (bytes memory) {\r\n        require(\r\n            msg.sender == admin,\r\n            \"Timelock::executeTransaction: Call must come from admin.\"\r\n        );\r\n\r\n        bytes32 txHash =\r\n            keccak256(abi.encode(target, value, signature, data, eta));\r\n        require(\r\n            queuedTransactions[txHash],\r\n            \"Timelock::executeTransaction: Transaction hasn't been queued.\"\r\n        );\r\n        require(\r\n            getBlockTimestamp() >= eta,\r\n            \"Timelock::executeTransaction: Transaction hasn't surpassed time lock.\"\r\n        );\r\n        require(\r\n            getBlockTimestamp() <= eta.add(GRACE_PERIOD),\r\n            \"Timelock::executeTransaction: Transaction is stale.\"\r\n        );\r\n\r\n        queuedTransactions[txHash] = false;\r\n\r\n        bytes memory callData;\r\n\r\n        if (bytes(signature).length == 0) {\r\n            callData = data;\r\n        } else {\r\n            callData = abi.encodePacked(\r\n                bytes4(keccak256(bytes(signature))),\r\n                data\r\n            );\r\n        }\r\n\r\n        // solium-disable-next-line security/no-call-value\r\n        (bool success, bytes memory returnData) =\r\n            target.call.value(value)(callData);\r\n        if (!success) {\r\n            if (returnData.length <= ERROR_MESSAGE_SHIFT) {\r\n                revert(\r\n                    \"Timelock::executeTransaction: Transaction execution reverted.\"\r\n                );\r\n            } else {\r\n                revert(\r\n                    _addErrorMessage(\r\n                        \"Timelock::executeTransaction: \",\r\n                        string(returnData)\r\n                    )\r\n                );\r\n            }\r\n        }\r\n\r\n        emit ExecuteTransaction(txHash, target, value, signature, data, eta);\r\n\r\n        return returnData;\r\n    }\r\n\r\n    function getBlockTimestamp() internal view returns (uint256) {\r\n        // solium-disable-next-line security/no-block-members\r\n        return block.timestamp;\r\n    }\r\n}\r\n\r\ncontract Checkpoints is StakingStorage, SafeMath96 {\r\n    /// @notice An event thats emitted when an account changes its delegate\r\n    event DelegateChanged(\r\n        address indexed delegator,\r\n        uint256 lockedUntil,\r\n        address indexed fromDelegate,\r\n        address indexed toDelegate\r\n    );\r\n\r\n    /// @notice An event thats emitted when a delegate account's stake balance changes\r\n    event DelegateStakeChanged(\r\n        address indexed delegate,\r\n        uint256 lockedUntil,\r\n        uint256 previousBalance,\r\n        uint256 newBalance\r\n    );\r\n\r\n    /// @notice An event thats emitted when tokens get staked\r\n    event TokensStaked(\r\n        address indexed staker,\r\n        uint256 amount,\r\n        uint256 lockedUntil,\r\n        uint256 totalStaked\r\n    );\r\n\r\n    /// @notice An event thats emitted when tokens get withdrawn\r\n    event TokensWithdrawn(\r\n        address indexed staker,\r\n        address receiver,\r\n        uint256 amount\r\n    );\r\n\r\n    /// @notice An event thats emitted when vesting tokens get withdrawn\r\n    event VestingTokensWithdrawn(address vesting, address receiver);\r\n\r\n    /// @notice An event thats emitted when the owner unlocks all tokens\r\n    event TokensUnlocked(uint256 amount);\r\n\r\n    /// @notice An event thats emitted when a staking period gets extended\r\n    event ExtendedStakingDuration(\r\n        address indexed staker,\r\n        uint256 previousDate,\r\n        uint256 newDate\r\n    );\r\n\r\n    /**\r\n     * @notice increases the user's stake for a giving lock date and writes a checkpoint\r\n     * @param account the user address\r\n     * @param lockedTS the lock date\r\n     * @param value the value to add to the staked balance\r\n     * */\r\n    function _increaseUserStake(\r\n        address account,\r\n        uint256 lockedTS,\r\n        uint96 value\r\n    ) internal {\r\n        uint32 nCheckpoints = numUserStakingCheckpoints[account][lockedTS];\r\n        uint96 staked =\r\n            userStakingCheckpoints[account][lockedTS][nCheckpoints - 1].stake;\r\n        uint96 newStake =\r\n            add96(\r\n                staked,\r\n                value,\r\n                \"Staking::_increaseUserStake: staked amount overflow\"\r\n            );\r\n        _writeUserCheckpoint(account, lockedTS, nCheckpoints, newStake);\r\n    }\r\n\r\n    /**\r\n     * @notice decreases the user's stake for a giving lock date and writes a checkpoint\r\n     * @param account the user address\r\n     * @param lockedTS the lock date\r\n     * @param value the value to add to the staked balance\r\n     * */\r\n    function _decreaseUserStake(\r\n        address account,\r\n        uint256 lockedTS,\r\n        uint96 value\r\n    ) internal {\r\n        uint32 nCheckpoints = numUserStakingCheckpoints[account][lockedTS];\r\n        uint96 staked =\r\n            userStakingCheckpoints[account][lockedTS][nCheckpoints - 1].stake;\r\n        uint96 newStake =\r\n            sub96(\r\n                staked,\r\n                value,\r\n                \"Staking::_decreaseUserStake: staked amount underflow\"\r\n            );\r\n        _writeUserCheckpoint(account, lockedTS, nCheckpoints, newStake);\r\n    }\r\n\r\n    function _writeUserCheckpoint(\r\n        address account,\r\n        uint256 lockedTS,\r\n        uint32 nCheckpoints,\r\n        uint96 newStake\r\n    ) internal {\r\n        uint32 blockNumber =\r\n            safe32(\r\n                block.number,\r\n                \"Staking::_writeStakingCheckpoint: block number exceeds 32 bits\"\r\n            );\r\n        if (\r\n            nCheckpoints > 0 &&\r\n            userStakingCheckpoints[account][lockedTS][nCheckpoints - 1]\r\n                .fromBlock ==\r\n            blockNumber\r\n        ) {\r\n            userStakingCheckpoints[account][lockedTS][nCheckpoints - 1]\r\n                .stake = newStake;\r\n        } else {\r\n            userStakingCheckpoints[account][lockedTS][\r\n                nCheckpoints\r\n            ] = Checkpoint(blockNumber, newStake);\r\n            numUserStakingCheckpoints[account][lockedTS] = nCheckpoints + 1;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * @notice increases the delegatee's stake for a giving lock date and writes a checkpoint\r\n     * @param delegatee the delegatee\r\n     * @param lockedTS the lock date\r\n     * @param value the value to add to the staked balance\r\n     * */\r\n    function _increaseDelegateStake(\r\n        address delegatee,\r\n        uint256 lockedTS,\r\n        uint96 value\r\n    ) internal {\r\n        uint32 nCheckpoints =\r\n            numDelegateStakingCheckpoints[delegatee][lockedTS];\r\n        uint96 staked =\r\n            delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1]\r\n                .stake;\r\n        uint96 newStake =\r\n            add96(\r\n                staked,\r\n                value,\r\n                \"Staking::_increaseDelegateeStake: staked amount overflow\"\r\n            );\r\n        _writeDelegateCheckpoint(delegatee, lockedTS, nCheckpoints, newStake);\r\n    }\r\n\r\n    /**\r\n     * @notice decreases the delegatee's stake for a giving lock date and writes a checkpoint\r\n     * @param delegatee the delegatee\r\n     * @param lockedTS the lock date\r\n     * @param value the value to add to the staked balance\r\n     * */\r\n    function _decreaseDelegateStake(\r\n        address delegatee,\r\n        uint256 lockedTS,\r\n        uint96 value\r\n    ) internal {\r\n        uint32 nCheckpoints =\r\n            numDelegateStakingCheckpoints[delegatee][lockedTS];\r\n        uint96 staked =\r\n            delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1]\r\n                .stake;\r\n        uint96 newStake =\r\n            sub96(\r\n                staked,\r\n                value,\r\n                \"Staking::_decreaseDailyStake: staked amount underflow\"\r\n            );\r\n        _writeDelegateCheckpoint(delegatee, lockedTS, nCheckpoints, newStake);\r\n    }\r\n\r\n    function _writeDelegateCheckpoint(\r\n        address delegatee,\r\n        uint256 lockedTS,\r\n        uint32 nCheckpoints,\r\n        uint96 newStake\r\n    ) internal {\r\n        uint32 blockNumber =\r\n            safe32(\r\n                block.number,\r\n                \"Staking::_writeStakingCheckpoint: block number exceeds 32 bits\"\r\n            );\r\n        uint96 oldStake =\r\n            delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1]\r\n                .stake;\r\n\r\n        if (\r\n            nCheckpoints > 0 &&\r\n            delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1]\r\n                .fromBlock ==\r\n            blockNumber\r\n        ) {\r\n            delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1]\r\n                .stake = newStake;\r\n        } else {\r\n            delegateStakingCheckpoints[delegatee][lockedTS][\r\n                nCheckpoints\r\n            ] = Checkpoint(blockNumber, newStake);\r\n            numDelegateStakingCheckpoints[delegatee][lockedTS] =\r\n                nCheckpoints +\r\n                1;\r\n        }\r\n        emit DelegateStakeChanged(delegatee, lockedTS, oldStake, newStake);\r\n    }\r\n\r\n    function _increaseDailyStake(uint256 lockedTS, uint96 value) internal {\r\n        uint32 nCheckpoints = numTotalStakingCheckpoints[lockedTS];\r\n        uint96 staked =\r\n            totalStakingCheckpoints[lockedTS][nCheckpoints - 1].stake;\r\n        uint96 newStake =\r\n            add96(\r\n                staked,\r\n                value,\r\n                \"Staking::_increaseDailyStake: staked amount overflow\"\r\n            );\r\n        _writeStakingCheckpoint(lockedTS, nCheckpoints, newStake);\r\n    }\r\n\r\n    function _decreaseDailyStake(uint256 lockedTS, uint96 value) internal {\r\n        uint32 nCheckpoints = numTotalStakingCheckpoints[lockedTS];\r\n        uint96 staked =\r\n            totalStakingCheckpoints[lockedTS][nCheckpoints - 1].stake;\r\n        uint96 newStake =\r\n            sub96(\r\n                staked,\r\n                value,\r\n                \"Staking::_decreaseDailyStake: staked amount underflow\"\r\n            );\r\n        _writeStakingCheckpoint(lockedTS, nCheckpoints, newStake);\r\n    }\r\n\r\n    function _writeStakingCheckpoint(\r\n        uint256 lockedTS,\r\n        uint32 nCheckpoints,\r\n        uint96 newStake\r\n    ) internal {\r\n        uint32 blockNumber =\r\n            safe32(\r\n                block.number,\r\n                \"Staking::_writeStakingCheckpoint: block number exceeds 32 bits\"\r\n            );\r\n\r\n        if (\r\n            nCheckpoints > 0 &&\r\n            totalStakingCheckpoints[lockedTS][nCheckpoints - 1].fromBlock ==\r\n            blockNumber\r\n        ) {\r\n            totalStakingCheckpoints[lockedTS][nCheckpoints - 1]\r\n                .stake = newStake;\r\n        } else {\r\n            totalStakingCheckpoints[lockedTS][nCheckpoints] = Checkpoint(\r\n                blockNumber,\r\n                newStake\r\n            );\r\n            numTotalStakingCheckpoints[lockedTS] = nCheckpoints + 1;\r\n        }\r\n    }\r\n}\r\n\r\ncontract WeightedStaking is Checkpoints {\r\n    /************* TOTAL VOTING POWER COMPUTATION ************************/\r\n\r\n    /**\r\n     * @notice computes the total voting power at a given time\r\n     * @param time the timestamp for which to calculate the total voting power\r\n     * @return the total voting power at the given time\r\n     * */\r\n    function getPriorTotalVotingPower(uint32 blockNumber, uint256 time)\r\n        public\r\n        view\r\n        returns (uint96 totalVotingPower)\r\n    {\r\n        //start the computation with the exact or previous unlocking date (voting weight remians the same until the next break point)\r\n        uint256 start = timestampToLockDate(time);\r\n        uint256 end = start + MAX_DURATION;\r\n\r\n        //max 78 iterations\r\n        for (uint256 i = start; i <= end; i += TWO_WEEKS) {\r\n            totalVotingPower = add96(\r\n                totalVotingPower,\r\n                _totalPowerByDate(i, start, blockNumber),\r\n                \"WeightedStaking::getPriorTotalVotingPower: overflow on total voting power computation\"\r\n            );\r\n        }\r\n    }\r\n\r\n    /**\r\n     * @notice computes the voting power for a secific date\r\n     * @param date the staking date to compute the power for\r\n     * @param startDate the date for which we need to know the power of the stake\r\n     * @param blockNumber the block number. needed for checkpointing.\r\n     * */\r\n    function _totalPowerByDate(\r\n        uint256 date,\r\n        uint256 startDate,\r\n        uint256 blockNumber\r\n    ) internal view returns (uint96 power) {\r\n        uint96 weight = computeWeightByDate(date, startDate);\r\n        uint96 staked = getPriorTotalStakesForDate(date, blockNumber);\r\n        //weight is multiplied by some factor to allow decimals.\r\n        power =\r\n            mul96(\r\n                staked,\r\n                weight,\r\n                \"WeightedStaking::_totalPowerByDate: multiplication overflow\"\r\n            ) /\r\n            WEIGHT_FACTOR;\r\n    }\r\n\r\n    /**\r\n     * @notice Determine the prior number of stake for an unlocking date as of a block number\r\n     * @dev Block number must be a finalized block or else this function will revert to prevent misinformation.\r\n     * @param date The date to check the stakes for\r\n     * @param blockNumber The block number to get the vote balance at\r\n     * @return The number of votes the account had as of the given block\r\n     */\r\n    function getPriorTotalStakesForDate(uint256 date, uint256 blockNumber)\r\n        public\r\n        view\r\n        returns (uint96)\r\n    {\r\n        require(\r\n            blockNumber < block.number,\r\n            \"WeightedStaking::getPriorTotalStakesForDate: not yet determined\"\r\n        );\r\n\r\n        uint32 nCheckpoints = numTotalStakingCheckpoints[date];\r\n        if (nCheckpoints == 0) {\r\n            return 0;\r\n        }\r\n\r\n        // First check most recent balance\r\n        if (\r\n            totalStakingCheckpoints[date][nCheckpoints - 1].fromBlock <=\r\n            blockNumber\r\n        ) {\r\n            return totalStakingCheckpoints[date][nCheckpoints - 1].stake;\r\n        }\r\n\r\n        // Next check implicit zero balance\r\n        if (totalStakingCheckpoints[date][0].fromBlock > blockNumber) {\r\n            return 0;\r\n        }\r\n\r\n        uint32 lower = 0;\r\n        uint32 upper = nCheckpoints - 1;\r\n        while (upper > lower) {\r\n            uint32 center = upper - (upper - lower) / 2; // ceil, avoiding overflow\r\n            Checkpoint memory cp = totalStakingCheckpoints[date][center];\r\n            if (cp.fromBlock == blockNumber) {\r\n                return cp.stake;\r\n            } else if (cp.fromBlock < blockNumber) {\r\n                lower = center;\r\n            } else {\r\n                upper = center - 1;\r\n            }\r\n        }\r\n        return totalStakingCheckpoints[date][lower].stake;\r\n    }\r\n\r\n    /****************************** DELEGATED VOTING POWER COMPUTATION ************************/\r\n\r\n    /**\r\n     * @notice Determine the prior number of votes for a delegatee as of a block number.\r\n     * @dev Block number must be a finalized block or else this function will revert to prevent misinformation.\r\n     *      Used for Voting, not for fee sharing.\r\n     * @param account The address of the account to check\r\n     * @param blockNumber The block number to get the vote balance at\r\n     * @return The number of votes the delegatee had as of the given block\r\n     */\r\n    function getPriorVotes(\r\n        address account,\r\n        uint256 blockNumber,\r\n        uint256 date\r\n    ) public view returns (uint96 votes) {\r\n        //if date is not an exact break point, start weight computation from the previous break point (alternative would be the next)\r\n        uint256 start = timestampToLockDate(date);\r\n        uint256 end = start + MAX_DURATION;\r\n\r\n        //max 78 iterations\r\n        for (uint256 i = start; i <= end; i += TWO_WEEKS) {\r\n            votes = add96(\r\n                votes,\r\n                _totalPowerByDateForDelegatee(account, i, start, blockNumber),\r\n                \"WeightedStaking::getPriorVotes: overflow on total voting power computation\"\r\n            );\r\n        }\r\n    }\r\n\r\n    /**\r\n     * @notice computes the voting power for a secific date\r\n     * @param date the staking date to compute the power for\r\n     * @param startDate the date for which we need to know the power of the stake\r\n     * @param blockNumber the block number. needed for checkpointing.\r\n     * */\r\n    function _totalPowerByDateForDelegatee(\r\n        address account,\r\n        uint256 date,\r\n        uint256 startDate,\r\n        uint256 blockNumber\r\n    ) internal view returns (uint96 power) {\r\n        uint96 weight = computeWeightByDate(date, startDate);\r\n        uint96 staked =\r\n            getPriorStakeByDateForDelegatee(account, date, blockNumber);\r\n        power =\r\n            mul96(\r\n                staked,\r\n                weight,\r\n                \"WeightedStaking::_totalPowerByDateForDelegatee: multiplication overflow\"\r\n            ) /\r\n            WEIGHT_FACTOR;\r\n    }\r\n\r\n    /**\r\n     * @notice Determine the prior number of stake for an account as of a block number\r\n     * @dev Block number must be a finalized block or else this function will revert to prevent misinformation.\r\n     * @param account The address of the account to check\r\n     * @param blockNumber The block number to get the vote balance at\r\n     * @return The number of votes the account had as of the given block\r\n     */\r\n    function getPriorStakeByDateForDelegatee(\r\n        address account,\r\n        uint256 date,\r\n        uint256 blockNumber\r\n    ) public view returns (uint96) {\r\n        require(\r\n            blockNumber < block.number,\r\n            \"WeightedStaking::getPriorStakeByDateForDelegatee: not yet determined\"\r\n        );\r\n\r\n        uint32 nCheckpoints = numDelegateStakingCheckpoints[account][date];\r\n        if (nCheckpoints == 0) {\r\n            return 0;\r\n        }\r\n\r\n        // First check most recent balance\r\n        if (\r\n            delegateStakingCheckpoints[account][date][nCheckpoints - 1]\r\n                .fromBlock <= blockNumber\r\n        ) {\r\n            return\r\n                delegateStakingCheckpoints[account][date][nCheckpoints - 1]\r\n                    .stake;\r\n        }\r\n\r\n        // Next check implicit zero balance\r\n        if (\r\n            delegateStakingCheckpoints[account][date][0].fromBlock > blockNumber\r\n        ) {\r\n            return 0;\r\n        }\r\n\r\n        uint32 lower = 0;\r\n        uint32 upper = nCheckpoints - 1;\r\n        while (upper > lower) {\r\n            uint32 center = upper - (upper - lower) / 2; // ceil, avoiding overflow\r\n            Checkpoint memory cp =\r\n                delegateStakingCheckpoints[account][date][center];\r\n            if (cp.fromBlock == blockNumber) {\r\n                return cp.stake;\r\n            } else if (cp.fromBlock < blockNumber) {\r\n                lower = center;\r\n            } else {\r\n                upper = center - 1;\r\n            }\r\n        }\r\n        return delegateStakingCheckpoints[account][date][lower].stake;\r\n    }\r\n\r\n    /*************************** User Weighted Stake computation for fee sharing *******************************/\r\n\r\n    /**\r\n     * @notice Determine the prior weighted stake for an account as of a block number\r\n     * @dev Block number must be a finalized block or else this function will revert to prevent misinformation.\r\n     *      Used for fee sharing, not voting.\r\n     * @param account The address of the account to check\r\n     * @param blockNumber The block number to get the vote balance at\r\n     * @return The weighted stake the account had as of the given block\r\n     */\r\n    function getPriorWeightedStake(\r\n        address account,\r\n        uint256 blockNumber,\r\n        uint256 date\r\n    ) public view returns (uint96 votes) {\r\n        //if date is not an exact break point, start weight computation from the previous break point (alternative would be the next)\r\n        uint256 start = timestampToLockDate(date);\r\n        uint256 end = start + MAX_DURATION;\r\n\r\n        //max 78 iterations\r\n        for (uint256 i = start; i <= end; i += TWO_WEEKS) {\r\n            uint96 weightedStake =\r\n                weightedStakeByDate(account, i, start, blockNumber);\r\n            if (weightedStake > 0) {\r\n                votes = add96(\r\n                    votes,\r\n                    weightedStake,\r\n                    \"WeightedStaking::getPriorWeightedStake: overflow on total weight computation\"\r\n                );\r\n            }\r\n        }\r\n    }\r\n\r\n    /**\r\n     * @notice computes the voting power for a secific date\r\n     * @param date the staking date to compute the power for\r\n     * @param startDate the date for which we need to know the power of the stake\r\n     * @param blockNumber the block number. needed for checkpointing.\r\n     * */\r\n    function weightedStakeByDate(\r\n        address account,\r\n        uint256 date,\r\n        uint256 startDate,\r\n        uint256 blockNumber\r\n    ) public view returns (uint96 power) {\r\n        uint96 staked = getPriorUserStakeByDate(account, date, blockNumber);\r\n        if (staked > 0) {\r\n            uint96 weight = computeWeightByDate(date, startDate);\r\n            power =\r\n                mul96(\r\n                    staked,\r\n                    weight,\r\n                    \"WeightedStaking::weightedStakeByDate: multiplication overflow\"\r\n                ) /\r\n                WEIGHT_FACTOR;\r\n        } else {\r\n            power = 0;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * @notice Determine the prior number of stake for an account until a certain lock date as of a block number\r\n     * @dev Block number must be a finalized block or else this function will revert to prevent misinformation.\r\n     * @param account The address of the account to check\r\n     * @param date the lock date\r\n     * @param blockNumber The block number to get the vote balance at\r\n     * @return The number of votes the account had as of the given block\r\n     */\r\n    function getPriorUserStakeByDate(\r\n        address account,\r\n        uint256 date,\r\n        uint256 blockNumber\r\n    ) public view returns (uint96) {\r\n        require(\r\n            blockNumber < block.number,\r\n            \"WeightedStaking::getPriorUserStakeAndDate: not yet determined\"\r\n        );\r\n\r\n        uint32 nCheckpoints = numUserStakingCheckpoints[account][date];\r\n        if (nCheckpoints == 0) {\r\n            return 0;\r\n        }\r\n\r\n        // First check most recent balance\r\n        if (\r\n            userStakingCheckpoints[account][date][nCheckpoints - 1].fromBlock <=\r\n            blockNumber\r\n        ) {\r\n            return\r\n                userStakingCheckpoints[account][date][nCheckpoints - 1].stake;\r\n        }\r\n\r\n        // Next check implicit zero balance\r\n        if (userStakingCheckpoints[account][date][0].fromBlock > blockNumber) {\r\n            return 0;\r\n        }\r\n\r\n        uint32 lower = 0;\r\n        uint32 upper = nCheckpoints - 1;\r\n        while (upper > lower) {\r\n            uint32 center = upper - (upper - lower) / 2; // ceil, avoiding overflow\r\n            Checkpoint memory cp =\r\n                userStakingCheckpoints[account][date][center];\r\n            if (cp.fromBlock == blockNumber) {\r\n                return cp.stake;\r\n            } else if (cp.fromBlock < blockNumber) {\r\n                lower = center;\r\n            } else {\r\n                upper = center - 1;\r\n            }\r\n        }\r\n        return userStakingCheckpoints[account][date][lower].stake;\r\n    }\r\n\r\n    /**************** SHARED FUNCTIONS *********************/\r\n\r\n    /**\r\n     * @notice compute the weight for a specific date\r\n     * @param date the unlocking date\r\n     * @param startDate we compute the weight for the tokens staked until 'date' on 'startDate'\r\n     * */\r\n    function computeWeightByDate(uint256 date, uint256 startDate)\r\n        public\r\n        pure\r\n        returns (uint96 weight)\r\n    {\r\n        require(\r\n            date >= startDate,\r\n            \"WeightedStaking::computeWeightByDate: date needs to be bigger than startDate\"\r\n        );\r\n        uint256 remainingTime = (date - startDate);\r\n        require(\r\n            MAX_DURATION >= remainingTime,\r\n            \"Staking::computeWeightByDate:remaining time can't be bigger than max duration\"\r\n        );\r\n        // x = max days - remaining days\r\n        uint96 x = uint96(MAX_DURATION - remainingTime) / (1 days);\r\n        //w = (m^2 - x^2)/m^2 +1 (multiplied by the weight factor)\r\n        weight = add96(\r\n            WEIGHT_FACTOR,\r\n            mul96(\r\n                MAX_VOTING_WEIGHT * WEIGHT_FACTOR,\r\n                sub96(\r\n                    MAX_DURATION_POW_2,\r\n                    x * x,\r\n                    \"underflow on weight calculation\"\r\n                ),\r\n                \"multiplication overflow on weight computation\"\r\n            ) / MAX_DURATION_POW_2,\r\n            \"overflow on weight computation\"\r\n        );\r\n    }\r\n\r\n    /**\r\n     * @notice unstaking is posisble every 2 weeks only. this means, to calculate the key value for the staking\r\n     * checkpoints, we need to map the intended timestamp to the closest available date\r\n     * @param timestamp the unlocking timestamp\r\n     * @return the actual unlocking date (might be up to 2 weeks shorter than intended)\r\n     * */\r\n    function timestampToLockDate(uint256 timestamp)\r\n        public\r\n        view\r\n        returns (uint256 lockDate)\r\n    {\r\n        require(\r\n            timestamp >= kickoffTS,\r\n            \"WeightedStaking::timestampToLockDate: timestamp lies before contract creation\"\r\n        );\r\n        //if staking timestamp does not match any of the unstaking dates, set the lockDate to the closest one before the timestamp\r\n        //e.g. passed timestamps lies 7 weeks after kickoff -> only stake for 6 weeks\r\n        uint256 periodFromKickoff = (timestamp - kickoffTS) / TWO_WEEKS;\r\n        lockDate = periodFromKickoff * TWO_WEEKS + kickoffTS;\r\n    }\r\n}\r\n\r\n/**\r\n * Base contract for receiving approval from SOV token\r\n */\r\ncontract ApprovalReceiver is ErrorDecoder, IApproveAndCall {\r\n    modifier onlyThisContract() {\r\n        //accepts calls only from receiveApproval function\r\n        require(msg.sender == address(this), \"unauthorized\");\r\n        _;\r\n    }\r\n\r\n    /**\r\n     * @notice receives approval from SOV token\r\n     * @param _data the data will be used for low level call\r\n     */\r\n    function receiveApproval(\r\n        address _sender,\r\n        uint256 _amount,\r\n        address _token,\r\n        bytes calldata _data\r\n    ) external {\r\n        //accepts calls only from SOV token\r\n        require(msg.sender == _getToken(), \"unauthorized\");\r\n        require(msg.sender == _token, \"unauthorized\");\r\n\r\n        //only allowed methods\r\n        bool isAllowed = false;\r\n        bytes4[] memory selectors = _getSelectors();\r\n        bytes4 sig = _getSig(_data);\r\n        for (uint256 i = 0; i < selectors.length; i++) {\r\n            if (sig == selectors[i]) {\r\n                isAllowed = true;\r\n                break;\r\n            }\r\n        }\r\n        require(isAllowed, \"method is not allowed\");\r\n\r\n        //check sender and amount\r\n        address sender;\r\n        uint256 amount;\r\n        (, sender, amount) = abi.decode(\r\n            abi.encodePacked(bytes28(0), _data),\r\n            (bytes32, address, uint256)\r\n        );\r\n        require(sender == _sender, \"sender mismatch\");\r\n        require(amount == _amount, \"amount mismatch\");\r\n\r\n        _call(_data);\r\n    }\r\n\r\n    /**\r\n     * @notice returns token address, only this address can be a sender for receiveApproval\r\n     * @dev should be overridden in child contracts, otherwise error will be thrown\r\n     */\r\n    function _getToken() internal view returns (address) {\r\n        return address(0);\r\n    }\r\n\r\n    /**\r\n     * @notice returns list of function selectors allowed to be invoked\r\n     * @dev should be overridden in child contracts, otherwise error will be thrown\r\n     */\r\n    function _getSelectors() internal view returns (bytes4[] memory) {\r\n        return new bytes4[](0);\r\n    }\r\n\r\n    function _call(bytes memory _data) internal {\r\n        //makes call and reads error message\r\n        (bool success, bytes memory returnData) = address(this).call(_data);\r\n        if (!success) {\r\n            if (returnData.length <= ERROR_MESSAGE_SHIFT) {\r\n                revert(\"receiveApproval: Transaction execution reverted.\");\r\n            } else {\r\n                revert(\r\n                    _addErrorMessage(\"receiveApproval: \", string(returnData))\r\n                );\r\n            }\r\n        }\r\n    }\r\n\r\n    function _getSig(bytes memory _data) internal pure returns (bytes4 sig) {\r\n        assembly {\r\n            sig := mload(add(_data, 32))\r\n        }\r\n    }\r\n}\r\n\r\ncontract Staking is IStaking, WeightedStaking, ApprovalReceiver {\r\n    /**\r\n     * @notice stakes the given amount for the given duration of time.\r\n     * @param amount the number of tokens to stake\r\n     * @param until timestamp indicating the date until which to stake\r\n     * @param stakeFor the address to stake the tokens for or 0x0 if staking for oneself\r\n     * @param delegatee the address of the delegatee or 0x0 if there is none.\r\n     */\r\n    function stake(\r\n        uint96 amount,\r\n        uint256 until,\r\n        address stakeFor,\r\n        address delegatee\r\n    ) external {\r\n        _stake(msg.sender, amount, until, stakeFor, delegatee, false);\r\n    }\r\n\r\n    /**\r\n     * @notice stakes the given amount for the given duration of time.\r\n     * @dev this function will be invoked from receiveApproval\r\n     * @dev SOV.approveAndCall -> this.receiveApproval -> this.stakeWithApproval\r\n     * @param sender the sender of SOV.approveAndCall\r\n     * @param amount the number of tokens to stake\r\n     * @param until timestamp indicating the date until which to stake\r\n     * @param stakeFor the address to stake the tokens for or 0x0 if staking for oneself\r\n     * @param delegatee the address of the delegatee or 0x0 if there is none.\r\n     */\r\n    function stakeWithApproval(\r\n        address sender,\r\n        uint96 amount,\r\n        uint256 until,\r\n        address stakeFor,\r\n        address delegatee\r\n    ) public onlyThisContract {\r\n        _stake(sender, amount, until, stakeFor, delegatee, false);\r\n    }\r\n\r\n    function _stake(\r\n        address sender,\r\n        uint96 amount,\r\n        uint256 until,\r\n        address stakeFor,\r\n        address delegatee,\r\n        bool timeAdjusted\r\n    ) internal {\r\n        require(\r\n            amount > 0,\r\n            \"Staking::stake: amount of tokens to stake needs to be bigger than 0\"\r\n        );\r\n\r\n        if (!timeAdjusted) {\r\n            until = timestampToLockDate(until);\r\n        }\r\n        require(\r\n            until > block.timestamp,\r\n            \"Staking::timestampToLockDate: staking period too short\"\r\n        );\r\n\r\n        //stake for the sender if not specified otherwise\r\n        if (stakeFor == address(0)) {\r\n            stakeFor = sender;\r\n        }\r\n        //delegate for stakeFor if not specified otherwise\r\n        if (delegatee == address(0)) {\r\n            delegatee = stakeFor;\r\n        }\r\n        //do not stake longer than the max duration\r\n        if (!timeAdjusted) {\r\n            uint256 latest =\r\n                timestampToLockDate(block.timestamp + MAX_DURATION);\r\n            if (until > latest) until = latest;\r\n        }\r\n\r\n        uint96 previousBalance = currentBalance(stakeFor, until);\r\n        //increase stake\r\n        _increaseStake(sender, amount, stakeFor, until);\r\n\r\n        if (previousBalance == 0) {\r\n            //regular delegation if it's a first stake\r\n            _delegate(stakeFor, delegatee, until);\r\n        } else {\r\n            address previousDelegatee = delegates[stakeFor][until];\r\n            if (previousDelegatee != delegatee) {\r\n                //update delegatee\r\n                delegates[stakeFor][until] = delegatee;\r\n                //decrease stake on previous balance for previous delegatee\r\n                _decreaseDelegateStake(\r\n                    previousDelegatee,\r\n                    until,\r\n                    previousBalance\r\n                );\r\n                //add previousBalance to amount\r\n                amount = add96(\r\n                    previousBalance,\r\n                    amount,\r\n                    \"Staking::stake: balance overflow\"\r\n                );\r\n            }\r\n            //increase stake\r\n            _increaseDelegateStake(delegatee, until, amount);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * @notice extends the staking duration until the specified date\r\n     * @param previousLock the old unlocking timestamp\r\n     * @param until the new unlocking timestamp in S\r\n     * */\r\n    function extendStakingDuration(uint256 previousLock, uint256 until) public {\r\n        until = timestampToLockDate(until);\r\n        require(\r\n            previousLock <= until,\r\n            \"Staking::extendStakingDuration: cannot reduce the staking duration\"\r\n        );\r\n\r\n        //do not exceed the max duration, no overflow possible\r\n        uint256 latest = timestampToLockDate(block.timestamp + MAX_DURATION);\r\n        if (until > latest) until = latest;\r\n\r\n        //update checkpoints\r\n        //todo James: can reading stake at block.number -1 cause trouble with multiple tx in a block?\r\n        uint96 amount =\r\n            getPriorUserStakeByDate(msg.sender, previousLock, block.number - 1);\r\n        require(\r\n            amount > 0,\r\n            \"Staking::extendStakingDuration: nothing staked until the previous lock date\"\r\n        );\r\n        _decreaseUserStake(msg.sender, previousLock, amount);\r\n        _increaseUserStake(msg.sender, until, amount);\r\n        _decreaseDailyStake(previousLock, amount);\r\n        _increaseDailyStake(until, amount);\r\n        //delegate might change: if there is already a delegate set for the until date, it will remain the delegate for this position\r\n        address delegateFrom = delegates[msg.sender][previousLock];\r\n        address delegateTo = delegates[msg.sender][until];\r\n        if (delegateTo == address(0)) {\r\n            delegateTo = delegateFrom;\r\n            delegates[msg.sender][until] = delegateFrom;\r\n        }\r\n        delegates[msg.sender][previousLock] = address(0);\r\n        _decreaseDelegateStake(delegateFrom, previousLock, amount);\r\n        _increaseDelegateStake(delegateTo, until, amount);\r\n\r\n        emit ExtendedStakingDuration(msg.sender, previousLock, until);\r\n    }\r\n\r\n    function _increaseStake(\r\n        address sender,\r\n        uint96 amount,\r\n        address stakeFor,\r\n        uint256 until\r\n    ) internal {\r\n        //retrieve the SOV tokens\r\n        bool success = SOVToken.transferFrom(sender, address(this), amount);\r\n        require(success);\r\n\r\n        //increase staked balance\r\n        uint96 balance = currentBalance(stakeFor, until);\r\n        balance = add96(\r\n            balance,\r\n            amount,\r\n            \"Staking::increaseStake: balance overflow\"\r\n        );\r\n\r\n        //update checkpoints\r\n        _increaseDailyStake(until, amount);\r\n        _increaseUserStake(stakeFor, until, amount);\r\n\r\n        emit TokensStaked(stakeFor, amount, until, balance);\r\n    }\r\n\r\n    /**\r\n     * @notice stakes tokens according to the vesting schedule\r\n     * @param amount the amount of tokens to stake\r\n     * @param cliff the time interval to the first withdraw\r\n     * @param duration the staking duration\r\n     * @param intervalLength the length of each staking interval when cliff passed\r\n     * @param stakeFor the address to stake the tokens for or 0x0 if staking for oneself\r\n     * @param delegatee the address of the delegatee or 0x0 if there is none.\r\n     * */\r\n    function stakesBySchedule(\r\n        uint256 amount,\r\n        uint256 cliff,\r\n        uint256 duration,\r\n        uint256 intervalLength,\r\n        address stakeFor,\r\n        address delegatee\r\n    ) public {\r\n        //stake them until lock dates according to the vesting schedule\r\n        //note: because staking is only possible in periods of 2 weeks, the total duration might\r\n        //end up a bit shorter than specified depending on the date of staking.\r\n        uint256 start = timestampToLockDate(block.timestamp + cliff);\r\n        if (duration > MAX_DURATION) {\r\n            duration = MAX_DURATION;\r\n        }\r\n        uint256 end = timestampToLockDate(block.timestamp + duration);\r\n        uint256 numIntervals = (end - start) / intervalLength + 1;\r\n        uint256 stakedPerInterval = amount / numIntervals;\r\n        //stakedPerInterval might lose some dust on rounding. add it to the first staking date\r\n        if (numIntervals >= 1) {\r\n            _stake(\r\n                msg.sender,\r\n                uint96(amount - stakedPerInterval * (numIntervals - 1)),\r\n                start,\r\n                stakeFor,\r\n                delegatee,\r\n                true\r\n            );\r\n        }\r\n        //stake the rest in 4 week intervals\r\n        for (\r\n            uint256 i = start + intervalLength;\r\n            i <= end;\r\n            i += intervalLength\r\n        ) {\r\n            //stakes for itself, delegates to the owner\r\n            _stake(\r\n                msg.sender,\r\n                uint96(stakedPerInterval),\r\n                i,\r\n                stakeFor,\r\n                delegatee,\r\n                true\r\n            );\r\n        }\r\n    }\r\n\r\n    /**\r\n     * @notice withdraws the given amount of tokens if they are unlocked\r\n     * @param amount the number of tokens to withdraw\r\n     * @param until the date until which the tokens were staked\r\n     * @param receiver the receiver of the tokens. If not specified, send to the msg.sender\r\n     * */\r\n    function withdraw(\r\n        uint96 amount,\r\n        uint256 until,\r\n        address receiver\r\n    ) public {\r\n        _withdraw(amount, until, receiver, false);\r\n    }\r\n\r\n    /**\r\n     * @notice withdraws the given amount of tokens\r\n     * @param amount the number of tokens to withdraw\r\n     * @param until the date until which the tokens were staked\r\n     * @param receiver the receiver of the tokens. If not specified, send to the msg.sender\r\n     * @dev can be invoked only by whitelisted contract passed to governanceWithdrawVesting\r\n     * */\r\n    function governanceWithdraw(\r\n        uint96 amount,\r\n        uint256 until,\r\n        address receiver\r\n    ) public {\r\n        require(vestingWhitelist[msg.sender], \"unauthorized\");\r\n\r\n        _withdraw(amount, until, receiver, true);\r\n    }\r\n\r\n    /**\r\n     * @notice withdraws tokens for vesting contact\r\n     * @param vesting the address of Vesting contract\r\n     * @param receiver the receiver of the tokens. If not specified, send to the msg.sender\r\n     * @dev can be invoked only by whitelisted contract passed to governanceWithdrawVesting\r\n     * */\r\n    function governanceWithdrawVesting(address vesting, address receiver)\r\n        public\r\n        onlyOwner\r\n    {\r\n        vestingWhitelist[vesting] = true;\r\n        ITeamVesting(vesting).governanceWithdrawTokens(receiver);\r\n        vestingWhitelist[vesting] = false;\r\n\r\n        emit VestingTokensWithdrawn(vesting, receiver);\r\n    }\r\n\r\n    function _withdraw(\r\n        uint96 amount,\r\n        uint256 until,\r\n        address receiver,\r\n        bool isGovernance\r\n    ) internal {\r\n        _validateWithdrawParams(amount, until);\r\n\r\n        //determine the receiver\r\n        if (receiver == address(0)) receiver = msg.sender;\r\n\r\n        //update the checkpoints\r\n        _decreaseDailyStake(until, amount);\r\n        _decreaseUserStake(msg.sender, until, amount);\r\n        _decreaseDelegateStake(delegates[msg.sender][until], until, amount);\r\n\r\n        //early unstaking should be punished\r\n        if (block.timestamp < until && !allUnlocked && !isGovernance) {\r\n            uint96 punishedAmount = _getPunishedAmount(amount, until);\r\n            amount -= punishedAmount;\r\n\r\n            //punishedAmount can be 0 if block.timestamp are very close to 'until'\r\n            if (punishedAmount > 0) {\r\n                require(\r\n                    address(feeSharing) != address(0),\r\n                    \"Staking::withdraw: FeeSharing address wasn't set\"\r\n                );\r\n                //move punished amount to fee sharing\r\n                //approve transfer here and let feeSharing do transfer and write checkpoint\r\n                SOVToken.approve(address(feeSharing), punishedAmount);\r\n                feeSharing.transferTokens(address(SOVToken), punishedAmount);\r\n            }\r\n        }\r\n\r\n        //transferFrom\r\n        bool success = SOVToken.transfer(receiver, amount);\r\n        require(success, \"Staking::withdraw: Token transfer failed\");\r\n\r\n        emit TokensWithdrawn(msg.sender, receiver, amount);\r\n    }\r\n\r\n    /**\r\n     * @notice returns available and punished amount for withdrawing\r\n     * @param amount the number of tokens to withdraw\r\n     * @param until the date until which the tokens were staked\r\n     * */\r\n    function getWithdrawAmounts(uint96 amount, uint256 until)\r\n        public\r\n        view\r\n        returns (uint96, uint96)\r\n    {\r\n        _validateWithdrawParams(amount, until);\r\n        uint96 punishedAmount = _getPunishedAmount(amount, until);\r\n        return (amount - punishedAmount, punishedAmount);\r\n    }\r\n\r\n    /**\r\n     * @notice returns punished amount for withdrawing\r\n     * @param amount the number of tokens to withdraw\r\n     * @param until the date until which the tokens were staked\r\n     * */\r\n    function _getPunishedAmount(uint96 amount, uint256 until)\r\n        internal\r\n        view\r\n        returns (uint96)\r\n    {\r\n        uint256 date = timestampToLockDate(block.timestamp);\r\n        uint96 weight = computeWeightByDate(until, date); // (10 - 1) * WEIGHT_FACTOR\r\n        weight = weight * weightScaling;\r\n        return (amount * weight) / WEIGHT_FACTOR / 100;\r\n    }\r\n\r\n    /**\r\n     * @notice validates withdraw parameters\r\n     * @param amount the number of tokens to withdraw\r\n     * @param until the date until which the tokens were staked\r\n     * */\r\n    function _validateWithdrawParams(uint96 amount, uint256 until)\r\n        internal\r\n        view\r\n    {\r\n        require(\r\n            amount > 0,\r\n            \"Staking::withdraw: amount of tokens to be withdrawn needs to be bigger than 0\"\r\n        );\r\n        uint96 balance =\r\n            getPriorUserStakeByDate(msg.sender, until, block.number - 1);\r\n        require(amount <= balance, \"Staking::withdraw: not enough balance\");\r\n    }\r\n\r\n    /**\r\n     * @notice returns the current balance of for an account locked until a certain date\r\n     * @param account the user address\r\n     * @param lockDate the lock date\r\n     * @return the lock date of the last checkpoint\r\n     * */\r\n    function currentBalance(address account, uint256 lockDate)\r\n        internal\r\n        view\r\n        returns (uint96)\r\n    {\r\n        return\r\n            userStakingCheckpoints[account][lockDate][\r\n                numUserStakingCheckpoints[account][lockDate] - 1\r\n            ]\r\n                .stake;\r\n    }\r\n\r\n    /**\r\n     * @notice Get the number of staked tokens held by the `account`\r\n     * @param account The address of the account to get the balance of\r\n     * @return The number of tokens held\r\n     */\r\n    function balanceOf(address account) public view returns (uint96 balance) {\r\n        for (\r\n            uint256 i = kickoffTS;\r\n            i <= block.timestamp + MAX_DURATION;\r\n            i += TWO_WEEKS\r\n        ) {\r\n            balance = add96(\r\n                balance,\r\n                currentBalance(account, i),\r\n                \"Staking::balanceOf: overflow\"\r\n            );\r\n        }\r\n    }\r\n\r\n    /**\r\n     * @notice Delegate votes from `msg.sender` which are locked until lockDate to `delegatee`\r\n     * @param delegatee The address to delegate votes to\r\n     * @param lockDate the date if the position to delegate\r\n     */\r\n    function delegate(address delegatee, uint256 lockDate) public {\r\n        return _delegate(msg.sender, delegatee, lockDate);\r\n    }\r\n\r\n    /**\r\n     * @notice Delegates votes from signatory to `delegatee`\r\n     * @param delegatee The address to delegate votes to\r\n     * @param lockDate the date until which the position is locked\r\n     * @param nonce The contract state required to match the signature\r\n     * @param expiry The time at which to expire the signature\r\n     * @param v The recovery byte of the signature\r\n     * @param r Half of the ECDSA signature pair\r\n     * @param s Half of the ECDSA signature pair\r\n     */\r\n    function delegateBySig(\r\n        address delegatee,\r\n        uint256 lockDate,\r\n        uint256 nonce,\r\n        uint256 expiry,\r\n        uint8 v,\r\n        bytes32 r,\r\n        bytes32 s\r\n    ) public {\r\n        bytes32 domainSeparator =\r\n            keccak256(\r\n                abi.encode(\r\n                    DOMAIN_TYPEHASH,\r\n                    keccak256(bytes(name)),\r\n                    getChainId(),\r\n                    address(this)\r\n                )\r\n            );\r\n        bytes32 structHash =\r\n            keccak256(\r\n                abi.encode(\r\n                    DELEGATION_TYPEHASH,\r\n                    delegatee,\r\n                    lockDate,\r\n                    nonce,\r\n                    expiry\r\n                )\r\n            );\r\n        bytes32 digest =\r\n            keccak256(\r\n                abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash)\r\n            );\r\n        address signatory = ecrecover(digest, v, r, s);\r\n        require(\r\n            RSKAddrValidator.checkPKNotZero(signatory),\r\n            \"Staking::delegateBySig: invalid signature\"\r\n        );\r\n        require(\r\n            nonce == nonces[signatory]++,\r\n            \"Staking::delegateBySig: invalid nonce\"\r\n        );\r\n        require(now <= expiry, \"Staking::delegateBySig: signature expired\");\r\n        return _delegate(signatory, delegatee, lockDate);\r\n    }\r\n\r\n    /**\r\n     * @notice Gets the current votes balance for `account`\r\n     * @param account The address to get votes balance\r\n     * @return The number of current votes for `account`\r\n     */\r\n    function getCurrentVotes(address account) external view returns (uint96) {\r\n        return getPriorVotes(account, block.number - 1, block.timestamp);\r\n    }\r\n\r\n    /**\r\n     * @notice gets the current number of tokens staked for a day\r\n     * @param lockedTS the timestamp to get the staked tokens for\r\n     */\r\n    function getCurrentStakedUntil(uint256 lockedTS)\r\n        external\r\n        view\r\n        returns (uint96)\r\n    {\r\n        uint32 nCheckpoints = numTotalStakingCheckpoints[lockedTS];\r\n        return\r\n            nCheckpoints > 0\r\n                ? totalStakingCheckpoints[lockedTS][nCheckpoints - 1].stake\r\n                : 0;\r\n    }\r\n\r\n    function _delegate(\r\n        address delegator,\r\n        address delegatee,\r\n        uint256 lockedTS\r\n    ) internal {\r\n        address currentDelegate = delegates[delegator][lockedTS];\r\n        uint96 delegatorBalance = currentBalance(delegator, lockedTS);\r\n        delegates[delegator][lockedTS] = delegatee;\r\n\r\n        emit DelegateChanged(delegator, lockedTS, currentDelegate, delegatee);\r\n\r\n        _moveDelegates(currentDelegate, delegatee, delegatorBalance, lockedTS);\r\n    }\r\n\r\n    function _moveDelegates(\r\n        address srcRep,\r\n        address dstRep,\r\n        uint96 amount,\r\n        uint256 lockedTS\r\n    ) internal {\r\n        if (srcRep != dstRep && amount > 0) {\r\n            if (srcRep != address(0))\r\n                _decreaseDelegateStake(srcRep, lockedTS, amount);\r\n\r\n            if (dstRep != address(0))\r\n                _increaseDelegateStake(dstRep, lockedTS, amount);\r\n        }\r\n    }\r\n\r\n    function getChainId() internal pure returns (uint256) {\r\n        uint256 chainId;\r\n        assembly {\r\n            chainId := chainid()\r\n        }\r\n        return chainId;\r\n    }\r\n\r\n    /**\r\n     * @notice allows the owner to set a new staking contract. as a consequence it allows the stakers to migrate their positions\r\n     * to the new contract.\r\n     * @dev doesn't have any influence as long as migrateToNewStakingContract is not implemented.\r\n     * @param _newStakingContract the address of the new staking contract\r\n     */\r\n    function setNewStakingContract(address _newStakingContract)\r\n        public\r\n        onlyOwner\r\n    {\r\n        require(\r\n            _newStakingContract != address(0),\r\n            \"can't reset the new staking contract to 0\"\r\n        );\r\n        newStakingContract = _newStakingContract;\r\n    }\r\n\r\n    /**\r\n     * @notice allows the owner to set a fee sharing proxy contract, we need it for unstaking with slashing.\r\n     * @param _feeSharing the address of FeeSharingProxy contract\r\n     */\r\n    function setFeeSharing(address _feeSharing) public onlyOwner {\r\n        require(_feeSharing != address(0), \"FeeSharing address shouldn't be 0\");\r\n        feeSharing = IFeeSharingProxy(_feeSharing);\r\n    }\r\n\r\n    /**\r\n     * @notice allows the owner to set weight scaling, we need it for unstaking with slashing.\r\n     * @param _weightScaling the weight scaling\r\n     */\r\n    function setWeightScaling(uint96 _weightScaling) public onlyOwner {\r\n        require(\r\n            MIN_WEIGHT_SCALING <= _weightScaling &&\r\n                _weightScaling <= MAX_WEIGHT_SCALING,\r\n            \"weight scaling doesn't belong to range [1, 9]\"\r\n        );\r\n        weightScaling = _weightScaling;\r\n    }\r\n\r\n    /**\r\n     * @notice allows a staker to migrate his positions to the new staking contract.\r\n     * @dev staking contract needs to be set before by the owner. currently not implemented, just needed for the interface.\r\n     *      in case it's needed at some point in the future, the implementation needs to be changed first.\r\n     */\r\n    function migrateToNewStakingContract() public {\r\n        require(\r\n            newStakingContract != address(0),\r\n            \"there is no new staking contract set\"\r\n        );\r\n        //implementation:\r\n        //iterate over all possible lock dates from now until now + MAX_DURATION\r\n        //read the stake & delegate of the msg.sender\r\n        //if stake > 0, stake it at the new contract until the lock date with the current delegate\r\n    }\r\n\r\n    /**\r\n     * @notice allow the owner to unlock all tokens in case the staking contract is going to be replaced\r\n     * note: not reversible on purpose. once unlocked, everything is unlocked. the owner should not be able to just quickly\r\n     * unlock to withdraw his own tokens and lock again.\r\n     * @dev last resort.\r\n     */\r\n    function unlockAllTokens() public onlyOwner {\r\n        allUnlocked = true;\r\n        emit TokensUnlocked(SOVToken.balanceOf(address(this)));\r\n    }\r\n\r\n    /**\r\n     * @notice Gets list of stakes for `account`\r\n     * @param account The address to get stakes\r\n     * @return The arrays of dates and stakes\r\n     */\r\n    function getStakes(address account)\r\n        external\r\n        view\r\n        returns (uint256[] memory dates, uint96[] memory stakes)\r\n    {\r\n        uint256 latest = timestampToLockDate(block.timestamp + MAX_DURATION);\r\n\r\n        //calculate stakes\r\n        uint256 count = 0;\r\n        //we need to iterate from first possible stake date after deployment to the latest from current time\r\n        for (uint256 i = kickoffTS + TWO_WEEKS; i <= latest; i += TWO_WEEKS) {\r\n            if (currentBalance(account, i) > 0) {\r\n                count++;\r\n            }\r\n        }\r\n        dates = new uint256[](count);\r\n        stakes = new uint96[](count);\r\n\r\n        //we need to iterate from first possible stake date after deployment to the latest from current time\r\n        uint256 j = 0;\r\n        for (uint256 i = kickoffTS + TWO_WEEKS; i <= latest; i += TWO_WEEKS) {\r\n            uint96 balance = currentBalance(account, i);\r\n            if (balance > 0) {\r\n                dates[j] = i;\r\n                stakes[j] = balance;\r\n                j++;\r\n            }\r\n        }\r\n    }\r\n\r\n    function _getToken() internal view returns (address) {\r\n        return address(SOVToken);\r\n    }\r\n\r\n    function _getSelectors() internal view returns (bytes4[] memory) {\r\n        bytes4[] memory selectors = new bytes4[](1);\r\n        selectors[0] = this.stakeWithApproval.selector;\r\n        return selectors;\r\n    }\r\n}\r\n\r\ncontract GovernorAlpha is SafeMath96 {\r\n    /// @notice The name of this contract\r\n    string public constant NAME = \"Sovryn Governor Alpha\";\r\n\r\n    /// @notice The maximum number of actions that can be included in a proposal\r\n    function proposalMaxOperations() public pure returns (uint256) {\r\n        return 10;\r\n    } // 10 actions\r\n\r\n    /// @notice The delay before voting on a proposal may take place, once proposed\r\n    function votingDelay() public pure returns (uint256) {\r\n        return 1;\r\n    } // 1 block\r\n\r\n    /// @notice The duration of voting on a proposal, in blocks\r\n    function votingPeriod() public pure returns (uint256) {\r\n        return 2880;\r\n    } // ~1 day in blocks (assuming 30s blocks)\r\n\r\n    /// @notice The address of the Sovryn Protocol Timelock\r\n    ITimelock public timelock;\r\n\r\n    /// @notice The address of the Sovryn staking contract\r\n    IStaking public staking;\r\n\r\n    /// @notice The address of the Governor Guardian\r\n    address public guardian;\r\n\r\n    /// @notice The total number of proposals\r\n    uint256 public proposalCount;\r\n\r\n    /// @notice Percentage of current total voting power require to vote.\r\n    uint96 public quorumPercentageVotes;\r\n\r\n    // @notice Majority percentage\r\n    uint96 public majorityPercentageVotes;\r\n\r\n    struct Proposal {\r\n        /// @notice Unique id for looking up a proposal\r\n        uint256 id;\r\n        /// @notice The block at which voting begins: holders must delegate their votes prior to this block\r\n        uint32 startBlock;\r\n        /// @notice The block at which voting ends: votes must be cast prior to this block\r\n        uint32 endBlock;\r\n        /// @notice Current number of votes in favor of this proposal\r\n        uint96 forVotes;\r\n        /// @notice Current number of votes in opposition to this proposal\r\n        uint96 againstVotes;\r\n        ///@notice the quorum required for this proposal\r\n        uint96 quorum;\r\n        ///@notice the majority percentage required for this proposal\r\n        uint96 majorityPercentage;\r\n        /// @notice The timestamp that the proposal will be available for execution, set once the vote succeeds\r\n        uint64 eta;\r\n        /// @notice the start time is required for the staking contract\r\n        uint64 startTime;\r\n        /// @notice Flag marking whether the proposal has been canceled\r\n        bool canceled;\r\n        /// @notice Flag marking whether the proposal has been executed\r\n        bool executed;\r\n        /// @notice Creator of the proposal\r\n        address proposer;\r\n        /// @notice the ordered list of target addresses for calls to be made\r\n        address[] targets;\r\n        /// @notice The ordered list of values (i.e. msg.value) to be passed to the calls to be made\r\n        uint256[] values;\r\n        /// @notice The ordered list of function signatures to be called\r\n        string[] signatures;\r\n        /// @notice The ordered list of calldata to be passed to each call\r\n        bytes[] calldatas;\r\n        /// @notice Receipts of ballots for the entire set of voters\r\n        mapping(address => Receipt) receipts;\r\n    }\r\n\r\n    /// @notice Ballot receipt record for a voter\r\n    struct Receipt {\r\n        /// @notice Whether or not a vote has been cast\r\n        bool hasVoted;\r\n        /// @notice Whether or not the voter supports the proposal\r\n        bool support;\r\n        /// @notice The number of votes the voter had, which were cast\r\n        uint96 votes;\r\n    }\r\n\r\n    /// @notice Possible states that a proposal may be in\r\n    enum ProposalState {\r\n        Pending,\r\n        Active,\r\n        Canceled,\r\n        Defeated,\r\n        Succeeded,\r\n        Queued,\r\n        Expired,\r\n        Executed\r\n    }\r\n\r\n    /// @notice The official record of all proposals ever proposed\r\n    mapping(uint256 => Proposal) public proposals;\r\n\r\n    /// @notice The latest proposal for each proposer\r\n    mapping(address => uint256) public latestProposalIds;\r\n\r\n    /// @notice The EIP-712 typehash for the contract's domain\r\n    bytes32 public constant DOMAIN_TYPEHASH =\r\n        keccak256(\r\n            \"EIP712Domain(string name,uint256 chainId,address verifyingContract)\"\r\n        );\r\n\r\n    /// @notice The EIP-712 typehash for the ballot struct used by the contract\r\n    bytes32 public constant BALLOT_TYPEHASH =\r\n        keccak256(\"Ballot(uint256 proposalId,bool support)\");\r\n\r\n    /// @notice An event emitted when a new proposal is created\r\n    event ProposalCreated(\r\n        uint256 id,\r\n        address proposer,\r\n        address[] targets,\r\n        uint256[] values,\r\n        string[] signatures,\r\n        bytes[] calldatas,\r\n        uint256 startBlock,\r\n        uint256 endBlock,\r\n        string description\r\n    );\r\n\r\n    /// @notice An event emitted when a vote has been cast on a proposal\r\n    event VoteCast(\r\n        address voter,\r\n        uint256 proposalId,\r\n        bool support,\r\n        uint256 votes\r\n    );\r\n\r\n    /// @notice An event emitted when a proposal has been canceled\r\n    event ProposalCanceled(uint256 id);\r\n\r\n    /// @notice An event emitted when a proposal has been queued in the Timelock\r\n    event ProposalQueued(uint256 id, uint256 eta);\r\n\r\n    /// @notice An event emitted when a proposal has been executed in the Timelock\r\n    event ProposalExecuted(uint256 id);\r\n\r\n    constructor(\r\n        address timelock_,\r\n        address staking_,\r\n        address guardian_,\r\n        uint96 _quorumPercentageVotes,\r\n        uint96 _majorityPercentageVotes\r\n    ) public {\r\n        timelock = ITimelock(timelock_);\r\n        staking = IStaking(staking_);\r\n        guardian = guardian_;\r\n        quorumPercentageVotes = _quorumPercentageVotes;\r\n        majorityPercentageVotes = _majorityPercentageVotes;\r\n    }\r\n\r\n    /// @notice The number of votes required in order for a voter to become a proposer\r\n    function proposalThreshold() public view returns (uint96) {\r\n        uint96 totalVotingPower =\r\n            staking.getPriorTotalVotingPower(\r\n                safe32(\r\n                    block.number - 1,\r\n                    \"GovernorAlpha::proposalThreshold: block number overflow\"\r\n                ),\r\n                block.timestamp\r\n            );\r\n        //1% of current total voting power\r\n        return totalVotingPower / 100;\r\n    }\r\n\r\n    /// @notice The number of votes in support of a proposal required in order for a quorum to be reached and for a vote to succeed\r\n    function quorumVotes() public view returns (uint96) {\r\n        uint96 totalVotingPower =\r\n            staking.getPriorTotalVotingPower(\r\n                safe32(\r\n                    block.number - 1,\r\n                    \"GovernorAlpha::quorumVotes: block number overflow\"\r\n                ),\r\n                block.timestamp\r\n            );\r\n        //4% of current total voting power\r\n        return\r\n            mul96(\r\n                quorumPercentageVotes,\r\n                totalVotingPower,\r\n                \"GovernorAlpha::quorumVotes:multiplication overflow\"\r\n            ) / 100;\r\n    }\r\n\r\n    function propose(\r\n        address[] memory targets,\r\n        uint256[] memory values,\r\n        string[] memory signatures,\r\n        bytes[] memory calldatas,\r\n        string memory description\r\n    ) public returns (uint256) {\r\n        //note: passing this block's timestamp, but the number of the previous block\r\n        //todo: think if it would be better to pass block.timestamp - 30 (average block time) (probably not because proposal starts in 1 block from now)\r\n        uint96 threshold = proposalThreshold();\r\n        require(\r\n            staking.getPriorVotes(\r\n                msg.sender,\r\n                sub256(block.number, 1),\r\n                block.timestamp\r\n            ) > threshold,\r\n            \"GovernorAlpha::propose: proposer votes below proposal threshold\"\r\n        );\r\n        require(\r\n            targets.length == values.length &&\r\n                targets.length == signatures.length &&\r\n                targets.length == calldatas.length,\r\n            \"GovernorAlpha::propose: proposal function information arity mismatch\"\r\n        );\r\n        require(\r\n            targets.length != 0,\r\n            \"GovernorAlpha::propose: must provide actions\"\r\n        );\r\n        require(\r\n            targets.length <= proposalMaxOperations(),\r\n            \"GovernorAlpha::propose: too many actions\"\r\n        );\r\n\r\n        uint256 latestProposalId = latestProposalIds[msg.sender];\r\n        if (latestProposalId != 0) {\r\n            ProposalState proposersLatestProposalState =\r\n                state(latestProposalId);\r\n            require(\r\n                proposersLatestProposalState != ProposalState.Active,\r\n                \"GovernorAlpha::propose: one live proposal per proposer, found an already active proposal\"\r\n            );\r\n            require(\r\n                proposersLatestProposalState != ProposalState.Pending,\r\n                \"GovernorAlpha::propose: one live proposal per proposer, found an already pending proposal\"\r\n            );\r\n        }\r\n\r\n        uint256 startBlock = add256(block.number, votingDelay());\r\n        uint256 endBlock = add256(startBlock, votingPeriod());\r\n\r\n        proposalCount++;\r\n        Proposal memory newProposal =\r\n            Proposal({\r\n                id: proposalCount,\r\n                startBlock: safe32(\r\n                    startBlock,\r\n                    \"GovernorAlpha::propose: start block number overflow\"\r\n                ),\r\n                endBlock: safe32(\r\n                    endBlock,\r\n                    \"GovernorAlpha::propose: end block number overflow\"\r\n                ),\r\n                forVotes: 0,\r\n                againstVotes: 0,\r\n                quorum: mul96(\r\n                    quorumPercentageVotes,\r\n                    threshold,\r\n                    \"GovernorAlpha::propose: overflow on quorum computation\"\r\n                ), //proposalThreshold is 1% of total votes, we can save gas using this pre calculated value\r\n                majorityPercentage: mul96(\r\n                    majorityPercentageVotes,\r\n                    threshold,\r\n                    \"GovernorAlpha::propose: overflow on majorityPercentage computation\"\r\n                ),\r\n                eta: 0,\r\n                startTime: safe64(\r\n                    block.timestamp,\r\n                    \"GovernorAlpha::propose: startTime overflow\"\r\n                ), //required by the staking contract. not used by the governance contract itself.\r\n                canceled: false,\r\n                executed: false,\r\n                proposer: msg.sender,\r\n                targets: targets,\r\n                values: values,\r\n                signatures: signatures,\r\n                calldatas: calldatas\r\n            });\r\n\r\n        proposals[newProposal.id] = newProposal;\r\n        latestProposalIds[newProposal.proposer] = newProposal.id;\r\n\r\n        emit ProposalCreated(\r\n            newProposal.id,\r\n            msg.sender,\r\n            targets,\r\n            values,\r\n            signatures,\r\n            calldatas,\r\n            startBlock,\r\n            endBlock,\r\n            description\r\n        );\r\n        return newProposal.id;\r\n    }\r\n\r\n    function queue(uint256 proposalId) public {\r\n        require(\r\n            state(proposalId) == ProposalState.Succeeded,\r\n            \"GovernorAlpha::queue: proposal can only be queued if it is succeeded\"\r\n        );\r\n        Proposal storage proposal = proposals[proposalId];\r\n        uint256 eta = add256(block.timestamp, timelock.delay());\r\n\r\n        for (uint256 i = 0; i < proposal.targets.length; i++) {\r\n            _queueOrRevert(\r\n                proposal.targets[i],\r\n                proposal.values[i],\r\n                proposal.signatures[i],\r\n                proposal.calldatas[i],\r\n                eta\r\n            );\r\n        }\r\n        proposal.eta = safe64(eta, \"GovernorAlpha::queue: ETA overflow\");\r\n        emit ProposalQueued(proposalId, eta);\r\n    }\r\n\r\n    function _queueOrRevert(\r\n        address target,\r\n        uint256 value,\r\n        string memory signature,\r\n        bytes memory data,\r\n        uint256 eta\r\n    ) internal {\r\n        require(\r\n            !timelock.queuedTransactions(\r\n                keccak256(abi.encode(target, value, signature, data, eta))\r\n            ),\r\n            \"GovernorAlpha::_queueOrRevert: proposal action already queued at eta\"\r\n        );\r\n        timelock.queueTransaction(target, value, signature, data, eta);\r\n    }\r\n\r\n    function execute(uint256 proposalId) public payable {\r\n        require(\r\n            state(proposalId) == ProposalState.Queued,\r\n            \"GovernorAlpha::execute: proposal can only be executed if it is queued\"\r\n        );\r\n        Proposal storage proposal = proposals[proposalId];\r\n        proposal.executed = true;\r\n\r\n        for (uint256 i = 0; i < proposal.targets.length; i++) {\r\n            timelock.executeTransaction.value(proposal.values[i])(\r\n                proposal.targets[i],\r\n                proposal.values[i],\r\n                proposal.signatures[i],\r\n                proposal.calldatas[i],\r\n                proposal.eta\r\n            );\r\n        }\r\n        emit ProposalExecuted(proposalId);\r\n    }\r\n\r\n    function cancel(uint256 proposalId) public {\r\n        ProposalState state = state(proposalId);\r\n        require(\r\n            state != ProposalState.Executed,\r\n            \"GovernorAlpha::cancel: cannot cancel executed proposal\"\r\n        );\r\n\r\n        Proposal storage proposal = proposals[proposalId];\r\n        //cancel only if sent by the guardian\r\n        require(\r\n            msg.sender == guardian,\r\n            \"GovernorAlpha::cancel: sender isn't a guardian\"\r\n        );\r\n\r\n        proposal.canceled = true;\r\n\r\n        for (uint256 i = 0; i < proposal.targets.length; i++) {\r\n            timelock.cancelTransaction(\r\n                proposal.targets[i],\r\n                proposal.values[i],\r\n                proposal.signatures[i],\r\n                proposal.calldatas[i],\r\n                proposal.eta\r\n            );\r\n        }\r\n\r\n        emit ProposalCanceled(proposalId);\r\n    }\r\n\r\n    function getActions(uint256 proposalId)\r\n        public\r\n        view\r\n        returns (\r\n            address[] memory targets,\r\n            uint256[] memory values,\r\n            string[] memory signatures,\r\n            bytes[] memory calldatas\r\n        )\r\n    {\r\n        Proposal storage p = proposals[proposalId];\r\n        return (p.targets, p.values, p.signatures, p.calldatas);\r\n    }\r\n\r\n    function getReceipt(uint256 proposalId, address voter)\r\n        public\r\n        view\r\n        returns (Receipt memory)\r\n    {\r\n        return proposals[proposalId].receipts[voter];\r\n    }\r\n\r\n    function castVote(uint256 proposalId, bool support) public {\r\n        return _castVote(msg.sender, proposalId, support);\r\n    }\r\n\r\n    function castVoteBySig(\r\n        uint256 proposalId,\r\n        bool support,\r\n        uint8 v,\r\n        bytes32 r,\r\n        bytes32 s\r\n    ) public {\r\n        bytes32 domainSeparator =\r\n            keccak256(\r\n                abi.encode(\r\n                    DOMAIN_TYPEHASH,\r\n                    keccak256(bytes(NAME)),\r\n                    getChainId(),\r\n                    address(this)\r\n                )\r\n            );\r\n        bytes32 structHash =\r\n            keccak256(abi.encode(BALLOT_TYPEHASH, proposalId, support));\r\n        bytes32 digest =\r\n            keccak256(\r\n                abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash)\r\n            );\r\n        address signatory = ecrecover(digest, v, r, s);\r\n        require(\r\n            RSKAddrValidator.checkPKNotZero(signatory),\r\n            \"GovernorAlpha::castVoteBySig: invalid signature\"\r\n        );\r\n        return _castVote(signatory, proposalId, support);\r\n    }\r\n\r\n    function _castVote(\r\n        address voter,\r\n        uint256 proposalId,\r\n        bool support\r\n    ) internal {\r\n        require(\r\n            state(proposalId) == ProposalState.Active,\r\n            \"GovernorAlpha::_castVote: voting is closed\"\r\n        );\r\n        Proposal storage proposal = proposals[proposalId];\r\n        Receipt storage receipt = proposal.receipts[voter];\r\n        require(\r\n            receipt.hasVoted == false,\r\n            \"GovernorAlpha::_castVote: voter already voted\"\r\n        );\r\n        uint96 votes =\r\n            staking.getPriorVotes(\r\n                voter,\r\n                proposal.startBlock,\r\n                proposal.startTime\r\n            );\r\n\r\n        if (support) {\r\n            proposal.forVotes = add96(\r\n                proposal.forVotes,\r\n                votes,\r\n                \"GovernorAlpha::_castVote: vote overflow\"\r\n            );\r\n        } else {\r\n            proposal.againstVotes = add96(\r\n                proposal.againstVotes,\r\n                votes,\r\n                \"GovernorAlpha::_castVote: vote overflow\"\r\n            );\r\n        }\r\n\r\n        receipt.hasVoted = true;\r\n        receipt.support = support;\r\n        receipt.votes = votes;\r\n\r\n        emit VoteCast(voter, proposalId, support, votes);\r\n    }\r\n\r\n    function __acceptAdmin() public {\r\n        require(\r\n            msg.sender == guardian,\r\n            \"GovernorAlpha::__acceptAdmin: sender must be gov guardian\"\r\n        );\r\n        timelock.acceptAdmin();\r\n    }\r\n\r\n    function __abdicate() public {\r\n        require(\r\n            msg.sender == guardian,\r\n            \"GovernorAlpha::__abdicate: sender must be gov guardian\"\r\n        );\r\n        guardian = address(0);\r\n    }\r\n\r\n    function __queueSetTimelockPendingAdmin(\r\n        address newPendingAdmin,\r\n        uint256 eta\r\n    ) public {\r\n        require(\r\n            msg.sender == guardian,\r\n            \"GovernorAlpha::__queueSetTimelockPendingAdmin: sender must be gov guardian\"\r\n        );\r\n        timelock.queueTransaction(\r\n            address(timelock),\r\n            0,\r\n            \"setPendingAdmin(address)\",\r\n            abi.encode(newPendingAdmin),\r\n            eta\r\n        );\r\n    }\r\n\r\n    function __executeSetTimelockPendingAdmin(\r\n        address newPendingAdmin,\r\n        uint256 eta\r\n    ) public {\r\n        require(\r\n            msg.sender == guardian,\r\n            \"GovernorAlpha::__executeSetTimelockPendingAdmin: sender must be gov guardian\"\r\n        );\r\n        timelock.executeTransaction(\r\n            address(timelock),\r\n            0,\r\n            \"setPendingAdmin(address)\",\r\n            abi.encode(newPendingAdmin),\r\n            eta\r\n        );\r\n    }\r\n\r\n    function state(uint256 proposalId) public view returns (ProposalState) {\r\n        require(\r\n            proposalCount >= proposalId && proposalId > 0,\r\n            \"GovernorAlpha::state: invalid proposal id\"\r\n        );\r\n        Proposal storage proposal = proposals[proposalId];\r\n\r\n        if (proposal.canceled) {\r\n            return ProposalState.Canceled;\r\n        }\r\n\r\n        if (block.number <= proposal.startBlock) {\r\n            return ProposalState.Pending;\r\n        }\r\n\r\n        if (block.number <= proposal.endBlock) {\r\n            return ProposalState.Active;\r\n        }\r\n\r\n        uint96 totalVotes =\r\n            add96(\r\n                proposal.forVotes,\r\n                proposal.againstVotes,\r\n                \"GovernorAlpha:: state: forVotes + againstVotes > uint96\"\r\n            );\r\n        uint96 totalVotesMajorityPercentage =\r\n            div96(totalVotes, 100, \"GovernorAlpha:: state: division error\");\r\n        totalVotesMajorityPercentage = mul96(\r\n            totalVotesMajorityPercentage,\r\n            majorityPercentageVotes,\r\n            \"GovernorAlpha:: state: totalVotes * majorityPercentage > uint96\"\r\n        );\r\n        if (\r\n            proposal.forVotes <= totalVotesMajorityPercentage ||\r\n            totalVotes < proposal.quorum\r\n        ) {\r\n            return ProposalState.Defeated;\r\n        }\r\n\r\n        if (proposal.eta == 0) {\r\n            return ProposalState.Succeeded;\r\n        }\r\n\r\n        if (proposal.executed) {\r\n            return ProposalState.Executed;\r\n        }\r\n\r\n        if (block.timestamp >= add256(proposal.eta, timelock.GRACE_PERIOD())) {\r\n            return ProposalState.Expired;\r\n        }\r\n\r\n        return ProposalState.Queued;\r\n    }\r\n\r\n    function add256(uint256 a, uint256 b) internal pure returns (uint256) {\r\n        uint256 c = a + b;\r\n        require(c >= a, \"addition overflow\");\r\n        return c;\r\n    }\r\n\r\n    function sub256(uint256 a, uint256 b) internal pure returns (uint256) {\r\n        require(b <= a, \"subtraction underflow\");\r\n        return a - b;\r\n    }\r\n\r\n    function getChainId() internal pure returns (uint256) {\r\n        uint256 chainId;\r\n        assembly {\r\n            chainId := chainid()\r\n        }\r\n        return chainId;\r\n    }\r\n}\r\n","creation_status":"success","file_path":"GovernorAlpha.sol"}