Source Code
Overview
ETH Balance
0 ETH
Token Holdings
More Info
ContractCreator
Multichain Info
N/A
Latest 25 from a total of 76 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Post Process Dkg | 4154465 | 578 days ago | IN | 0 ETH | 0.0004197 | ||||
Commit Dkg | 4154445 | 578 days ago | IN | 0 ETH | 0.00123777 | ||||
Commit Dkg | 4154445 | 578 days ago | IN | 0 ETH | 0.00082695 | ||||
Commit Dkg | 4154445 | 578 days ago | IN | 0 ETH | 0.00121435 | ||||
Node Activate | 4154423 | 578 days ago | IN | 0 ETH | 0.00573289 | ||||
Node Activate | 4154421 | 578 days ago | IN | 0 ETH | 0.00070031 | ||||
Node Activate | 4154419 | 578 days ago | IN | 0 ETH | 0.00066398 | ||||
Node Activate | 4154417 | 578 days ago | IN | 0 ETH | 0.00079036 | ||||
Node Quit | 4154415 | 578 days ago | IN | 0 ETH | 0.0003725 | ||||
Node Activate | 4151957 | 578 days ago | IN | 0 ETH | 0.00078951 | ||||
Node Activate | 4151955 | 578 days ago | IN | 0 ETH | 0.00075336 | ||||
Node Quit | 4151954 | 578 days ago | IN | 0 ETH | 0.00032993 | ||||
Post Process Dkg | 4151952 | 578 days ago | IN | 0 ETH | 0.00055065 | ||||
Node Quit | 4151951 | 578 days ago | IN | 0 ETH | 0.00036371 | ||||
Post Process Dkg | 4151949 | 578 days ago | IN | 0 ETH | 0.00077717 | ||||
Node Quit | 4151914 | 579 days ago | IN | 0 ETH | 0.00062556 | ||||
Node Quit | 4151913 | 579 days ago | IN | 0 ETH | 0.00066944 | ||||
Node Quit | 4151912 | 579 days ago | IN | 0 ETH | 0.00072827 | ||||
Node Quit | 4151910 | 579 days ago | IN | 0 ETH | 0.00548168 | ||||
Node Quit | 4151909 | 579 days ago | IN | 0 ETH | 0.00590074 | ||||
Node Quit | 4151907 | 579 days ago | IN | 0 ETH | 0.00574016 | ||||
Post Process Dkg | 3633226 | 658 days ago | IN | 0 ETH | 0.00039428 | ||||
Post Process Dkg | 3633225 | 658 days ago | IN | 0 ETH | 0.00039502 | ||||
Post Process Dkg | 3633225 | 658 days ago | IN | 0 ETH | 0.00043305 | ||||
Post Process Dkg | 3633225 | 658 days ago | IN | 0 ETH | 0.00039353 |
Latest 23 internal transactions
Advanced mode:
Parent Transaction Hash | Method | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|---|
Transfer | 4154465 | 578 days ago | 0 ETH | ||||
0x60c06040 | 4154423 | 578 days ago | Contract Creation | 0 ETH | |||
Transfer | 4151952 | 578 days ago | 0 ETH | ||||
Transfer | 4151949 | 578 days ago | 0 ETH | ||||
0x60c06040 | 4151910 | 579 days ago | Contract Creation | 0 ETH | |||
0x60c06040 | 4151909 | 579 days ago | Contract Creation | 0 ETH | |||
0x60c06040 | 4151907 | 579 days ago | Contract Creation | 0 ETH | |||
Transfer | 3633225 | 658 days ago | 0 ETH | ||||
Transfer | 3633225 | 658 days ago | 0 ETH | ||||
0x60c06040 | 3633183 | 658 days ago | Contract Creation | 0 ETH | |||
0x60c06040 | 3633183 | 658 days ago | Contract Creation | 0 ETH | |||
0x60c06040 | 3633183 | 658 days ago | Contract Creation | 0 ETH | |||
0x60c06040 | 3633183 | 658 days ago | Contract Creation | 0 ETH | |||
Transfer | 3633079 | 658 days ago | 0 ETH | ||||
0x60c06040 | 3633037 | 658 days ago | Contract Creation | 0 ETH | |||
0x60c06040 | 3633036 | 658 days ago | Contract Creation | 0 ETH | |||
0x60c06040 | 3633036 | 658 days ago | Contract Creation | 0 ETH | |||
0x60c06040 | 3633035 | 658 days ago | Contract Creation | 0 ETH | |||
0x60c06040 | 3633035 | 658 days ago | Contract Creation | 0 ETH | |||
0x60c06040 | 3633035 | 658 days ago | Contract Creation | 0 ETH | |||
0x60c06040 | 3633035 | 658 days ago | Contract Creation | 0 ETH | |||
Transfer | 3632665 | 658 days ago | 0 ETH | ||||
0x60c06040 | 3632623 | 658 days ago | Contract Creation | 0 ETH |
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
Controller
Compiler Version
v0.8.18+commit.87f61d96
Optimization Enabled:
Yes with 500 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.18; import {IERC20, SafeERC20} from "openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol"; import {OwnableUpgradeable} from "openzeppelin-contracts-upgradeable/contracts/access/OwnableUpgradeable.sol"; import {Initializable} from "openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol"; import {IController} from "./interfaces/IController.sol"; import {IControllerOwner} from "./interfaces/IControllerOwner.sol"; import {IAdapter} from "./interfaces/IAdapter.sol"; import {ICoordinator} from "./interfaces/ICoordinator.sol"; import {INodeStaking} from "Staking-v0.1/interfaces/INodeStaking.sol"; import {BLS} from "./libraries/BLS.sol"; import {GroupLib} from "./libraries/GroupLib.sol"; import {Coordinator} from "./Coordinator.sol"; contract Controller is Initializable, IController, IControllerOwner, OwnableUpgradeable { using SafeERC20 for IERC20; using GroupLib for GroupLib.GroupData; // *Constants* uint16 private constant _BALANCE_BASE = 1; // *Controller Config* ControllerConfig private _config; IERC20 private _arpa; // *Node State Variables* mapping(address => Node) private _nodes; // maps node address to Node Struct mapping(address => uint256) private _withdrawableEths; // maps node address to withdrawable eth amount mapping(address => uint256) private _arpaRewards; // maps node address to arpa rewards // *DKG Variables* mapping(uint256 => address) private _coordinators; // maps group index to coordinator address // *Group Variables* GroupLib.GroupData internal _groupData; // *Task Variables* uint256 private _lastOutput; // *Structs* struct ControllerConfig { address stakingContractAddress; address adapterContractAddress; uint256 nodeStakingAmount; uint256 disqualifiedNodePenaltyAmount; uint256 defaultDkgPhaseDuration; uint256 pendingBlockAfterQuit; uint256 dkgPostProcessReward; } // *Events* event NodeRegistered(address indexed nodeAddress, bytes dkgPublicKey, uint256 groupIndex); event NodeActivated(address indexed nodeAddress, uint256 groupIndex); event NodeQuit(address indexed nodeAddress); event DkgPublicKeyChanged(address indexed nodeAddress, bytes dkgPublicKey); event NodeSlashed(address indexed nodeIdAddress, uint256 stakingRewardPenalty, uint256 pendingBlock); event NodeRewarded(address indexed nodeAddress, uint256 ethAmount, uint256 arpaAmount); event ControllerConfigSet( address stakingContractAddress, address adapterContractAddress, uint256 nodeStakingAmount, uint256 disqualifiedNodePenaltyAmount, uint256 defaultNumberOfCommitters, uint256 defaultDkgPhaseDuration, uint256 groupMaxCapacity, uint256 idealNumberOfGroups, uint256 pendingBlockAfterQuit, uint256 dkgPostProcessReward ); event DkgTask( uint256 indexed globalEpoch, uint256 indexed groupIndex, uint256 indexed groupEpoch, uint256 size, uint256 threshold, address[] members, uint256 assignmentBlockHeight, address coordinatorAddress ); // *Errors* error NodeNotRegistered(); error NodeAlreadyRegistered(); error NodeAlreadyActive(); error NodeStillPending(uint256 pendingUntilBlock); error GroupNotExist(uint256 groupIndex); error CoordinatorNotFound(uint256 groupIndex); error DkgNotInProgress(uint256 groupIndex); error DkgStillInProgress(uint256 groupIndex, int8 phase); error EpochMismatch(uint256 groupIndex, uint256 inputGroupEpoch, uint256 currentGroupEpoch); error NodeNotInGroup(uint256 groupIndex, address nodeIdAddress); error PartialKeyAlreadyRegistered(uint256 groupIndex, address nodeIdAddress); error SenderNotAdapter(); error InvalidZeroAddress(); function initialize(address arpa, uint256 lastOutput) public initializer { _arpa = IERC20(arpa); _lastOutput = lastOutput; __Ownable_init(); } // ============= // IControllerOwner // ============= function setControllerConfig( address stakingContractAddress, address adapterContractAddress, uint256 nodeStakingAmount, uint256 disqualifiedNodePenaltyAmount, uint256 defaultNumberOfCommitters, uint256 defaultDkgPhaseDuration, uint256 groupMaxCapacity, uint256 idealNumberOfGroups, uint256 pendingBlockAfterQuit, uint256 dkgPostProcessReward ) external override(IControllerOwner) onlyOwner { _config = ControllerConfig({ stakingContractAddress: stakingContractAddress, adapterContractAddress: adapterContractAddress, nodeStakingAmount: nodeStakingAmount, disqualifiedNodePenaltyAmount: disqualifiedNodePenaltyAmount, defaultDkgPhaseDuration: defaultDkgPhaseDuration, pendingBlockAfterQuit: pendingBlockAfterQuit, dkgPostProcessReward: dkgPostProcessReward }); _groupData.setConfig(idealNumberOfGroups, groupMaxCapacity, defaultNumberOfCommitters); emit ControllerConfigSet( stakingContractAddress, adapterContractAddress, nodeStakingAmount, disqualifiedNodePenaltyAmount, defaultNumberOfCommitters, defaultDkgPhaseDuration, groupMaxCapacity, idealNumberOfGroups, pendingBlockAfterQuit, dkgPostProcessReward ); } // ============= // IController // ============= function nodeRegister(bytes calldata dkgPublicKey) external override(IController) { if (_nodes[msg.sender].idAddress != address(0)) { revert NodeAlreadyRegistered(); } uint256[4] memory publicKey = BLS.fromBytesPublicKey(dkgPublicKey); if (!BLS.isValidPublicKey(publicKey)) { revert BLS.InvalidPublicKey(); } // Lock staking amount in Staking contract INodeStaking(_config.stakingContractAddress).lock(msg.sender, _config.nodeStakingAmount); // Populate Node struct and insert into nodes Node storage n = _nodes[msg.sender]; n.idAddress = msg.sender; n.dkgPublicKey = dkgPublicKey; n.state = true; // Initialize withdrawable eths and arpa rewards to save gas for adapter call _withdrawableEths[msg.sender] = _BALANCE_BASE; _arpaRewards[msg.sender] = _BALANCE_BASE; (uint256 groupIndex, uint256[] memory groupIndicesToEmitEvent) = _groupData.nodeJoin(msg.sender, _lastOutput); for (uint256 i = 0; i < groupIndicesToEmitEvent.length; i++) { _emitGroupEvent(groupIndicesToEmitEvent[i]); } emit NodeRegistered(msg.sender, dkgPublicKey, groupIndex); } function nodeActivate() external override(IController) { Node storage node = _nodes[msg.sender]; if (node.idAddress != msg.sender) { revert NodeNotRegistered(); } if (node.state) { revert NodeAlreadyActive(); } if (node.pendingUntilBlock > block.number) { revert NodeStillPending(node.pendingUntilBlock); } // lock up to staking amount in Staking contract uint256 lockedAmount = INodeStaking(_config.stakingContractAddress).getLockedAmount(msg.sender); if (lockedAmount < _config.nodeStakingAmount) { INodeStaking(_config.stakingContractAddress).lock(msg.sender, _config.nodeStakingAmount - lockedAmount); } node.state = true; (uint256 groupIndex, uint256[] memory groupIndicesToEmitEvent) = _groupData.nodeJoin(msg.sender, _lastOutput); for (uint256 i = 0; i < groupIndicesToEmitEvent.length; i++) { _emitGroupEvent(groupIndicesToEmitEvent[i]); } emit NodeActivated(msg.sender, groupIndex); } function nodeQuit() external override(IController) { Node storage node = _nodes[msg.sender]; if (node.idAddress != msg.sender) { revert NodeNotRegistered(); } uint256[] memory groupIndicesToEmitEvent = _groupData.nodeLeave(msg.sender, _lastOutput); for (uint256 i = 0; i < groupIndicesToEmitEvent.length; i++) { _emitGroupEvent(groupIndicesToEmitEvent[i]); } _freezeNode(msg.sender, _config.pendingBlockAfterQuit); // unlock staking amount in Staking contract INodeStaking(_config.stakingContractAddress).unlock(msg.sender, _config.nodeStakingAmount); emit NodeQuit(msg.sender); } function changeDkgPublicKey(bytes calldata dkgPublicKey) external override(IController) { Node storage node = _nodes[msg.sender]; if (node.idAddress != msg.sender) { revert NodeNotRegistered(); } if (node.state) { revert NodeAlreadyActive(); } uint256[4] memory publicKey = BLS.fromBytesPublicKey(dkgPublicKey); if (!BLS.isValidPublicKey(publicKey)) { revert BLS.InvalidPublicKey(); } node.dkgPublicKey = dkgPublicKey; emit DkgPublicKeyChanged(msg.sender, dkgPublicKey); } function commitDkg(CommitDkgParams memory params) external override(IController) { if (params.groupIndex >= _groupData.groupCount) revert GroupNotExist(params.groupIndex); // require coordinator exists if (_coordinators[params.groupIndex] == address(0)) { revert CoordinatorNotFound(params.groupIndex); } // Ensure DKG Proccess is in Phase ICoordinator coordinator = ICoordinator(_coordinators[params.groupIndex]); if (coordinator.inPhase() == -1) { revert DkgNotInProgress(params.groupIndex); } // Ensure epoch is correct, node is in group, and has not already submitted a partial key Group storage g = _groupData.groups[params.groupIndex]; if (params.groupEpoch != g.epoch) { revert EpochMismatch(params.groupIndex, params.groupEpoch, g.epoch); } if (_groupData.getMemberIndexByAddress(params.groupIndex, msg.sender) == -1) { revert NodeNotInGroup(params.groupIndex, msg.sender); } // check to see if member has called commitdkg in the past. if (isPartialKeyRegistered(params.groupIndex, msg.sender)) { revert PartialKeyAlreadyRegistered(params.groupIndex, msg.sender); } // require publickey and partial public key are not empty / are the right format uint256[4] memory partialPublicKey = BLS.fromBytesPublicKey(params.partialPublicKey); if (!BLS.isValidPublicKey(partialPublicKey)) { revert BLS.InvalidPartialPublicKey(); } uint256[4] memory publicKey = BLS.fromBytesPublicKey(params.publicKey); if (!BLS.isValidPublicKey(publicKey)) { revert BLS.InvalidPublicKey(); } // Populate CommitResult / CommitCache CommitResult memory commitResult = CommitResult({ groupEpoch: params.groupEpoch, publicKey: publicKey, disqualifiedNodes: params.disqualifiedNodes }); if (!_groupData.tryAddToExistingCommitCache(params.groupIndex, commitResult)) { CommitCache memory commitCache = CommitCache({commitResult: commitResult, nodeIdAddress: new address[](1)}); commitCache.nodeIdAddress[0] = msg.sender; g.commitCacheList.push(commitCache); } // no matter consensus previously reached, update the partial public key of the given node's member entry in the group g.members[uint256(_groupData.getMemberIndexByAddress(params.groupIndex, msg.sender))].partialPublicKey = partialPublicKey; // if not.. call get StrictlyMajorityIdenticalCommitmentResult for the group and check if consensus has been reached. if (!g.isStrictlyMajorityConsensusReached) { (bool success, address[] memory disqualifiedNodes) = _groupData.tryEnableGroup(params.groupIndex, _lastOutput); if (success) { // Iterate over disqualified nodes and call slashNode on each. for (uint256 i = 0; i < disqualifiedNodes.length; i++) { _slashNode(disqualifiedNodes[i], _config.disqualifiedNodePenaltyAmount, 0); } } } } function postProcessDkg(uint256 groupIndex, uint256 groupEpoch) external override(IController) { if (groupIndex >= _groupData.groupCount) revert GroupNotExist(groupIndex); // require calling node is in group if (_groupData.getMemberIndexByAddress(groupIndex, msg.sender) == -1) { revert NodeNotInGroup(groupIndex, msg.sender); } // require correct epoch Group storage g = _groupData.groups[groupIndex]; if (groupEpoch != g.epoch) { revert EpochMismatch(groupIndex, groupEpoch, g.epoch); } // require coordinator exists if (_coordinators[groupIndex] == address(0)) { revert CoordinatorNotFound(groupIndex); } // Ensure DKG Proccess is out of phase ICoordinator coordinator = ICoordinator(_coordinators[groupIndex]); if (coordinator.inPhase() != -1) { revert DkgStillInProgress(groupIndex, coordinator.inPhase()); } // delete coordinator coordinator.selfDestruct(); // coordinator self destructs _coordinators[groupIndex] = address(0); // remove coordinator from mapping if (!g.isStrictlyMajorityConsensusReached) { (address[] memory nodesToBeSlashed, uint256[] memory groupIndicesToEmitEvent) = _groupData.handleUnsuccessfulGroupDkg(groupIndex, _lastOutput); for (uint256 i = 0; i < nodesToBeSlashed.length; i++) { _slashNode(nodesToBeSlashed[i], _config.disqualifiedNodePenaltyAmount, 0); } for (uint256 i = 0; i < groupIndicesToEmitEvent.length; i++) { _emitGroupEvent(groupIndicesToEmitEvent[i]); } } // update rewards for calling node _arpaRewards[msg.sender] += _config.dkgPostProcessReward; emit NodeRewarded(msg.sender, 0, _config.dkgPostProcessReward); } function nodeWithdraw(address recipient) external override(IController) { if (recipient == address(0)) { revert InvalidZeroAddress(); } uint256 ethAmount = _withdrawableEths[msg.sender]; uint256 arpaAmount = _arpaRewards[msg.sender]; if (arpaAmount > _BALANCE_BASE) { _arpaRewards[msg.sender] = _BALANCE_BASE; _arpa.safeTransfer(recipient, arpaAmount - _BALANCE_BASE); } if (ethAmount > _BALANCE_BASE) { _withdrawableEths[msg.sender] = _BALANCE_BASE; IAdapter(_config.adapterContractAddress).nodeWithdrawETH(recipient, ethAmount - _BALANCE_BASE); } } function addReward(address[] memory nodes, uint256 ethAmount, uint256 arpaAmount) public override(IController) { if (msg.sender != _config.adapterContractAddress) { revert SenderNotAdapter(); } for (uint256 i = 0; i < nodes.length; i++) { _withdrawableEths[nodes[i]] += ethAmount; _arpaRewards[nodes[i]] += arpaAmount; emit NodeRewarded(nodes[i], ethAmount, arpaAmount); } } function setLastOutput(uint256 lastOutput) external override(IController) { if (msg.sender != _config.adapterContractAddress) { revert SenderNotAdapter(); } _lastOutput = lastOutput; } function getControllerConfig() external view returns ( address stakingContractAddress, address adapterContractAddress, uint256 nodeStakingAmount, uint256 disqualifiedNodePenaltyAmount, uint256 defaultNumberOfCommitters, uint256 defaultDkgPhaseDuration, uint256 groupMaxCapacity, uint256 idealNumberOfGroups, uint256 pendingBlockAfterQuit, uint256 dkgPostProcessReward ) { return ( _config.stakingContractAddress, _config.adapterContractAddress, _config.nodeStakingAmount, _config.disqualifiedNodePenaltyAmount, _groupData.defaultNumberOfCommitters, _config.defaultDkgPhaseDuration, _groupData.groupMaxCapacity, _groupData.idealNumberOfGroups, _config.pendingBlockAfterQuit, _config.dkgPostProcessReward ); } function getValidGroupIndices() public view override(IController) returns (uint256[] memory) { return _groupData.getValidGroupIndices(); } function getGroupEpoch() external view returns (uint256) { return _groupData.epoch; } function getGroupCount() external view override(IController) returns (uint256) { return _groupData.groupCount; } function getGroup(uint256 groupIndex) public view override(IController) returns (Group memory) { return _groupData.groups[groupIndex]; } function getGroupThreshold(uint256 groupIndex) public view override(IController) returns (uint256, uint256) { return (_groupData.groups[groupIndex].threshold, _groupData.groups[groupIndex].size); } function getNode(address nodeAddress) public view override(IController) returns (Node memory) { return _nodes[nodeAddress]; } function getMember(uint256 groupIndex, uint256 memberIndex) public view override(IController) returns (Member memory) { return _groupData.groups[groupIndex].members[memberIndex]; } function getBelongingGroup(address nodeAddress) external view override(IController) returns (int256, int256) { return _groupData.getBelongingGroupByMemberAddress(nodeAddress); } function getCoordinator(uint256 groupIndex) public view override(IController) returns (address) { return _coordinators[groupIndex]; } function getNodeWithdrawableTokens(address nodeAddress) public view override(IController) returns (uint256, uint256) { return ( _withdrawableEths[nodeAddress] == 0 ? 0 : (_withdrawableEths[nodeAddress] - _BALANCE_BASE), _arpaRewards[nodeAddress] == 0 ? 0 : (_arpaRewards[nodeAddress] - _BALANCE_BASE) ); } function getLastOutput() external view returns (uint256) { return _lastOutput; } /// Check to see if a group has a partial public key registered for a given node. function isPartialKeyRegistered(uint256 groupIndex, address nodeIdAddress) public view override(IController) returns (bool) { Group memory g = _groupData.groups[groupIndex]; for (uint256 i = 0; i < g.members.length; i++) { if (g.members[i].nodeIdAddress == nodeIdAddress) { return g.members[i].partialPublicKey[0] != 0; } } return false; } // ============= // Internal // ============= function _emitGroupEvent(uint256 groupIndex) internal { _groupData.prepareGroupEvent(groupIndex); Group memory g = _groupData.groups[groupIndex]; // Deploy coordinator, add to coordinators mapping Coordinator coordinator; coordinator = new Coordinator(g.threshold, _config.defaultDkgPhaseDuration); _coordinators[groupIndex] = address(coordinator); // Initialize Coordinator address[] memory groupNodes = new address[](g.size); bytes[] memory groupKeys = new bytes[](g.size); for (uint256 i = 0; i < g.size; i++) { groupNodes[i] = g.members[i].nodeIdAddress; groupKeys[i] = _nodes[g.members[i].nodeIdAddress].dkgPublicKey; } coordinator.initialize(groupNodes, groupKeys); emit DkgTask( _groupData.epoch, g.index, g.epoch, g.size, g.threshold, groupNodes, block.number, address(coordinator) ); } // Give node staking reward penalty and freezeNode function _slashNode(address nodeIdAddress, uint256 stakingRewardPenalty, uint256 pendingBlock) internal { // slash staking reward in Staking contract INodeStaking(_config.stakingContractAddress).slashDelegationReward(nodeIdAddress, stakingRewardPenalty); // remove node from group if handleGroup is true and deactivate it _freezeNode(nodeIdAddress, pendingBlock); emit NodeSlashed(nodeIdAddress, stakingRewardPenalty, pendingBlock); } function _freezeNode(address nodeIdAddress, uint256 pendingBlock) internal { // set node state to false for frozen node _nodes[nodeIdAddress].state = false; uint256 currentBlock = block.number; // if the node is already pending, add the pending block to the current pending block if (_nodes[nodeIdAddress].pendingUntilBlock > currentBlock) { _nodes[nodeIdAddress].pendingUntilBlock += pendingBlock; // else set the pending block to the current block + pending block } else { _nodes[nodeIdAddress].pendingUntilBlock = currentBlock + pendingBlock; } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; import "../extensions/draft-IERC20Permit.sol"; import "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; function safeTransfer( IERC20 token, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom( IERC20 token, address from, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove( IERC20 token, address spender, uint256 value ) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance( IERC20 token, address spender, uint256 value ) internal { uint256 newAllowance = token.allowance(address(this), spender) + value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance( IERC20 token, address spender, uint256 value ) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); uint256 newAllowance = oldAllowance - value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } } function safePermit( IERC20Permit token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit(owner, spender, value, deadline, v, r, s); uint256 nonceAfter = token.nonces(owner); require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/ContextUpgradeable.sol"; import "../proxy/utils/Initializable.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ function __Ownable_init() internal onlyInitializing { __Ownable_init_unchained(); } function __Ownable_init_unchained() internal onlyInitializing { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.1) (proxy/utils/Initializable.sol) pragma solidity ^0.8.2; import "../../utils/AddressUpgradeable.sol"; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ``` * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. * @custom:oz-retyped-from bool */ uint8 private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint8 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. * * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a * constructor. * * Emits an {Initialized} event. */ modifier initializer() { bool isTopLevelCall = !_initializing; require( (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1), "Initializable: contract is already initialized" ); _initialized = 1; if (isTopLevelCall) { _initializing = true; } _; if (isTopLevelCall) { _initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * A reinitializer may be used after the original initialization step. This is essential to configure modules that * are added through upgrades and that require initialization. * * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` * cannot be nested. If one is invoked in the context of another, execution will revert. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. * * WARNING: setting the version to 255 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint8 version) { require(!_initializing && _initialized < version, "Initializable: contract is already initialized"); _initialized = version; _initializing = true; _; _initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { require(_initializing, "Initializable: contract is not initializing"); _; } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { require(!_initializing, "Initializable: contract is initializing"); if (_initialized < type(uint8).max) { _initialized = type(uint8).max; emit Initialized(type(uint8).max); } } /** * @dev Returns the highest version that has been initialized. See {reinitializer}. */ function _getInitializedVersion() internal view returns (uint8) { return _initialized; } /** * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. */ function _isInitializing() internal view returns (bool) { return _initializing; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.18; interface IController { struct Group { uint256 index; uint256 epoch; uint256 size; uint256 threshold; Member[] members; address[] committers; CommitCache[] commitCacheList; bool isStrictlyMajorityConsensusReached; uint256[4] publicKey; } struct Member { address nodeIdAddress; uint256[4] partialPublicKey; } struct CommitResult { uint256 groupEpoch; uint256[4] publicKey; address[] disqualifiedNodes; } struct CommitCache { address[] nodeIdAddress; CommitResult commitResult; } struct Node { address idAddress; bytes dkgPublicKey; bool state; uint256 pendingUntilBlock; } struct CommitDkgParams { uint256 groupIndex; uint256 groupEpoch; bytes publicKey; bytes partialPublicKey; address[] disqualifiedNodes; } // node transaction function nodeRegister(bytes calldata dkgPublicKey) external; function nodeActivate() external; function nodeQuit() external; function changeDkgPublicKey(bytes calldata dkgPublicKey) external; function commitDkg(CommitDkgParams memory params) external; function postProcessDkg(uint256 groupIndex, uint256 groupEpoch) external; function nodeWithdraw(address recipient) external; // adapter transaction function addReward(address[] memory nodes, uint256 ethAmount, uint256 arpaAmount) external; function setLastOutput(uint256 lastOutput) external; // view function getControllerConfig() external view returns ( address stakingContractAddress, address adapterContractAddress, uint256 nodeStakingAmount, uint256 disqualifiedNodePenaltyAmount, uint256 defaultNumberOfCommitters, uint256 defaultDkgPhaseDuration, uint256 groupMaxCapacity, uint256 idealNumberOfGroups, uint256 pendingBlockAfterQuit, uint256 dkgPostProcessReward ); /// @notice Get list of all group indexes where group.isStrictlyMajorityConsensusReached == true /// @return uint256[] List of valid group indexes function getValidGroupIndices() external view returns (uint256[] memory); function getGroupEpoch() external view returns (uint256); function getGroupCount() external view returns (uint256); function getGroup(uint256 index) external view returns (Group memory); function getGroupThreshold(uint256 groupIndex) external view returns (uint256, uint256); function getNode(address nodeAddress) external view returns (Node memory); function getMember(uint256 groupIndex, uint256 memberIndex) external view returns (Member memory); /// @notice Get the group index and member index of a given node. function getBelongingGroup(address nodeAddress) external view returns (int256, int256); function getCoordinator(uint256 groupIndex) external view returns (address); function getNodeWithdrawableTokens(address nodeAddress) external view returns (uint256, uint256); function getLastOutput() external view returns (uint256); /// @notice Check to see if a group has a partial public key registered for a given node. /// @return bool True if the node has a partial public key registered for the group. function isPartialKeyRegistered(uint256 groupIndex, address nodeIdAddress) external view returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.18; interface IControllerOwner { /** * @notice Sets the configuration of the controller * @param stakingContract The address of the staking contract * @param adapterContract The address of the adapter contract * @param nodeStakingAmount The amount of ARPA must staked by a node * @param disqualifiedNodePenaltyAmount The amount of ARPA will be slashed from a node if it is disqualified * @param defaultNumberOfCommitters The default number of committers for a DKG * @param defaultDkgPhaseDuration The default duration(block number) of a DKG phase * @param groupMaxCapacity The maximum number of nodes in a group * @param idealNumberOfGroups The ideal number of groups * @param pendingBlockAfterQuit The number of blocks a node must wait before joining a group after quitting * @param dkgPostProcessReward The amount of ARPA will be rewarded to the node after dkgPostProcess is completed */ function setControllerConfig( address stakingContract, address adapterContract, uint256 nodeStakingAmount, uint256 disqualifiedNodePenaltyAmount, uint256 defaultNumberOfCommitters, uint256 defaultDkgPhaseDuration, uint256 groupMaxCapacity, uint256 idealNumberOfGroups, uint256 pendingBlockAfterQuit, uint256 dkgPostProcessReward ) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.18; import {IRequestTypeBase} from "./IRequestTypeBase.sol"; interface IAdapter is IRequestTypeBase { struct PartialSignature { uint256 index; uint256 partialSignature; } struct RandomnessRequestParams { RequestType requestType; bytes params; uint64 subId; uint256 seed; uint16 requestConfirmations; uint32 callbackGasLimit; uint256 callbackMaxGasPrice; } struct RequestDetail { uint64 subId; uint32 groupIndex; RequestType requestType; bytes params; address callbackContract; uint256 seed; uint16 requestConfirmations; uint32 callbackGasLimit; uint256 callbackMaxGasPrice; uint256 blockNum; } // controller transaction function nodeWithdrawETH(address recipient, uint256 ethAmount) external; // consumer contract transaction function requestRandomness(RandomnessRequestParams calldata params) external returns (bytes32); function fulfillRandomness( uint32 groupIndex, bytes32 requestId, uint256 signature, RequestDetail calldata requestDetail, PartialSignature[] calldata partialSignatures ) external; // user transaction function createSubscription() external returns (uint64); function addConsumer(uint64 subId, address consumer) external; function fundSubscription(uint64 subId) external payable; function setReferral(uint64 subId, uint64 referralSubId) external; function cancelSubscription(uint64 subId, address to) external; function removeConsumer(uint64 subId, address consumer) external; // view function getLastSubscription(address consumer) external view returns (uint64); function getSubscription(uint64 subId) external view returns ( address owner, address[] memory consumers, uint256 balance, uint256 inflightCost, uint64 reqCount, uint64 freeRequestCount, uint64 referralSubId, uint64 reqCountInCurrentPeriod, uint256 lastRequestTimestamp ); function getPendingRequestCommitment(bytes32 requestId) external view returns (bytes32); function getLastAssignedGroupIndex() external view returns (uint256); function getLastRandomness() external view returns (uint256); function getRandomnessCount() external view returns (uint256); function getCurrentSubId() external view returns (uint64); function getCumulativeData() external view returns (uint256, uint256, uint256); function getController() external view returns (address); function getAdapterConfig() external view returns ( uint16 minimumRequestConfirmations, uint32 maxGasLimit, uint32 gasAfterPaymentCalculation, uint32 gasExceptCallback, uint256 signatureTaskExclusiveWindow, uint256 rewardPerSignature, uint256 committerRewardPerSignature ); function getFlatFeeConfig() external view returns ( uint32 fulfillmentFlatFeeLinkPPMTier1, uint32 fulfillmentFlatFeeLinkPPMTier2, uint32 fulfillmentFlatFeeLinkPPMTier3, uint32 fulfillmentFlatFeeLinkPPMTier4, uint32 fulfillmentFlatFeeLinkPPMTier5, uint24 reqsForTier2, uint24 reqsForTier3, uint24 reqsForTier4, uint24 reqsForTier5, uint16 flatFeePromotionGlobalPercentage, bool isFlatFeePromotionEnabledPermanently, uint256 flatFeePromotionStartTimestamp, uint256 flatFeePromotionEndTimestamp ); function getReferralConfig() external view returns (bool isReferralEnabled, uint16 freeRequestCountForReferrer, uint16 freeRequestCountForReferee); /* * @notice Compute fee based on the request count * @param reqCount number of requests * @return feePPM fee in ARPA PPM */ function getFeeTier(uint64 reqCount) external view returns (uint32); // Estimate the amount of gas used for fulfillment function estimatePaymentAmountInETH( uint32 callbackGasLimit, uint32 gasExceptCallback, uint32 fulfillmentFlatFeeEthPPM, uint256 weiPerUnitGas ) external view returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.18; interface ICoordinator { function inPhase() external view returns (int8); function initialize(address[] memory nodes, bytes[] memory publicKeys) external; function startBlock() external view returns (uint256); function selfDestruct() external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.18; interface INodeStaking { /// @notice This event is emitted when a node locks stake in the pool. /// @param staker Staker address /// @param newLock New principal amount locked event Locked(address staker, uint256 newLock); /// @notice This event is emitted when a node unlocks stake in the pool. /// @param staker Staker address /// @param newUnlock New principal amount unlocked event Unlocked(address staker, uint256 newUnlock); /// @notice This event is emitted when a node gets delegation reward slashed. /// @param staker Staker address /// @param amount Amount slashed event DelegationRewardSlashed(address staker, uint256 amount); /// @notice This error is raised when attempting to unlock with more than the current locked staking amount /// @param currentLockedStakingAmount Current locked staking amount error InadequateOperatorLockedStakingAmount(uint256 currentLockedStakingAmount); /// @notice This function allows controller to lock staking amount for a node. /// @param staker Node address /// @param amount Amount to lock function lock(address staker, uint256 amount) external; /// @notice This function allows controller to unlock staking amount for a node. /// @param staker Node address /// @param amount Amount to unlock function unlock(address staker, uint256 amount) external; /// @notice This function allows controller to slash delegation reward of a node. /// @param staker Node address /// @param amount Amount to slash function slashDelegationReward(address staker, uint256 amount) external; /// @notice This function returns the locked amount of a node. /// @param staker Node address function getLockedAmount(address staker) external view returns (uint256); }
// SPDX-License-Identifier: LGPL 3.0 pragma solidity ^0.8.18; import {BN256G2} from "./BN256G2.sol"; /** * @title BLS operations on bn254 curve * @author ARPA-Network adapted from https://github.com/ChihChengLiang/bls_solidity_python * @dev Homepage: https://github.com/ARPA-Network/BLS-TSS-Network * Signature and Point hashed to G1 are represented by affine coordinate in big-endian order, deserialized from compressed format. * Public key is represented and serialized by affine coordinate Q-x-re(x0), Q-x-im(x1), Q-y-re(y0), Q-y-im(y1) in big-endian order. */ library BLS { // Field order uint256 public constant N = 21888242871839275222246405745257275088696311157297823662689037894645226208583; // Negated genarator of G2 uint256 public constant N_G2_X1 = 11559732032986387107991004021392285783925812861821192530917403151452391805634; uint256 public constant N_G2_X0 = 10857046999023057135944570762232829481370756359578518086990519993285655852781; uint256 public constant N_G2_Y1 = 17805874995975841540914202342111839520379459829704422454583296818431106115052; uint256 public constant N_G2_Y0 = 13392588948715843804641432497768002650278120570034223513918757245338268106653; uint256 public constant FIELD_MASK = 0x3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff; error MustNotBeInfinity(); error InvalidPublicKeyEncoding(); error InvalidSignatureFormat(); error InvalidSignature(); error InvalidPartialSignatureFormat(); error InvalidPartialSignatures(); error EmptyPartialSignatures(); error InvalidPublicKey(); error InvalidPartialPublicKey(); function verifySingle(uint256[2] memory signature, uint256[4] memory pubkey, uint256[2] memory message) public view returns (bool) { uint256[12] memory input = [ signature[0], signature[1], N_G2_X1, N_G2_X0, N_G2_Y1, N_G2_Y0, message[0], message[1], pubkey[1], pubkey[0], pubkey[3], pubkey[2] ]; uint256[1] memory out; bool success; // solhint-disable-next-line no-inline-assembly assembly { success := staticcall(sub(gas(), 2000), 8, input, 384, out, 0x20) switch success case 0 { invalid() } } require(success, ""); return out[0] != 0; } function verifyPartials(uint256[2][] memory partials, uint256[4][] memory pubkeys, uint256[2] memory message) public view returns (bool) { uint256[2] memory aggregatedSignature; uint256[4] memory aggregatedPublicKey; for (uint256 i = 0; i < partials.length; i++) { aggregatedSignature = addPoints(aggregatedSignature, partials[i]); aggregatedPublicKey = BN256G2.ecTwistAdd(aggregatedPublicKey, pubkeys[i]); } uint256[12] memory input = [ aggregatedSignature[0], aggregatedSignature[1], N_G2_X1, N_G2_X0, N_G2_Y1, N_G2_Y0, message[0], message[1], aggregatedPublicKey[1], aggregatedPublicKey[0], aggregatedPublicKey[3], aggregatedPublicKey[2] ]; uint256[1] memory out; bool success; // solhint-disable-next-line no-inline-assembly assembly { success := staticcall(sub(gas(), 2000), 8, input, 384, out, 0x20) switch success case 0 { invalid() } } require(success, ""); return out[0] != 0; } // TODO a simple hash and increment implementation, can be improved later function hashToPoint(bytes memory data) public view returns (uint256[2] memory p) { bool found; bytes32 candidateHash = keccak256(data); while (true) { (p, found) = mapToPoint(candidateHash); if (found) { break; } candidateHash = keccak256(bytes.concat(candidateHash)); } } // we take the y-coordinate as the lexicographically largest of the two associated with the encoded x-coordinate function mapToPoint(bytes32 _x) internal view returns (uint256[2] memory p, bool found) { uint256 y; uint256 x = uint256(_x) % N; (y, found) = deriveYOnG1(x); if (found) { p[0] = x; p[1] = y > N / 2 ? N - y : y; } } function deriveYOnG1(uint256 x) internal view returns (uint256, bool) { uint256 y; y = mulmod(x, x, N); y = mulmod(y, x, N); y = addmod(y, 3, N); return sqrt(y); } function isValidPublicKey(uint256[4] memory publicKey) public pure returns (bool) { if ((publicKey[0] >= N) || (publicKey[1] >= N) || (publicKey[2] >= N || (publicKey[3] >= N))) { return false; } else { return isOnCurveG2(publicKey); } } function fromBytesPublicKey(bytes memory point) public pure returns (uint256[4] memory pubkey) { if (point.length != 128) { revert InvalidPublicKeyEncoding(); } uint256 x0; uint256 x1; uint256 y0; uint256 y1; // solhint-disable-next-line no-inline-assembly assembly { // look the first 32 bytes of a bytes struct is its length x0 := mload(add(point, 32)) x1 := mload(add(point, 64)) y0 := mload(add(point, 96)) y1 := mload(add(point, 128)) } pubkey = [x0, x1, y0, y1]; } function decompress(uint256 compressedSignature) public view returns (uint256[2] memory uncompressed) { uint256 x = compressedSignature & FIELD_MASK; // The most significant bit, when set, indicates that the y-coordinate of the point // is the lexicographically largest of the two associated values. // The second-most significant bit indicates that the point is at infinity. If this bit is set, // the remaining bits of the group element's encoding should be set to zero. // We don't accept infinity as valid signature. uint256 decision = compressedSignature >> 254; if (decision & 1 == 1) { revert MustNotBeInfinity(); } uint256 y; (y,) = deriveYOnG1(x); // If the following two conditions or their negative forms are not met at the same time, get the negative y. // 1. The most significant bit of compressed signature is set // 2. The y we recovered first is the lexicographically largest if (((decision >> 1) ^ (y > N / 2 ? 1 : 0)) == 1) { y = N - y; } return [x, y]; } function isValid(uint256 compressedSignature) public view returns (bool) { uint256 x = compressedSignature & FIELD_MASK; if (x >= N) { return false; } else if (x == 0) { return false; } return isOnCurveG1(x); } function isOnCurveG1(uint256[2] memory point) internal pure returns (bool _isOnCurve) { // solhint-disable-next-line no-inline-assembly assembly { let t0 := mload(point) let t1 := mload(add(point, 32)) let t2 := mulmod(t0, t0, N) t2 := mulmod(t2, t0, N) t2 := addmod(t2, 3, N) t1 := mulmod(t1, t1, N) _isOnCurve := eq(t1, t2) } } function isOnCurveG1(uint256 x) internal view returns (bool _isOnCurve) { bool callSuccess; // solhint-disable-next-line no-inline-assembly assembly { let t0 := x let t1 := mulmod(t0, t0, N) t1 := mulmod(t1, t0, N) // x ^ 3 + b t1 := addmod(t1, 3, N) let freemem := mload(0x40) mstore(freemem, 0x20) mstore(add(freemem, 0x20), 0x20) mstore(add(freemem, 0x40), 0x20) mstore(add(freemem, 0x60), t1) // (N - 1) / 2 = 0x183227397098d014dc2822db40c0ac2ecbc0b548b438e5469e10460b6c3e7ea3 mstore(add(freemem, 0x80), 0x183227397098d014dc2822db40c0ac2ecbc0b548b438e5469e10460b6c3e7ea3) // N = 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47 mstore(add(freemem, 0xA0), 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47) callSuccess := staticcall(sub(gas(), 2000), 5, freemem, 0xC0, freemem, 0x20) _isOnCurve := eq(1, mload(freemem)) } } function isOnCurveG2(uint256[4] memory point) internal pure returns (bool _isOnCurve) { // solhint-disable-next-line no-inline-assembly assembly { // x0, x1 let t0 := mload(point) let t1 := mload(add(point, 32)) // x0 ^ 2 let t2 := mulmod(t0, t0, N) // x1 ^ 2 let t3 := mulmod(t1, t1, N) // 3 * x0 ^ 2 let t4 := add(add(t2, t2), t2) // 3 * x1 ^ 2 let t5 := addmod(add(t3, t3), t3, N) // x0 * (x0 ^ 2 - 3 * x1 ^ 2) t2 := mulmod(add(t2, sub(N, t5)), t0, N) // x1 * (3 * x0 ^ 2 - x1 ^ 2) t3 := mulmod(add(t4, sub(N, t3)), t1, N) // x ^ 3 + b t0 := addmod(t2, 0x2b149d40ceb8aaae81be18991be06ac3b5b4c5e559dbefa33267e6dc24a138e5, N) t1 := addmod(t3, 0x009713b03af0fed4cd2cafadeed8fdf4a74fa084e52d1852e4a2bd0685c315d2, N) // y0, y1 t2 := mload(add(point, 64)) t3 := mload(add(point, 96)) // y ^ 2 t4 := mulmod(addmod(t2, t3, N), addmod(t2, sub(N, t3), N), N) t3 := mulmod(shl(1, t2), t3, N) // y ^ 2 == x ^ 3 + b _isOnCurve := and(eq(t0, t4), eq(t1, t3)) } } function sqrt(uint256 xx) internal view returns (uint256 x, bool hasRoot) { bool callSuccess; // solhint-disable-next-line no-inline-assembly assembly { let freemem := mload(0x40) mstore(freemem, 0x20) mstore(add(freemem, 0x20), 0x20) mstore(add(freemem, 0x40), 0x20) mstore(add(freemem, 0x60), xx) // this is enabled by N % 4 = 3 and Fermat's little theorem // (N + 1) / 4 = 0xc19139cb84c680a6e14116da060561765e05aa45a1c72a34f082305b61f3f52 mstore(add(freemem, 0x80), 0xc19139cb84c680a6e14116da060561765e05aa45a1c72a34f082305b61f3f52) // N = 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47 mstore(add(freemem, 0xA0), 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47) callSuccess := staticcall(sub(gas(), 2000), 5, freemem, 0xC0, freemem, 0x20) x := mload(freemem) hasRoot := eq(xx, mulmod(x, x, N)) } require(callSuccess, "BLS: sqrt modexp call failed"); } /// @notice Add two points in G1 function addPoints(uint256[2] memory p1, uint256[2] memory p2) internal view returns (uint256[2] memory ret) { uint256[4] memory input; input[0] = p1[0]; input[1] = p1[1]; input[2] = p2[0]; input[3] = p2[1]; bool success; // solhint-disable-next-line no-inline-assembly assembly { success := staticcall(sub(gas(), 2000), 6, input, 0xc0, ret, 0x60) } // solhint-disable-next-line reason-string require(success); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.18; import {IController} from "../interfaces/IController.sol"; // solhint-disable-next-line no-global-import import "../utils/Utils.sol" as Utils; library GroupLib { // *Constants* uint256 public constant DEFAULT_MINIMUM_THRESHOLD = 3; struct GroupData { uint256 epoch; uint256 groupCount; mapping(uint256 => IController.Group) groups; // group_index => Group struct uint256 idealNumberOfGroups; uint256 groupMaxCapacity; uint256 defaultNumberOfCommitters; } event GroupRebalanced(uint256 indexed groupIndex1, uint256 indexed groupIndex2); // ============= // Transaction // ============= function setConfig( GroupData storage groupData, uint256 idealNumberOfGroups, uint256 groupMaxCapacity, uint256 defaultNumberOfCommitters ) public { groupData.idealNumberOfGroups = idealNumberOfGroups; groupData.groupMaxCapacity = groupMaxCapacity; groupData.defaultNumberOfCommitters = defaultNumberOfCommitters; } function nodeJoin(GroupData storage groupData, address idAddress, uint256 lastOutput) public returns (uint256 groupIndex, uint256[] memory groupIndicesToEmitEvent) { groupIndicesToEmitEvent = new uint256[](0); bool needRebalance; (groupIndex, needRebalance) = findOrCreateTargetGroup(groupData); bool needEmitGroupEvent = addToGroup(groupData, idAddress, groupIndex); if (needEmitGroupEvent) { groupIndicesToEmitEvent = new uint256[](1); groupIndicesToEmitEvent[0] = groupIndex; return (groupIndex, groupIndicesToEmitEvent); } if (needRebalance) { (bool rebalanceSuccess, uint256 groupIndexToRebalance) = tryRebalanceGroup(groupData, groupIndex, lastOutput); if (rebalanceSuccess) { groupIndicesToEmitEvent = new uint256[](2); groupIndicesToEmitEvent[0] = groupIndex; groupIndicesToEmitEvent[1] = groupIndexToRebalance; } } } function nodeLeave(GroupData storage groupData, address idAddress, uint256 lastOutput) public returns (uint256[] memory groupIndicesToEmitEvent) { groupIndicesToEmitEvent = new uint256[](0); (int256 groupIndex, int256 memberIndex) = getBelongingGroupByMemberAddress(groupData, idAddress); if (groupIndex != -1) { (bool needRebalance, bool needEmitGroupEvent) = removeFromGroup(groupData, uint256(memberIndex), uint256(groupIndex)); if (needEmitGroupEvent) { groupIndicesToEmitEvent = new uint256[](1); groupIndicesToEmitEvent[0] = uint256(groupIndex); return groupIndicesToEmitEvent; } if (needRebalance) { return arrangeMembersInGroup(groupData, uint256(groupIndex), lastOutput); } } } function tryEnableGroup(GroupData storage groupData, uint256 groupIndex, uint256 lastOutput) public returns (bool success, address[] memory disqualifiedNodes) { IController.Group storage g = groupData.groups[groupIndex]; IController.CommitCache memory identicalCommits = getStrictlyMajorityIdenticalCommitmentResult(groupData, groupIndex); if (identicalCommits.nodeIdAddress.length != 0) { disqualifiedNodes = identicalCommits.commitResult.disqualifiedNodes; // Get list of majority members with disqualified nodes excluded address[] memory majorityMembers = Utils.getNonDisqualifiedMajorityMembers(identicalCommits.nodeIdAddress, disqualifiedNodes); if (majorityMembers.length >= g.threshold) { // Remove all members from group where member.nodeIdAddress is in the disqualified nodes. for (uint256 i = 0; i < disqualifiedNodes.length; i++) { for (uint256 j = 0; j < g.members.length; j++) { if (g.members[j].nodeIdAddress == disqualifiedNodes[i]) { g.members[j] = g.members[g.members.length - 1]; g.members.pop(); break; } } } // Update group with new values g.isStrictlyMajorityConsensusReached = true; g.size -= identicalCommits.commitResult.disqualifiedNodes.length; g.publicKey = identicalCommits.commitResult.publicKey; // Create indexMemberMap: Iterate through group.members and create mapping: memberIndex -> nodeIdAddress // Create qualifiedIndices: Iterate through group, add all member indexes found in majorityMembers. uint256[] memory qualifiedIndices = new uint256[]( majorityMembers.length ); for (uint256 j = 0; j < majorityMembers.length; j++) { for (uint256 i = 0; i < g.members.length; i++) { if (g.members[i].nodeIdAddress == majorityMembers[j]) { qualifiedIndices[j] = i; break; } } } // Compute commiter_indices by calling pickRandomIndex with qualifiedIndices as input. uint256[] memory committerIndices = Utils.pickRandomIndex(lastOutput, qualifiedIndices, groupData.defaultNumberOfCommitters); // For selected commiter_indices: add corresponding members into g.committers g.committers = new address[](committerIndices.length); for (uint256 i = 0; i < committerIndices.length; i++) { g.committers[i] = g.members[committerIndices[i]].nodeIdAddress; } return (true, disqualifiedNodes); } } } function handleUnsuccessfulGroupDkg(GroupData storage groupData, uint256 groupIndex, uint256 lastOutput) public returns (address[] memory nodesToBeSlashed, uint256[] memory groupIndicesToEmitEvent) { IController.Group storage g = groupData.groups[groupIndex]; // get strictly majority identical commitment result IController.CommitCache memory majorityMembers = getStrictlyMajorityIdenticalCommitmentResult(groupData, groupIndex); if (majorityMembers.nodeIdAddress.length == 0) { // if empty cache: zero out group g.size = 0; g.threshold = 0; nodesToBeSlashed = new address[](g.members.length); for (uint256 i = 0; i < g.members.length; i++) { nodesToBeSlashed[i] = g.members[i].nodeIdAddress; } // zero out group members delete g.members; return (nodesToBeSlashed, new uint256[](0)); } else { address[] memory disqualifiedNodes = majorityMembers.commitResult.disqualifiedNodes; g.size -= disqualifiedNodes.length; uint256 minimum = Utils.minimumThreshold(g.size); // set g.threshold to max (default min threshold / minimum threshold) g.threshold = GroupLib.DEFAULT_MINIMUM_THRESHOLD > minimum ? GroupLib.DEFAULT_MINIMUM_THRESHOLD : minimum; // Delete disqualified members from group for (uint256 j = 0; j < disqualifiedNodes.length; j++) { for (uint256 i = 0; i < g.members.length; i++) { if (g.members[i].nodeIdAddress == disqualifiedNodes[j]) { g.members[i] = g.members[g.members.length - 1]; g.members.pop(); break; } } } return (disqualifiedNodes, arrangeMembersInGroup(groupData, groupIndex, lastOutput)); } } function tryAddToExistingCommitCache( GroupData storage groupData, uint256 groupIndex, IController.CommitResult memory commitResult ) public returns (bool isExist) { IController.Group storage g = groupData.groups[groupIndex]; for (uint256 i = 0; i < g.commitCacheList.length; i++) { if (keccak256(abi.encode(g.commitCacheList[i].commitResult)) == keccak256(abi.encode(commitResult))) { g.commitCacheList[i].nodeIdAddress.push(msg.sender); return true; } } } function prepareGroupEvent(GroupData storage groupData, uint256 groupIndex) internal { groupData.epoch++; IController.Group storage g = groupData.groups[groupIndex]; g.epoch++; g.isStrictlyMajorityConsensusReached = false; delete g.committers; delete g.commitCacheList; for (uint256 i = 0; i < g.members.length; i++) { delete g.members[i].partialPublicKey; } } // ============= // View // ============= // Find group with member address equals to nodeIdAddress, return -1 if not found. function getBelongingGroupByMemberAddress(GroupData storage groupData, address nodeIdAddress) public view returns (int256, int256) { for (uint256 i = 0; i < groupData.groupCount; i++) { int256 memberIndex = getMemberIndexByAddress(groupData, i, nodeIdAddress); if (memberIndex != -1) { return (int256(i), memberIndex); } } return (-1, -1); } function getMemberIndexByAddress(GroupData storage groupData, uint256 groupIndex, address nodeIdAddress) public view returns (int256) { IController.Group memory g = groupData.groups[groupIndex]; for (uint256 i = 0; i < g.members.length; i++) { if (g.members[i].nodeIdAddress == nodeIdAddress) { return int256(i); } } return -1; } function getValidGroupIndices(GroupData storage groupData) public view returns (uint256[] memory) { uint256[] memory groupIndices = new uint256[](groupData.groupCount); //max length is group count uint256 index = 0; for (uint256 i = 0; i < groupData.groupCount; i++) { IController.Group memory g = groupData.groups[i]; if (g.isStrictlyMajorityConsensusReached) { groupIndices[index] = i; index++; } } return Utils.trimTrailingElements(groupIndices, index); } // ============= // Internal // ============= // Tries to rebalance the groups, and if it fails, it collects the IDs of the members in the group and tries to add them to other groups. // If a member is added to another group, the group is checked to see if its size meets a threshold; if it does, a group event is emitted. function arrangeMembersInGroup(GroupData storage groupData, uint256 groupIndex, uint256 lastOutput) internal returns (uint256[] memory groupIndicesToEmitEvent) { groupIndicesToEmitEvent = new uint256[](0); IController.Group storage g = groupData.groups[groupIndex]; if (g.size == 0) { return groupIndicesToEmitEvent; } (bool rebalanceSuccess, uint256 groupIndexToRebalance) = tryRebalanceGroup(groupData, groupIndex, lastOutput); if (rebalanceSuccess) { groupIndicesToEmitEvent = new uint256[](2); groupIndicesToEmitEvent[0] = groupIndex; groupIndicesToEmitEvent[1] = groupIndexToRebalance; return groupIndicesToEmitEvent; } // Get group and set isStrictlyMajorityConsensusReached to false g.isStrictlyMajorityConsensusReached = false; // collect idAddress of members in group address[] memory membersLeftInGroup = new address[](g.members.length); for (uint256 i = 0; i < g.members.length; i++) { membersLeftInGroup[i] = g.members[i].nodeIdAddress; } uint256[] memory involvedGroups = new uint256[](groupData.groupCount); // max number of groups involved is groupCount uint256 currentIndex; // for each membersLeftInGroup, call findOrCreateTargetGroup and then add that member to the new group. for (uint256 i = 0; i < membersLeftInGroup.length; i++) { // find a suitable group for the member (uint256 targetGroupIndex,) = findOrCreateTargetGroup(groupData); // if the current group index is selected, break if (groupIndex == targetGroupIndex) { break; } // add member to target group addToGroup(groupData, membersLeftInGroup[i], targetGroupIndex); if (groupData.groups[i].size >= DEFAULT_MINIMUM_THRESHOLD) { involvedGroups[currentIndex] = targetGroupIndex; currentIndex++; } } return Utils.trimTrailingElements(involvedGroups, currentIndex); } function tryRebalanceGroup(GroupData storage groupData, uint256 groupIndex, uint256 lastOutput) internal returns (bool rebalanceSuccess, uint256 groupIndexToRebalance) { // get all group indices excluding the current groupIndex uint256[] memory groupIndices = new uint256[](groupData.groupCount -1); uint256 index = 0; for (uint256 i = 0; i < groupData.groupCount; i++) { if (i != groupIndex) { groupIndices[index] = i; index++; } } // try to reblance each group, if succesful, return true for (uint256 i = 0; i < groupIndices.length; i++) { if (rebalanceGroup(groupData, groupIndices[i], groupIndex, lastOutput)) { return (true, groupIndices[i]); } } } function rebalanceGroup(GroupData storage groupData, uint256 groupAIndex, uint256 groupBIndex, uint256 lastOutput) internal returns (bool) { IController.Group memory groupA = groupData.groups[groupAIndex]; IController.Group memory groupB = groupData.groups[groupBIndex]; if (groupB.size > groupA.size) { (groupA, groupB) = (groupB, groupA); (groupAIndex, groupBIndex) = (groupBIndex, groupAIndex); } uint256 expectedSizeToMove = groupA.size - (groupA.size + groupB.size) / 2; if (expectedSizeToMove == 0 || groupA.size - expectedSizeToMove < DEFAULT_MINIMUM_THRESHOLD) { return false; } // Move members from group A to group B for (uint256 i = 0; i < expectedSizeToMove; i++) { uint256 memberIndex = Utils.pickRandomIndex(lastOutput, groupA.members.length - i); address memberAddress = getMemberAddressByIndex(groupData, groupAIndex, memberIndex); removeFromGroup(groupData, memberIndex, groupAIndex); addToGroup(groupData, memberAddress, groupBIndex); } emit GroupRebalanced(groupAIndex, groupBIndex); return true; } function findOrCreateTargetGroup(GroupData storage groupData) internal returns (uint256 groupIndex, bool needsRebalance) { // if group is empty, addgroup. if (groupData.groupCount == 0) { return (addGroup(groupData), false); } // get the group index of the group with the minimum size, as well as the min size uint256 indexOfMinSize; uint256 minSize = groupData.groupMaxCapacity; for (uint256 i = 0; i < groupData.groupCount; i++) { IController.Group memory g = groupData.groups[i]; if (g.size < minSize) { minSize = g.size; indexOfMinSize = i; } } // compute the valid group count uint256 validGroupCount = getValidGroupIndices(groupData).length; // check if valid group count < ideal_number_of_groups || minSize == group_max_capacity // If either condition is met and the number of valid groups == group count, call add group and return (index of new group, true) if ( (validGroupCount < groupData.idealNumberOfGroups && validGroupCount == groupData.groupCount) || (minSize == groupData.groupMaxCapacity) ) return (addGroup(groupData), true); // if none of the above conditions are met: return (indexOfMinSize, false); } function addGroup(GroupData storage groupData) internal returns (uint256) { uint256 groupIndex = groupData.groupCount; // groupIndex starts at 0. groupCount is index of next group to be added groupData.groupCount++; IController.Group storage g = groupData.groups[groupIndex]; g.index = groupIndex; g.size = 0; g.threshold = DEFAULT_MINIMUM_THRESHOLD; return groupIndex; } function addToGroup(GroupData storage groupData, address idAddress, uint256 groupIndex) internal returns (bool needEmitGroupEvent) { // Get group from group index IController.Group storage g = groupData.groups[groupIndex]; // Add Member Struct to group at group index IController.Member memory m; m.nodeIdAddress = idAddress; // insert (node id address - > member) into group.members g.members.push(m); g.size++; // assign group threshold uint256 minimum = Utils.minimumThreshold(g.size); // 51% of group size // max of 51% of group size and DEFAULT_MINIMUM_THRESHOLD g.threshold = minimum > DEFAULT_MINIMUM_THRESHOLD ? minimum : DEFAULT_MINIMUM_THRESHOLD; if (g.size >= 3) { return true; } } function removeFromGroup(GroupData storage groupData, uint256 memberIndex, uint256 groupIndex) public returns (bool needRebalance, bool needEmitGroupEvent) { IController.Group storage g = groupData.groups[groupIndex]; g.size--; if (g.size == 0) { delete g.members; g.threshold = 0; return (false, false); } // Remove node from members g.members[memberIndex] = g.members[g.members.length - 1]; g.members.pop(); uint256 minimum = Utils.minimumThreshold(g.size); g.threshold = minimum > DEFAULT_MINIMUM_THRESHOLD ? minimum : DEFAULT_MINIMUM_THRESHOLD; if (g.size < 3) { return (true, false); } return (false, true); } // Get array of majority members with identical commit result. Return commit cache. if no majority, return empty commit cache. function getStrictlyMajorityIdenticalCommitmentResult(GroupData storage groupData, uint256 groupIndex) internal view returns (IController.CommitCache memory) { IController.CommitCache memory emptyCache; // If there are no commit caches, return empty commit cache. IController.Group memory g = groupData.groups[groupIndex]; if (g.commitCacheList.length == 0) { return (emptyCache); } // If there is only one commit cache, return it. if (g.commitCacheList.length == 1) { return (g.commitCacheList[0]); } // If there are multiple commit caches, check if there is a majority. bool isStrictlyMajorityExist = true; IController.CommitCache memory majorityCommitCache = g.commitCacheList[0]; for (uint256 i = 1; i < g.commitCacheList.length; i++) { IController.CommitCache memory commitCache = g.commitCacheList[i]; if (commitCache.nodeIdAddress.length > majorityCommitCache.nodeIdAddress.length) { isStrictlyMajorityExist = true; majorityCommitCache = commitCache; } else if (commitCache.nodeIdAddress.length == majorityCommitCache.nodeIdAddress.length) { isStrictlyMajorityExist = false; } } // If no majority, return empty commit cache. if (!isStrictlyMajorityExist) { return (emptyCache); } // If majority, return majority commit cache return (majorityCommitCache); } function getMemberAddressByIndex(GroupData storage groupData, uint256 groupIndex, uint256 memberIndex) internal view returns (address nodeIdAddress) { IController.Group memory g = groupData.groups[groupIndex]; return g.members[memberIndex].nodeIdAddress; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.18; import {Ownable} from "openzeppelin-contracts/contracts/access/Ownable.sol"; contract Coordinator is Ownable { /// Mapping of Ethereum Address => DKG public keys mapping(address => bytes) public keys; /// Mapping of Ethereum Address => DKG Phase 1 Shares mapping(address => bytes) public shares; /// Mapping of Ethereum Address => DKG Phase 2 Responses mapping(address => bytes) public responses; /// Mapping of Ethereum Address => DKG Phase 3 Justifications mapping(address => bytes) public justifications; // List of registered Ethereum keys (used for conveniently fetching data) address[] public participants; /// The duration of each phase uint256 public immutable phaseDuration; /// The dkgThreshold of the DKG uint256 public immutable dkgThreshold; /// If it's 0 then the DKG is still pending start. If >0, it is the DKG's start block uint256 public startBlock = 0; /// A group member is one whose pubkey's length > 0 modifier onlyGroupMember() { require(keys[msg.sender].length > 0, "you are not a group member!"); _; } /// The DKG starts when startBlock > 0 modifier onlyWhenNotStarted() { require(startBlock == 0, "DKG has already started"); _; } constructor(uint256 threshold, uint256 duration) { dkgThreshold = threshold; phaseDuration = duration; } function initialize(address[] calldata nodes, bytes[] calldata publicKeys) external onlyWhenNotStarted onlyOwner { for (uint256 i = 0; i < nodes.length; i++) { participants.push(nodes[i]); keys[nodes[i]] = publicKeys[i]; } startBlock = block.number; } /// Participant publishes their data and depending on the phase the data gets inserted /// in the shares, responses or justifications mapping. Reverts if the participant /// has already published their data for a phase or if the DKG has ended. function publish(bytes calldata value) external onlyGroupMember { uint256 blocksSinceStart = block.number - startBlock; if (blocksSinceStart <= phaseDuration) { require(shares[msg.sender].length == 0, "share existed"); shares[msg.sender] = value; } else if (blocksSinceStart <= 2 * phaseDuration) { require(responses[msg.sender].length == 0, "response existed"); responses[msg.sender] = value; } else if (blocksSinceStart <= 3 * phaseDuration) { require(justifications[msg.sender].length == 0, "justification existed"); justifications[msg.sender] = value; } else { revert("DKG Publish has ended"); } } // Helpers to fetch data in the mappings. If a participant has registered but not // published their data for a phase, the array element at their index is expected to be 0 /// Gets the participants' shares function getShares() external view returns (bytes[] memory) { bytes[] memory _shares = new bytes[](participants.length); for (uint256 i = 0; i < participants.length; i++) { _shares[i] = shares[participants[i]]; } return _shares; } /// Gets the participants' responses function getResponses() external view returns (bytes[] memory) { bytes[] memory _responses = new bytes[](participants.length); for (uint256 i = 0; i < participants.length; i++) { _responses[i] = responses[participants[i]]; } return _responses; } /// Gets the participants' justifications function getJustifications() external view returns (bytes[] memory) { bytes[] memory _justifications = new bytes[](participants.length); for (uint256 i = 0; i < participants.length; i++) { _justifications[i] = justifications[participants[i]]; } return _justifications; } /// Gets the participants' ethereum addresses function getParticipants() external view returns (address[] memory) { return participants; } /// Gets the participants' DKG keys along with the thershold of the DKG function getDkgKeys() external view returns (uint256, bytes[] memory) { bytes[] memory _keys = new bytes[](participants.length); for (uint256 i = 0; i < participants.length; i++) { _keys[i] = keys[participants[i]]; } return (dkgThreshold, _keys); } /// Returns the current phase of the DKG. function inPhase() public view returns (int8) { // Phase 0 for after deployment before initialization. if (startBlock == 0) { return 0; } uint256 blocksSinceStart = block.number - startBlock; if (blocksSinceStart <= phaseDuration) { return 1; // share } if (blocksSinceStart <= 2 * phaseDuration) { return 2; // response } if (blocksSinceStart <= 3 * phaseDuration) { return 3; // justification } if (blocksSinceStart <= 4 * phaseDuration) { return 4; // Commit DKG: Handled in controller } // DKG Ended, commit_dkg should be called before this return -1; } function selfDestruct() external onlyOwner { selfdestruct(payable(owner())); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 amount ) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; import "../proxy/utils/Initializable.sol"; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract ContextUpgradeable is Initializable { function __Context_init() internal onlyInitializing { } function __Context_init_unchained() internal onlyInitializing { } function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library AddressUpgradeable { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.18; interface IRequestTypeBase { enum RequestType { Randomness, RandomWords, Shuffling } }
// SPDX-License-Identifier: LGPL 3.0 pragma solidity ^0.8.18; /** * @title Elliptic curve operations on twist points for alt_bn128 * @author ARPA-Network adapted from https://github.com/musalbas/solidity-BN256G2 * @dev Homepage: https://github.com/ARPA-Network/BLS-TSS-Network */ library BN256G2 { uint256 public constant FIELD_MODULUS = 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47; uint256 public constant TWISTBX = 0x2b149d40ceb8aaae81be18991be06ac3b5b4c5e559dbefa33267e6dc24a138e5; uint256 public constant TWISTBY = 0x9713b03af0fed4cd2cafadeed8fdf4a74fa084e52d1852e4a2bd0685c315d2; uint256 public constant PTXX = 0; uint256 public constant PTXY = 1; uint256 public constant PTYX = 2; uint256 public constant PTYY = 3; uint256 public constant PTZX = 4; uint256 public constant PTZY = 5; function ecTwistAdd(uint256[4] memory pt1, uint256[4] memory pt2) internal view returns (uint256[4] memory pt) { (uint256 xx, uint256 xy, uint256 yx, uint256 yy) = ecTwistAdd(pt1[0], pt1[1], pt1[2], pt1[3], pt2[0], pt2[1], pt2[2], pt2[3]); pt = [xx, xy, yx, yy]; } /** * @notice Add two twist points * @param pt1xx Coefficient 1 of x on point 1 * @param pt1xy Coefficient 2 of x on point 1 * @param pt1yx Coefficient 1 of y on point 1 * @param pt1yy Coefficient 2 of y on point 1 * @param pt2xx Coefficient 1 of x on point 2 * @param pt2xy Coefficient 2 of x on point 2 * @param pt2yx Coefficient 1 of y on point 2 * @param pt2yy Coefficient 2 of y on point 2 * @return (pt3xx, pt3xy, pt3yx, pt3yy) */ function ecTwistAdd( uint256 pt1xx, uint256 pt1xy, uint256 pt1yx, uint256 pt1yy, uint256 pt2xx, uint256 pt2xy, uint256 pt2yx, uint256 pt2yy ) internal view returns (uint256, uint256, uint256, uint256) { if (pt1xx == 0 && pt1xy == 0 && pt1yx == 0 && pt1yy == 0) { if (!(pt2xx == 0 && pt2xy == 0 && pt2yx == 0 && pt2yy == 0)) { assert(isOnCurve(pt2xx, pt2xy, pt2yx, pt2yy)); } return (pt2xx, pt2xy, pt2yx, pt2yy); } else if (pt2xx == 0 && pt2xy == 0 && pt2yx == 0 && pt2yy == 0) { assert(isOnCurve(pt1xx, pt1xy, pt1yx, pt1yy)); return (pt1xx, pt1xy, pt1yx, pt1yy); } assert(isOnCurve(pt1xx, pt1xy, pt1yx, pt1yy)); assert(isOnCurve(pt2xx, pt2xy, pt2yx, pt2yy)); uint256[6] memory pt1 = [pt1xx, pt1xy, pt1yx, pt1yy, 1, 0]; uint256[6] memory pt2 = [pt2xx, pt2xy, pt2yx, pt2yy, 1, 0]; uint256[6] memory pt3 = ecTwistAddJacobian(pt1, pt2); return fromJacobian(pt3[PTXX], pt3[PTXY], pt3[PTYX], pt3[PTYY], pt3[PTZX], pt3[PTZY]); } function submod(uint256 a, uint256 b, uint256 n) internal pure returns (uint256) { return addmod(a, n - b, n); } function fq2Mul(uint256 xx, uint256 xy, uint256 yx, uint256 yy) internal pure returns (uint256, uint256) { return ( submod(mulmod(xx, yx, FIELD_MODULUS), mulmod(xy, yy, FIELD_MODULUS), FIELD_MODULUS), addmod(mulmod(xx, yy, FIELD_MODULUS), mulmod(xy, yx, FIELD_MODULUS), FIELD_MODULUS) ); } function fq2Muc(uint256 xx, uint256 xy, uint256 c) internal pure returns (uint256, uint256) { return (mulmod(xx, c, FIELD_MODULUS), mulmod(xy, c, FIELD_MODULUS)); } function fq2Sub(uint256 xx, uint256 xy, uint256 yx, uint256 yy) internal pure returns (uint256 rx, uint256 ry) { return (submod(xx, yx, FIELD_MODULUS), submod(xy, yy, FIELD_MODULUS)); } function fq2Inv(uint256 x, uint256 y) internal view returns (uint256, uint256) { uint256 inv = modInv(addmod(mulmod(y, y, FIELD_MODULUS), mulmod(x, x, FIELD_MODULUS), FIELD_MODULUS), FIELD_MODULUS); return (mulmod(x, inv, FIELD_MODULUS), FIELD_MODULUS - mulmod(y, inv, FIELD_MODULUS)); } function isOnCurve(uint256 xx, uint256 xy, uint256 yx, uint256 yy) internal pure returns (bool) { uint256 yyx; uint256 yyy; uint256 xxxx; uint256 xxxy; (yyx, yyy) = fq2Mul(yx, yy, yx, yy); (xxxx, xxxy) = fq2Mul(xx, xy, xx, xy); (xxxx, xxxy) = fq2Mul(xxxx, xxxy, xx, xy); (yyx, yyy) = fq2Sub(yyx, yyy, xxxx, xxxy); (yyx, yyy) = fq2Sub(yyx, yyy, TWISTBX, TWISTBY); return yyx == 0 && yyy == 0; } function modInv(uint256 a, uint256 n) internal view returns (uint256 result) { bool success; // solhint-disable-next-line no-inline-assembly assembly { let freemem := mload(0x40) mstore(freemem, 0x20) mstore(add(freemem, 0x20), 0x20) mstore(add(freemem, 0x40), 0x20) mstore(add(freemem, 0x60), a) mstore(add(freemem, 0x80), sub(n, 2)) mstore(add(freemem, 0xA0), n) success := staticcall(sub(gas(), 2000), 5, freemem, 0xC0, freemem, 0x20) result := mload(freemem) } // solhint-disable-next-line reason-string require(success); } function fromJacobian(uint256 pt1xx, uint256 pt1xy, uint256 pt1yx, uint256 pt1yy, uint256 pt1zx, uint256 pt1zy) internal view returns (uint256 pt2xx, uint256 pt2xy, uint256 pt2yx, uint256 pt2yy) { uint256 invzx; uint256 invzy; (invzx, invzy) = fq2Inv(pt1zx, pt1zy); (pt2xx, pt2xy) = fq2Mul(pt1xx, pt1xy, invzx, invzy); (pt2yx, pt2yy) = fq2Mul(pt1yx, pt1yy, invzx, invzy); } function ecTwistAddJacobian(uint256[6] memory pt1, uint256[6] memory pt2) public pure returns (uint256[6] memory pt3) { if (pt1[4] == 0 && pt1[5] == 0) { (pt3[PTXX], pt3[PTXY], pt3[PTYX], pt3[PTYY], pt3[PTZX], pt3[PTZY]) = (pt2[0], pt2[1], pt2[2], pt2[3], pt2[4], pt2[5]); return pt3; } else if (pt2[4] == 0 && pt2[5] == 0) { (pt3[PTXX], pt3[PTXY], pt3[PTYX], pt3[PTYY], pt3[PTZX], pt3[PTZY]) = (pt1[0], pt1[1], pt1[2], pt1[3], pt1[4], pt1[5]); return pt3; } (pt2[2], pt2[3]) = fq2Mul(pt2[2], pt2[3], pt1[4], pt1[5]); // U1 = y2 * z1 (pt3[PTYX], pt3[PTYY]) = fq2Mul(pt1[2], pt1[3], pt2[4], pt2[5]); // U2 = y1 * z2 (pt2[0], pt2[1]) = fq2Mul(pt2[0], pt2[1], pt1[4], pt1[5]); // V1 = x2 * z1 (pt3[PTZX], pt3[PTZY]) = fq2Mul(pt1[0], pt1[1], pt2[4], pt2[5]); // V2 = x1 * z2 if (pt2[0] == pt3[PTZX] && pt2[1] == pt3[PTZY]) { if (pt2[2] == pt3[PTYX] && pt2[3] == pt3[PTYY]) { (pt3[PTXX], pt3[PTXY], pt3[PTYX], pt3[PTYY], pt3[PTZX], pt3[PTZY]) = ecTwistDoubleJacobian(pt1[0], pt1[1], pt1[2], pt1[3], pt1[4], pt1[5]); return pt3; } (pt3[PTXX], pt3[PTXY], pt3[PTYX], pt3[PTYY], pt3[PTZX], pt3[PTZY]) = (1, 0, 1, 0, 0, 0); return pt3; } (pt2[4], pt2[5]) = fq2Mul(pt1[4], pt1[5], pt2[4], pt2[5]); // W = z1 * z2 (pt1[0], pt1[1]) = fq2Sub(pt2[2], pt2[3], pt3[PTYX], pt3[PTYY]); // U = U1 - U2 (pt1[2], pt1[3]) = fq2Sub(pt2[0], pt2[1], pt3[PTZX], pt3[PTZY]); // V = V1 - V2 (pt1[4], pt1[5]) = fq2Mul(pt1[2], pt1[3], pt1[2], pt1[3]); // V_squared = V * V (pt2[2], pt2[3]) = fq2Mul(pt1[4], pt1[5], pt3[PTZX], pt3[PTZY]); // V_squared_times_V2 = V_squared * V2 (pt1[4], pt1[5]) = fq2Mul(pt1[4], pt1[5], pt1[2], pt1[3]); // V_cubed = V * V_squared (pt3[PTZX], pt3[PTZY]) = fq2Mul(pt1[4], pt1[5], pt2[4], pt2[5]); // newz = V_cubed * W (pt2[0], pt2[1]) = fq2Mul(pt1[0], pt1[1], pt1[0], pt1[1]); // U * U (pt2[0], pt2[1]) = fq2Mul(pt2[0], pt2[1], pt2[4], pt2[5]); // U * U * W (pt2[0], pt2[1]) = fq2Sub(pt2[0], pt2[1], pt1[4], pt1[5]); // U * U * W - V_cubed (pt2[4], pt2[5]) = fq2Muc(pt2[2], pt2[3], 2); // 2 * V_squared_times_V2 (pt2[0], pt2[1]) = fq2Sub(pt2[0], pt2[1], pt2[4], pt2[5]); // A = U * U * W - V_cubed - 2 * V_squared_times_V2 (pt3[PTXX], pt3[PTXY]) = fq2Mul(pt1[2], pt1[3], pt2[0], pt2[1]); // newx = V * A (pt1[2], pt1[3]) = fq2Sub(pt2[2], pt2[3], pt2[0], pt2[1]); // V_squared_times_V2 - A (pt1[2], pt1[3]) = fq2Mul(pt1[0], pt1[1], pt1[2], pt1[3]); // U * (V_squared_times_V2 - A) (pt1[0], pt1[1]) = fq2Mul(pt1[4], pt1[5], pt3[PTYX], pt3[PTYY]); // V_cubed * U2 (pt3[PTYX], pt3[PTYY]) = fq2Sub(pt1[2], pt1[3], pt1[0], pt1[1]); // newy = U * (V_squared_times_V2 - A) - V_cubed * U2 } function ecTwistDoubleJacobian( uint256 pt1xx, uint256 pt1xy, uint256 pt1yx, uint256 pt1yy, uint256 pt1zx, uint256 pt1zy ) public pure returns (uint256 pt2xx, uint256 pt2xy, uint256 pt2yx, uint256 pt2yy, uint256 pt2zx, uint256 pt2zy) { (pt2xx, pt2xy) = fq2Muc(pt1xx, pt1xy, 3); // 3 * x (pt2xx, pt2xy) = fq2Mul(pt2xx, pt2xy, pt1xx, pt1xy); // W = 3 * x * x (pt1zx, pt1zy) = fq2Mul(pt1yx, pt1yy, pt1zx, pt1zy); // S = y * z (pt2yx, pt2yy) = fq2Mul(pt1xx, pt1xy, pt1yx, pt1yy); // x * y (pt2yx, pt2yy) = fq2Mul(pt2yx, pt2yy, pt1zx, pt1zy); // B = x * y * S (pt1xx, pt1xy) = fq2Mul(pt2xx, pt2xy, pt2xx, pt2xy); // W * W (pt2zx, pt2zy) = fq2Muc(pt2yx, pt2yy, 8); // 8 * B (pt1xx, pt1xy) = fq2Sub(pt1xx, pt1xy, pt2zx, pt2zy); // H = W * W - 8 * B (pt2zx, pt2zy) = fq2Mul(pt1zx, pt1zy, pt1zx, pt1zy); // S_squared = S * S (pt2yx, pt2yy) = fq2Muc(pt2yx, pt2yy, 4); // 4 * B (pt2yx, pt2yy) = fq2Sub(pt2yx, pt2yy, pt1xx, pt1xy); // 4 * B - H (pt2yx, pt2yy) = fq2Mul(pt2yx, pt2yy, pt2xx, pt2xy); // W * (4 * B - H) (pt2xx, pt2xy) = fq2Muc(pt1yx, pt1yy, 8); // 8 * y (pt2xx, pt2xy) = fq2Mul(pt2xx, pt2xy, pt1yx, pt1yy); // 8 * y * y (pt2xx, pt2xy) = fq2Mul(pt2xx, pt2xy, pt2zx, pt2zy); // 8 * y * y * S_squared (pt2yx, pt2yy) = fq2Sub(pt2yx, pt2yy, pt2xx, pt2xy); // newy = W * (4 * B - H) - 8 * y * y * S_squared (pt2xx, pt2xy) = fq2Muc(pt1xx, pt1xy, 2); // 2 * H (pt2xx, pt2xy) = fq2Mul(pt2xx, pt2xy, pt1zx, pt1zy); // newx = 2 * H * S (pt2zx, pt2zy) = fq2Mul(pt1zx, pt1zy, pt2zx, pt2zy); // S * S_squared (pt2zx, pt2zy) = fq2Muc(pt2zx, pt2zy, 8); // newz = 8 * S * S_squared } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.18; // 5k is plenty for an EXTCODESIZE call (2600) + warm CALL (100) // and some arithmetic operations. uint256 constant GAS_FOR_CALL_EXACT_CHECK = 5_000; function containElement(uint256[] memory arr, uint256 element) pure returns (bool) { for (uint256 i = 0; i < arr.length; i++) { if (arr[i] == element) { return true; } } return false; } function containElement(address[] memory arr, address element) pure returns (bool) { for (uint256 i = 0; i < arr.length; i++) { if (arr[i] == element) { return true; } } return false; } /** * @dev returns the minimum threshold for a group of size groupSize */ function minimumThreshold(uint256 groupSize) pure returns (uint256) { return groupSize / 2 + 1; } /** * @dev choose one random index from an array. */ function pickRandomIndex(uint256 seed, uint256 length) pure returns (uint256) { return uint256(keccak256(abi.encodePacked(seed))) % length; } /** * @dev choose "count" random indices from "indices" array. */ function pickRandomIndex(uint256 seed, uint256[] memory indices, uint256 count) pure returns (uint256[] memory) { uint256[] memory chosenIndices = new uint256[](count); // Create copy of indices to avoid modifying original array. uint256[] memory remainingIndices = new uint256[](indices.length); for (uint256 i = 0; i < indices.length; i++) { remainingIndices[i] = indices[i]; } uint256 remainingCount = remainingIndices.length; for (uint256 i = 0; i < count; i++) { uint256 index = uint256(keccak256(abi.encodePacked(seed, i))) % remainingCount; chosenIndices[i] = remainingIndices[index]; remainingIndices[index] = remainingIndices[remainingCount - 1]; remainingCount--; } return chosenIndices; } /** * @dev iterates through list of members and remove disqualified nodes. */ function getNonDisqualifiedMajorityMembers(address[] memory nodeAddresses, address[] memory disqualifiedNodes) pure returns (address[] memory) { address[] memory majorityMembers = new address[](nodeAddresses.length); uint256 majorityMembersLength = 0; for (uint256 i = 0; i < nodeAddresses.length; i++) { if (!containElement(disqualifiedNodes, nodeAddresses[i])) { majorityMembers[majorityMembersLength] = nodeAddresses[i]; majorityMembersLength++; } } // remove trailing zero addresses return trimTrailingElements(majorityMembers, majorityMembersLength); } function trimTrailingElements(uint256[] memory arr, uint256 newLength) pure returns (uint256[] memory) { uint256[] memory output = new uint256[](newLength); for (uint256 i = 0; i < newLength; i++) { output[i] = arr[i]; } return output; } function trimTrailingElements(address[] memory arr, uint256 newLength) pure returns (address[] memory) { address[] memory output = new address[](newLength); for (uint256 i = 0; i < newLength; i++) { output[i] = arr[i]; } return output; } /** * @dev calls target address with exactly gasAmount gas and data as calldata * or reverts if at least gasAmount gas is not available. */ function callWithExactGas(uint256 gasAmount, address target, bytes memory data) returns (bool success) { // solhint-disable-next-line no-inline-assembly assembly { let g := gas() // Compute g -= GAS_FOR_CALL_EXACT_CHECK and check for underflow // The gas actually passed to the callee is min(gasAmount, 63//64*gas available). // We want to ensure that we revert if gasAmount > 63//64*gas available // as we do not want to provide them with less, however that check itself costs // gas. GAS_FOR_CALL_EXACT_CHECK ensures we have at least enough gas to be able // to revert if gasAmount > 63//64*gas available. if lt(g, GAS_FOR_CALL_EXACT_CHECK) { revert(0, 0) } g := sub(g, GAS_FOR_CALL_EXACT_CHECK) // if g - g//64 <= gasAmount, revert // (we subtract g//64 because of EIP-150) if iszero(gt(sub(g, div(g, 64)), gasAmount)) { revert(0, 0) } // solidity calls check that a contract actually exists at the destination, so we do the same if iszero(extcodesize(target)) { revert(0, 0) } // call and return whether we succeeded. ignore return data // call(gas,addr,value,argsOffset,argsLength,retOffset,retLength) success := call(gasAmount, target, 0, add(data, 0x20), mload(data), 0, 0) } return success; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor() { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
{ "remappings": [ "Staking-v0.1/=lib/Staking-v0.1/src/", "ds-test/=lib/forge-std/lib/ds-test/src/", "forge-std/=lib/forge-std/src/", "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/", "openzeppelin-contracts/=lib/openzeppelin-contracts/" ], "optimizer": { "enabled": true, "runs": 500 }, "metadata": { "bytecodeHash": "ipfs", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "paris", "libraries": { "src/libraries/BLS.sol": { "BLS": "0x34E6885e0e9BBEA0Bae36d00D4D9B4ED873f2cA8" }, "src/libraries/GroupLib.sol": { "GroupLib": "0xCd97Ed85f6EDDC535A4f55A4c67C2e02800C2E67" } } }
Contract ABI
API[{"inputs":[{"internalType":"uint256","name":"groupIndex","type":"uint256"}],"name":"CoordinatorNotFound","type":"error"},{"inputs":[{"internalType":"uint256","name":"groupIndex","type":"uint256"}],"name":"DkgNotInProgress","type":"error"},{"inputs":[{"internalType":"uint256","name":"groupIndex","type":"uint256"},{"internalType":"int8","name":"phase","type":"int8"}],"name":"DkgStillInProgress","type":"error"},{"inputs":[{"internalType":"uint256","name":"groupIndex","type":"uint256"},{"internalType":"uint256","name":"inputGroupEpoch","type":"uint256"},{"internalType":"uint256","name":"currentGroupEpoch","type":"uint256"}],"name":"EpochMismatch","type":"error"},{"inputs":[{"internalType":"uint256","name":"groupIndex","type":"uint256"}],"name":"GroupNotExist","type":"error"},{"inputs":[],"name":"InvalidPartialPublicKey","type":"error"},{"inputs":[],"name":"InvalidPublicKey","type":"error"},{"inputs":[],"name":"InvalidZeroAddress","type":"error"},{"inputs":[],"name":"NodeAlreadyActive","type":"error"},{"inputs":[],"name":"NodeAlreadyRegistered","type":"error"},{"inputs":[{"internalType":"uint256","name":"groupIndex","type":"uint256"},{"internalType":"address","name":"nodeIdAddress","type":"address"}],"name":"NodeNotInGroup","type":"error"},{"inputs":[],"name":"NodeNotRegistered","type":"error"},{"inputs":[{"internalType":"uint256","name":"pendingUntilBlock","type":"uint256"}],"name":"NodeStillPending","type":"error"},{"inputs":[{"internalType":"uint256","name":"groupIndex","type":"uint256"},{"internalType":"address","name":"nodeIdAddress","type":"address"}],"name":"PartialKeyAlreadyRegistered","type":"error"},{"inputs":[],"name":"SenderNotAdapter","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"stakingContractAddress","type":"address"},{"indexed":false,"internalType":"address","name":"adapterContractAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"nodeStakingAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"disqualifiedNodePenaltyAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"defaultNumberOfCommitters","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"defaultDkgPhaseDuration","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"groupMaxCapacity","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"idealNumberOfGroups","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"pendingBlockAfterQuit","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"dkgPostProcessReward","type":"uint256"}],"name":"ControllerConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"nodeAddress","type":"address"},{"indexed":false,"internalType":"bytes","name":"dkgPublicKey","type":"bytes"}],"name":"DkgPublicKeyChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"globalEpoch","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"groupIndex","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"groupEpoch","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"size","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"threshold","type":"uint256"},{"indexed":false,"internalType":"address[]","name":"members","type":"address[]"},{"indexed":false,"internalType":"uint256","name":"assignmentBlockHeight","type":"uint256"},{"indexed":false,"internalType":"address","name":"coordinatorAddress","type":"address"}],"name":"DkgTask","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"nodeAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"groupIndex","type":"uint256"}],"name":"NodeActivated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"nodeAddress","type":"address"}],"name":"NodeQuit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"nodeAddress","type":"address"},{"indexed":false,"internalType":"bytes","name":"dkgPublicKey","type":"bytes"},{"indexed":false,"internalType":"uint256","name":"groupIndex","type":"uint256"}],"name":"NodeRegistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"nodeAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"ethAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"arpaAmount","type":"uint256"}],"name":"NodeRewarded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"nodeIdAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"stakingRewardPenalty","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"pendingBlock","type":"uint256"}],"name":"NodeSlashed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[{"internalType":"address[]","name":"nodes","type":"address[]"},{"internalType":"uint256","name":"ethAmount","type":"uint256"},{"internalType":"uint256","name":"arpaAmount","type":"uint256"}],"name":"addReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"dkgPublicKey","type":"bytes"}],"name":"changeDkgPublicKey","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"groupIndex","type":"uint256"},{"internalType":"uint256","name":"groupEpoch","type":"uint256"},{"internalType":"bytes","name":"publicKey","type":"bytes"},{"internalType":"bytes","name":"partialPublicKey","type":"bytes"},{"internalType":"address[]","name":"disqualifiedNodes","type":"address[]"}],"internalType":"struct IController.CommitDkgParams","name":"params","type":"tuple"}],"name":"commitDkg","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"nodeAddress","type":"address"}],"name":"getBelongingGroup","outputs":[{"internalType":"int256","name":"","type":"int256"},{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getControllerConfig","outputs":[{"internalType":"address","name":"stakingContractAddress","type":"address"},{"internalType":"address","name":"adapterContractAddress","type":"address"},{"internalType":"uint256","name":"nodeStakingAmount","type":"uint256"},{"internalType":"uint256","name":"disqualifiedNodePenaltyAmount","type":"uint256"},{"internalType":"uint256","name":"defaultNumberOfCommitters","type":"uint256"},{"internalType":"uint256","name":"defaultDkgPhaseDuration","type":"uint256"},{"internalType":"uint256","name":"groupMaxCapacity","type":"uint256"},{"internalType":"uint256","name":"idealNumberOfGroups","type":"uint256"},{"internalType":"uint256","name":"pendingBlockAfterQuit","type":"uint256"},{"internalType":"uint256","name":"dkgPostProcessReward","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"groupIndex","type":"uint256"}],"name":"getCoordinator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"groupIndex","type":"uint256"}],"name":"getGroup","outputs":[{"components":[{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint256","name":"epoch","type":"uint256"},{"internalType":"uint256","name":"size","type":"uint256"},{"internalType":"uint256","name":"threshold","type":"uint256"},{"components":[{"internalType":"address","name":"nodeIdAddress","type":"address"},{"internalType":"uint256[4]","name":"partialPublicKey","type":"uint256[4]"}],"internalType":"struct IController.Member[]","name":"members","type":"tuple[]"},{"internalType":"address[]","name":"committers","type":"address[]"},{"components":[{"internalType":"address[]","name":"nodeIdAddress","type":"address[]"},{"components":[{"internalType":"uint256","name":"groupEpoch","type":"uint256"},{"internalType":"uint256[4]","name":"publicKey","type":"uint256[4]"},{"internalType":"address[]","name":"disqualifiedNodes","type":"address[]"}],"internalType":"struct IController.CommitResult","name":"commitResult","type":"tuple"}],"internalType":"struct IController.CommitCache[]","name":"commitCacheList","type":"tuple[]"},{"internalType":"bool","name":"isStrictlyMajorityConsensusReached","type":"bool"},{"internalType":"uint256[4]","name":"publicKey","type":"uint256[4]"}],"internalType":"struct IController.Group","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getGroupCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getGroupEpoch","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"groupIndex","type":"uint256"}],"name":"getGroupThreshold","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastOutput","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"groupIndex","type":"uint256"},{"internalType":"uint256","name":"memberIndex","type":"uint256"}],"name":"getMember","outputs":[{"components":[{"internalType":"address","name":"nodeIdAddress","type":"address"},{"internalType":"uint256[4]","name":"partialPublicKey","type":"uint256[4]"}],"internalType":"struct IController.Member","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"nodeAddress","type":"address"}],"name":"getNode","outputs":[{"components":[{"internalType":"address","name":"idAddress","type":"address"},{"internalType":"bytes","name":"dkgPublicKey","type":"bytes"},{"internalType":"bool","name":"state","type":"bool"},{"internalType":"uint256","name":"pendingUntilBlock","type":"uint256"}],"internalType":"struct IController.Node","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"nodeAddress","type":"address"}],"name":"getNodeWithdrawableTokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getValidGroupIndices","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"arpa","type":"address"},{"internalType":"uint256","name":"lastOutput","type":"uint256"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"groupIndex","type":"uint256"},{"internalType":"address","name":"nodeIdAddress","type":"address"}],"name":"isPartialKeyRegistered","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nodeActivate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"nodeQuit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"dkgPublicKey","type":"bytes"}],"name":"nodeRegister","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"}],"name":"nodeWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"groupIndex","type":"uint256"},{"internalType":"uint256","name":"groupEpoch","type":"uint256"}],"name":"postProcessDkg","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"stakingContractAddress","type":"address"},{"internalType":"address","name":"adapterContractAddress","type":"address"},{"internalType":"uint256","name":"nodeStakingAmount","type":"uint256"},{"internalType":"uint256","name":"disqualifiedNodePenaltyAmount","type":"uint256"},{"internalType":"uint256","name":"defaultNumberOfCommitters","type":"uint256"},{"internalType":"uint256","name":"defaultDkgPhaseDuration","type":"uint256"},{"internalType":"uint256","name":"groupMaxCapacity","type":"uint256"},{"internalType":"uint256","name":"idealNumberOfGroups","type":"uint256"},{"internalType":"uint256","name":"pendingBlockAfterQuit","type":"uint256"},{"internalType":"uint256","name":"dkgPostProcessReward","type":"uint256"}],"name":"setControllerConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"lastOutput","type":"uint256"}],"name":"setLastOutput","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
608060405234801561001057600080fd5b50615ff6806100206000396000f3fe60806040523480156200001157600080fd5b5060043610620001dd5760003560e01c80638da5cb5b116200010d578063ceb6065411620000a3578063e37eb96c116200007a578063e37eb96c146200048e578063f2fde38b14620004a5578063f3df080214620004bc578063f49e0ba914620004d357600080fd5b8063ceb6065414620003dd578063d11b8e681462000403578063e275cde6146200047757600080fd5b80639d20904811620000e45780639d209048146200035f578063b330a0fd1462000385578063c2db900b146200039e578063cd6dc68714620003c657600080fd5b80638da5cb5b146200032c578063914eb34d146200033e5780639a075bc3146200035557600080fd5b80634d79a8931162000183578063715018a6116200015a578063715018a614620002f85780637a2af56e14620003025780637ee49cfd146200030c57806380110e4e146200031557600080fd5b80634d79a89314620002b25780634ecea80d14620002d857806351a2b9a014620002ef57600080fd5b80632ff9e52011620001b85780632ff9e520146200023f5780633b6c00b0146200025657806342424d6f146200026d57600080fd5b806306545a9314620001e25780630bf9c5c614620001f9578063227d0f461462000212575b600080fd5b6072545b6040519081526020015b60405180910390f35b620002106200020a36600462003aa3565b62000501565b005b620002296200022336600462003adc565b62000999565b60408051928352602083019190915201620001f0565b620002106200025036600462003b03565b62000a42565b620002296200026736600462003adc565b62000bcf565b620002996200027e36600462003b86565b6000908152607060205260409020546001600160a01b031690565b6040516001600160a01b039091168152602001620001f0565b620002c9620002c336600462003aa3565b62000c59565b604051620001f0919062003be6565b62000210620002e936600462003adc565b62000cf6565b607754620001e6565b6200021062000e26565b6200021062000e3e565b607154620001e6565b620002106200032636600462003bf6565b62000ff1565b6033546001600160a01b031662000299565b620002106200034f36600462003d88565b62001336565b62000210620014a7565b620003766200037036600462003adc565b62001751565b604051620001f0919062003e2e565b6200038f62001875565b604051620001f0919062003e81565b620003b5620003af36600462003ec7565b620018f8565b6040519015158152602001620001f0565b62000210620003d736600462003efa565b62001cc4565b620003f4620003ee36600462003b86565b62001e0e565b604051620001f0919062004056565b606554606654606754606854607654606954607554607454606a54606b54604080516001600160a01b039b8c1681529a90991660208b0152978901969096526060880194909452608087019290925260a086015260c085015260e084015261010083015261012082015261014001620001f0565b620002106200048836600462003bf6565b6200212c565b620002106200049f3660046200418b565b620022fe565b62000210620004b636600462003adc565b62002ada565b62000210620004cd36600462003b86565b62002b59565b62000229620004e436600462003b86565b600090815260736020526040902060038101546002909101549091565b60725482106200052c57604051637f6efcb560e11b8152600481018390526024015b60405180910390fd5b6040516358914d0360e01b8152607160048201526024810183905233604482015273cd97ed85f6eddc535a4f55a4c67c2e02800c2e67906358914d0390606401602060405180830381865af41580156200058a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620005b0919062004262565b19620005d95760405163eb51f5f960e01b81526004810183905233602482015260440162000523565b6000828152607360205260409020600181015482146200062457600181015460405163048b63c360e11b81526004810185905260248101849052604481019190915260640162000523565b6000838152607060205260409020546001600160a01b03166200065e57604051635291bbcf60e01b81526004810184905260240162000523565b60008381526070602090815260409182902054825163221f951160e01b815292516001600160a01b0390911692839263221f9511926004808401938290030181865afa158015620006b3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620006d991906200427c565b60000b60001914620007715783816001600160a01b031663221f95116040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000725573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200074b91906200427c565b60405163f7c06f9160e01b8152600481019290925260000b602482015260440162000523565b806001600160a01b0316639cb8a26a6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015620007ad57600080fd5b505af1158015620007c2573d6000803e3d6000fd5b505050600085815260706020526040902080546001600160a01b031916905550600782015460ff166200092457607754604051630295316d60e51b815260716004820152602481018690526044810191909152600090819073cd97ed85f6eddc535a4f55a4c67c2e02800c2e67906352a62da090606401600060405180830381865af415801562000857573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405262000881919081019062004370565b9150915060005b8251811015620008d657620008c1838281518110620008ab57620008ab620043db565b6020026020010151606560030154600062002b8a565b80620008cd8162004407565b91505062000888565b5060005b815181101562000920576200090b828281518110620008fd57620008fd620043db565b602002602001015162002c47565b80620009178162004407565b915050620008da565b5050505b606b54336000908152606f6020526040812080549091906200094890849062004423565b9091555050606b5460405133917f8353a804115421789f3ab2eeb3f5215943906ce12100c91d40fc865caf742b6f916200098b9160008252602082015260400190565b60405180910390a250505050565b6001600160a01b0381166000908152606e6020526040812054819015620009e7576001600160a01b0383166000908152606e6020526040902054620009e19060019062004439565b620009ea565b60005b6001600160a01b0384166000908152606f60205260409020541562000a36576001600160a01b0384166000908152606f602052604090205462000a309060019062004439565b62000a39565b60005b91509150915091565b62000a4c620032ba565b6040805160e0810182526001600160a01b038c8116808352908c16602083018190528284018c9052606083018b90526080830189905260a0830186905260c0909201849052606580546001600160a01b03199081169092179055606680549091169091179055606789905560688890556069869055606a839055606b829055516301a79f6360e71b81526071600482015260248101849052604481018590526064810187905273cd97ed85f6eddc535a4f55a4c67c2e02800c2e679063d3cfb1809060840160006040518083038186803b15801562000b2a57600080fd5b505af415801562000b3f573d6000803e3d6000fd5b5050604080516001600160a01b03808f1682528d1660208201529081018b9052606081018a90526080810189905260a0810188905260c0810187905260e08101869052610100810185905261012081018490527f3202ca2a288846b65f27bc3e13c1e38aaf2e4356b80b963d67aea8a822645e1f925061014001905060405180910390a150505050505050505050565b60405163787c576760e01b8152607160048201526001600160a01b0382166024820152600090819073cd97ed85f6eddc535a4f55a4c67c2e02800c2e679063787c5767906044016040805180830381865af415801562000c33573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000a3991906200444f565b62000c63620038af565b600083815260736020526040902060040180548390811062000c895762000c89620043db565b6000918252602091829020604080518082018252600590930290910180546001600160a01b0316835281516080810190925291928301906001830160048282826020028201915b81548152602001906001019080831162000cd05750505050508152505090505b92915050565b6001600160a01b03811662000d1e5760405163f6b2911f60e01b815260040160405180910390fd5b336000908152606e6020908152604080832054606f90925290912054600181111562000d8057336000908152606f6020526040902060019081905562000d8090849062000d6c908462004439565b606c546001600160a01b0316919062003316565b600182111562000e2157336000908152606e602052604090206001908190556066546001600160a01b031690630ad98f6a90859062000dc0908662004439565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401600060405180830381600087803b15801562000e0757600080fd5b505af115801562000e1c573d6000803e3d6000fd5b505050505b505050565b62000e30620032ba565b62000e3c60006200337f565b565b336000818152606d60205260409020805490916001600160a01b039091161462000e7a576040516229eaad60e31b815260040160405180910390fd5b60775460405163a6ae8a8160e01b815260716004820152336024820152604481019190915260009073cd97ed85f6eddc535a4f55a4c67c2e02800c2e679063a6ae8a8190606401600060405180830381865af415801562000edf573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405262000f09919081019062004474565b905060005b815181101562000f465762000f31828281518110620008fd57620008fd620043db565b8062000f3d8162004407565b91505062000f0e565b5062000f5833606560050154620033d1565b606554606754604051637eee288d60e01b815233600482015260248101919091526001600160a01b0390911690637eee288d90604401600060405180830381600087803b15801562000fa957600080fd5b505af115801562000fbe573d6000803e3d6000fd5b50506040513392507f68577adbb6b0647e21353ff032be5797d9fa0879ce7e05fe617e40368441f97d9150600090a25050565b336000908152606d60205260409020546001600160a01b0316156200102957604051630eb0d31360e11b815260040160405180910390fd5b6040516316f6db8160e01b81526000907334e6885e0e9bbea0bae36d00d4d9b4ed873f2ca8906316f6db8190620010679086908690600401620044d6565b608060405180830381865af415801562001085573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620010ab9190620044ec565b604051636fda2c7960e01b81529091507334e6885e0e9bbea0bae36d00d4d9b4ed873f2ca890636fda2c7990620010e790849060040162004572565b602060405180830381865af415801562001105573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200112b919062004598565b620011495760405163145a1fdd60e31b815260040160405180910390fd5b60655460675460405163282d3fdf60e01b815233600482015260248101919091526001600160a01b039091169063282d3fdf90604401600060405180830381600087803b1580156200119a57600080fd5b505af1158015620011af573d6000803e3d6000fd5b5050336000818152606d6020526040902080546001600160a01b031916909117815591505060018101620011e58486836200463c565b5060028101805460ff19166001908117909155336000818152606e60209081526040808320859055606f909152808220939093556077549251629bf68360e11b81526071600482015260248101929092526044820192909252819073cd97ed85f6eddc535a4f55a4c67c2e02800c2e6790630137ed0690606401600060405180830381865af41580156200127d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052620012a791908101906200470a565b9150915060005b8151811015620012e657620012d1828281518110620008fd57620008fd620043db565b80620012dd8162004407565b915050620012ae565b50336001600160a01b03167fd4ec586f4f9f417f99e20fe821fbaa10a10a4b95f8712a0c57c6d8ed970e98bd87878560405162001326939291906200474b565b60405180910390a2505050505050565b6066546001600160a01b03163314620013625760405163469666c560e01b815260040160405180910390fd5b60005b8351811015620014a15782606e6000868481518110620013895762001389620043db565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020016000206000828254620013c2919062004423565b9250508190555081606f6000868481518110620013e357620013e3620043db565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060008282546200141c919062004423565b92505081905550838181518110620014385762001438620043db565b60200260200101516001600160a01b03167f8353a804115421789f3ab2eeb3f5215943906ce12100c91d40fc865caf742b6f848460405162001484929190918252602082015260400190565b60405180910390a280620014988162004407565b91505062001365565b50505050565b336000818152606d60205260409020805490916001600160a01b0390911614620014e3576040516229eaad60e31b815260040160405180910390fd5b600281015460ff16156200150a576040516324a228bb60e21b815260040160405180910390fd5b4381600301541115620015395780600301546040516363525acb60e11b81526004016200052391815260200190565b60655460405163929ec53760e01b81523360048201526000916001600160a01b03169063929ec53790602401602060405180830381865afa15801562001583573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620015a9919062004262565b6067549091508110156200163f576065546067546001600160a01b039091169063282d3fdf903390620015de90859062004439565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401600060405180830381600087803b1580156200162557600080fd5b505af11580156200163a573d6000803e3d6000fd5b505050505b60028201805460ff19166001179055607754604051629bf68360e11b8152607160048201523360248201526044810191909152600090819073cd97ed85f6eddc535a4f55a4c67c2e02800c2e6790630137ed0690606401600060405180830381865af4158015620016b4573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052620016de91908101906200470a565b9150915060005b81518110156200171d5762001708828281518110620008fd57620008fd620043db565b80620017148162004407565b915050620016e5565b5060405182815233907ffc97cd9154b40031874ef09a9436a4b60052e4dcf40f21b1258be265fac4a397906020016200098b565b62001788604051806080016040528060006001600160a01b0316815260200160608152602001600015158152602001600081525090565b6001600160a01b038083166000908152606d60209081526040918290208251608081019093528054909316825260018301805492939291840191620017cd90620045b6565b80601f0160208091040260200160405190810160405280929190818152602001828054620017fb90620045b6565b80156200184c5780601f1062001820576101008083540402835291602001916200184c565b820191906000526020600020905b8154815290600101906020018083116200182e57829003601f168201915b5050509183525050600282015460ff161515602082015260039091015460409091015292915050565b604051631c2da66560e31b81526071600482015260609073cd97ed85f6eddc535a4f55a4c67c2e02800c2e679063e16d332890602401600060405180830381865af4158015620018c9573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052620018f3919081019062004474565b905090565b6000828152607360209081526040808320815161012081018352815481526001820154818501526002820154818401526003820154606082015260048201805484518187028101870190955280855286959294608086019390929190879084015b82821015620019d55760008481526020908190206040805180820182526005860290920180546001600160a01b0316835281516080810190925291928301906001830160048282826020028201915b815481526020019060010190808311620019a8575050505050815250508152602001906001019062001959565b5050505081526020016005820180548060200260200160405190810160405280929190818152602001828054801562001a3857602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831162001a19575b5050505050815260200160068201805480602002602001604051908101604052809291908181526020016000905b8282101562001bb657838290600052602060002090600702016040518060400160405290816000820180548060200260200160405190810160405280929190818152602001828054801562001ae557602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831162001ac6575b50505091835250506040805160608101825260018401805482528251608081019384905260209485019492939192840191600287019060049082845b81548152602001906001019080831162001b2157505050505081526020016005820180548060200260200160405190810160405280929190818152602001828054801562001b9957602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831162001b7a575b505050505081525050815250508152602001906001019062001a66565b50505090825250600782015460ff1615156020820152604080516080810182529101906008830160048282826020028201915b81548152602001906001019080831162001be957505050505081525050905060005b81608001515181101562001cb957836001600160a01b03168260800151828151811062001c3c5762001c3c620043db565b6020026020010151600001516001600160a01b03160362001ca4578160800151818151811062001c705762001c70620043db565b60200260200101516020015160006004811062001c915762001c91620043db565b6020020151600014159250505062000cf0565b8062001cb08162004407565b91505062001c0b565b506000949350505050565b600054610100900460ff161580801562001ce55750600054600160ff909116105b8062001d015750303b15801562001d01575060005460ff166001145b62001d755760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a6564000000000000000000000000000000000000606482015260840162000523565b6000805460ff19166001179055801562001d99576000805461ff0019166101001790555b606c80546001600160a01b0319166001600160a01b038516179055607782905562001dc362003469565b801562000e21576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a1505050565b62001e18620038d9565b60008281526073602090815260408083208151610120810183528154815260018201548185015260028201548184015260038201546060820152600482018054845181870281018701909552808552919592946080870194939192919084015b8282101562001ef45760008481526020908190206040805180820182526005860290920180546001600160a01b0316835281516080810190925291928301906001830160048282826020028201915b81548152602001906001019080831162001ec7575050505050815250508152602001906001019062001e78565b5050505081526020016005820180548060200260200160405190810160405280929190818152602001828054801562001f5757602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831162001f38575b5050505050815260200160068201805480602002602001604051908101604052809291908181526020016000905b82821015620020d55783829060005260206000209060070201604051806040016040529081600082018054806020026020016040519081016040528092919081815260200182805480156200200457602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831162001fe5575b50505091835250506040805160608101825260018401805482528251608081019384905260209485019492939192840191600287019060049082845b81548152602001906001019080831162002040575050505050815260200160058201805480602002602001604051908101604052809291908181526020018280548015620020b857602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831162002099575b505050505081525050815250508152602001906001019062001f85565b50505090825250600782015460ff1615156020820152604080516080810182529101906008830160048282826020028201915b81548152602001906001019080831162002108575050505050815250509050919050565b336000818152606d60205260409020805490916001600160a01b039091161462002168576040516229eaad60e31b815260040160405180910390fd5b600281015460ff16156200218f576040516324a228bb60e21b815260040160405180910390fd5b6040516316f6db8160e01b81526000907334e6885e0e9bbea0bae36d00d4d9b4ed873f2ca8906316f6db8190620021cd9087908790600401620044d6565b608060405180830381865af4158015620021eb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620022119190620044ec565b604051636fda2c7960e01b81529091507334e6885e0e9bbea0bae36d00d4d9b4ed873f2ca890636fda2c79906200224d90849060040162004572565b602060405180830381865af41580156200226b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062002291919062004598565b620022af5760405163145a1fdd60e31b815260040160405180910390fd5b60018201620022c08486836200463c565b50336001600160a01b03167f4a327ac4843af7a9586b5a2a2c312bd17289ae1d70da32855ed539fe39f86a5085856040516200098b929190620044d6565b60725481511062002329578051604051637f6efcb560e11b8152600481019190915260240162000523565b80516000908152607060205260409020546001600160a01b031662002368578051604051635291bbcf60e01b8152600481019190915260240162000523565b805160009081526070602090815260409182902054825163221f951160e01b815292516001600160a01b0390911692839263221f9511926004808401938290030181865afa158015620023bf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620023e591906200427c565b60000b196200240e5781516040516343609fe160e01b8152600481019190915260240162000523565b81516000908152607360209081526040909120600181015491840151909114620024695782516020840151600183015460405163048b63c360e11b815260048101939093526024830191909152604482015260640162000523565b82516040516358914d0360e01b815260716004820152602481019190915233604482015273cd97ed85f6eddc535a4f55a4c67c2e02800c2e67906358914d0390606401602060405180830381865af4158015620024ca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620024f0919062004262565b196200251c57825160405163eb51f5f960e01b8152600481019190915233602482015260440162000523565b82516200252a9033620018f8565b156200255657825160405163173ca10960e31b8152600481019190915233602482015260440162000523565b60608301516040516316f6db8160e01b81526000917334e6885e0e9bbea0bae36d00d4d9b4ed873f2ca8916316f6db8191620025959160040162004771565b608060405180830381865af4158015620025b3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620025d99190620044ec565b604051636fda2c7960e01b81529091507334e6885e0e9bbea0bae36d00d4d9b4ed873f2ca890636fda2c79906200261590849060040162004572565b602060405180830381865af415801562002633573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062002659919062004598565b6200267757604051631886185760e01b815260040160405180910390fd5b60408085015190516316f6db8160e01b81526000917334e6885e0e9bbea0bae36d00d4d9b4ed873f2ca8916316f6db8191620026b69160040162004771565b608060405180830381865af4158015620026d4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620026fa9190620044ec565b604051636fda2c7960e01b81529091507334e6885e0e9bbea0bae36d00d4d9b4ed873f2ca890636fda2c79906200273690849060040162004572565b602060405180830381865af415801562002754573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200277a919062004598565b620027985760405163145a1fdd60e31b815260040160405180910390fd5b604080516060810182526020808801518252810183905260808701518183015286519151636aba6eeb60e11b8152909173cd97ed85f6eddc535a4f55a4c67c2e02800c2e679163d574ddd691620027f89160719190869060040162004786565b602060405180830381865af415801562002816573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200283c919062004598565b6200292357604080516001818301818152608083019093526000928291606083016020803683375050508152602001839052805180519192503391600090620028895762002889620043db565b6001600160a01b03909216602092830291909101820152600686018054600181018255600091825290829020835180518594600790940290920192620028d59284929091019062003929565b5060208281015180516001840190815591810151909190620028fe906002850190600462003993565b50604082015180516200291c91600584019160209091019062003929565b5050505050505b85516040516358914d0360e01b815260716004808301919091526024820192909252336044820152849186019073cd97ed85f6eddc535a4f55a4c67c2e02800c2e67906358914d0390606401602060405180830381865af41580156200298d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620029b3919062004262565b81548110620029c657620029c6620043db565b9060005260206000209060050201600101906004620029e792919062003993565b50600784015460ff1662002ad257855160775460405163449cf2fd60e11b81526071600482015260248101929092526044820152600090819073cd97ed85f6eddc535a4f55a4c67c2e02800c2e6790638939e5fa90606401600060405180830381865af415801562002a5d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405262002a87919081019062004811565b91509150811562002acf5760005b815181101562002acd5762002ab8828281518110620008ab57620008ab620043db565b8062002ac48162004407565b91505062002a95565b505b50505b505050505050565b62002ae4620032ba565b6001600160a01b03811662002b4b5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840162000523565b62002b56816200337f565b50565b6066546001600160a01b0316331462002b855760405163469666c560e01b815260040160405180910390fd5b607755565b606554604051638899fdeb60e01b81526001600160a01b0385811660048301526024820185905290911690638899fdeb90604401600060405180830381600087803b15801562002bd957600080fd5b505af115801562002bee573d6000803e3d6000fd5b5050505062002bfe8382620033d1565b60408051838152602081018390526001600160a01b038516917fa8d720d0a0a2e7c96bf9eb87433901ebb6331356c8f3283b2568de34478703cc910160405180910390a2505050565b62002c54607182620034e0565b60008181526073602090815260408083208151610120810183528154815260018201548185015260028201548184015260038201546060820152600482018054845181870281018701909552808552919492936080860193909290879084015b8282101562002d305760008481526020908190206040805180820182526005860290920180546001600160a01b0316835281516080810190925291928301906001830160048282826020028201915b81548152602001906001019080831162002d03575050505050815250508152602001906001019062002cb4565b5050505081526020016005820180548060200260200160405190810160405280929190818152602001828054801562002d9357602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831162002d74575b5050505050815260200160068201805480602002602001604051908101604052809291908181526020016000905b8282101562002f1157838290600052602060002090600702016040518060400160405290816000820180548060200260200160405190810160405280929190818152602001828054801562002e4057602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831162002e21575b50505091835250506040805160608101825260018401805482528251608081019384905260209485019492939192840191600287019060049082845b81548152602001906001019080831162002e7c57505050505081526020016005820180548060200260200160405190810160405280929190818152602001828054801562002ef457602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831162002ed5575b505050505081525050815250508152602001906001019062002dc1565b50505090825250600782015460ff1615156020820152604080516080810182529101906008830160048282826020028201915b81548152602001906001019080831162002f445750505050508152505090506000816060015160656004015460405162002f7e90620039c4565b9182526020820152604001604051809103906000f08015801562002fa6573d6000803e3d6000fd5b5060008481526070602052604080822080546001600160a01b0319166001600160a01b0385161790558401519192509067ffffffffffffffff81111562002ff15762002ff162003c6d565b6040519080825280602002602001820160405280156200301b578160200160208202803683370190505b5090506000836040015167ffffffffffffffff81111562003040576200304062003c6d565b6040519080825280602002602001820160405280156200307557816020015b60608152602001906001900390816200305f5790505b50905060005b8460400151811015620031f55784608001518181518110620030a157620030a1620043db565b602002602001015160000151838281518110620030c257620030c2620043db565b60200260200101906001600160a01b031690816001600160a01b031681525050606d600086608001518381518110620030ff57620030ff620043db565b6020026020010151600001516001600160a01b03166001600160a01b0316815260200190815260200160002060010180546200313b90620045b6565b80601f01602080910402602001604051908101604052809291908181526020018280546200316990620045b6565b8015620031ba5780601f106200318e57610100808354040283529160200191620031ba565b820191906000526020600020905b8154815290600101906020018083116200319c57829003601f168201915b5050505050828281518110620031d457620031d4620043db565b60200260200101819052508080620031ec9062004407565b9150506200307b565b506040516337f8d5ff60e01b81526001600160a01b038416906337f8d5ff906200322690859085906004016200485b565b600060405180830381600087803b1580156200324157600080fd5b505af115801562003256573d6000803e3d6000fd5b50505050836020015184600001516071600001547fbbd25d64683f157b2e3544d3d6430e14102db1e49592cf4dcaf827e2ded517ee8760400151886060015187438a604051620032ab959493929190620048d3565b60405180910390a45050505050565b6033546001600160a01b0316331462000e3c5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640162000523565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1663a9059cbb60e01b17905262000e21908490620035bb565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6001600160a01b0382166000908152606d6020526040902060028101805460ff191690556003015443908110156200343c576001600160a01b0383166000908152606d6020526040812060030180548492906200343090849062004423565b9091555062000e219050565b62003448828262004423565b6001600160a01b0384166000908152606d6020526040902060030155505050565b600054610100900460ff16620034d65760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b606482015260840162000523565b62000e3c62003694565b8154826000620034f08362004407565b9091555050600081815260028301602052604081206001810180549192620035188362004407565b909155505060078101805460ff1916905562003539600582016000620039d2565b62003549600682016000620039f2565b60005b6004820154811015620014a157816004018181548110620035715762003571620043db565b90600052602060002090600502016001016000620035a691905060008155600101600081556001016000815560010160009055565b80620035b28162004407565b9150506200354c565b600062003612826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166200370c9092919063ffffffff16565b80519091501562000e21578080602001905181019062003633919062004598565b62000e215760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840162000523565b600054610100900460ff16620037015760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b606482015260840162000523565b62000e3c336200337f565b60606200371d848460008562003725565b949350505050565b606082471015620037885760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840162000523565b600080866001600160a01b03168587604051620037a6919062004915565b60006040518083038185875af1925050503d8060008114620037e5576040519150601f19603f3d011682016040523d82523d6000602084013e620037ea565b606091505b5091509150620037fd8783838762003808565b979650505050505050565b606083156200387c57825160000362003874576001600160a01b0385163b620038745760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640162000523565b50816200371d565b6200371d8383815115620038935781518083602001fd5b8060405162461bcd60e51b815260040162000523919062004771565b604051806040016040528060006001600160a01b03168152602001620038d462003a15565b905290565b60405180610120016040528060008152602001600081526020016000815260200160008152602001606081526020016060815260200160608152602001600015158152602001620038d462003a15565b82805482825590600052602060002090810192821562003981579160200282015b828111156200398157825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906200394a565b506200398f92915062003a33565b5090565b826004810192821562003981579160200282015b8281111562003981578251825591602001919060010190620039a7565b61168d806200493483390190565b508054600082559060005260206000209081019062002b56919062003a33565b508054600082556007029060005260206000209081019062002b56919062003a4a565b60405180608001604052806004906020820280368337509192915050565b5b808211156200398f576000815560010162003a34565b808211156200398f57600062003a618282620039d2565b600060018301818155600284018290556003840182905560048401829055600584018290559062003a97600583016000620039d2565b50505060070162003a4a565b6000806040838503121562003ab757600080fd5b50508035926020909101359150565b6001600160a01b038116811462002b5657600080fd5b60006020828403121562003aef57600080fd5b813562003afc8162003ac6565b9392505050565b6000806000806000806000806000806101408b8d03121562003b2457600080fd5b8a3562003b318162003ac6565b995060208b013562003b438162003ac6565b999c999b505050506040880135976060810135976080820135975060a0820135965060c0820135955060e082013594506101008201359350610120909101359150565b60006020828403121562003b9957600080fd5b5035919050565b8060005b6004811015620014a157815184526020938401939091019060010162003ba4565b6001600160a01b038151168252602081015162000e21602084018262003ba0565b60a0810162000cf0828462003bc5565b6000806020838503121562003c0a57600080fd5b823567ffffffffffffffff8082111562003c2357600080fd5b818501915085601f83011262003c3857600080fd5b81358181111562003c4857600080fd5b86602082850101111562003c5b57600080fd5b60209290920196919550909350505050565b634e487b7160e01b600052604160045260246000fd5b60405160a0810167ffffffffffffffff8111828210171562003ca95762003ca962003c6d565b60405290565b604051601f8201601f1916810167ffffffffffffffff8111828210171562003cdb5762003cdb62003c6d565b604052919050565b600067ffffffffffffffff82111562003d005762003d0062003c6d565b5060051b60200190565b600082601f83011262003d1c57600080fd5b8135602062003d3562003d2f8362003ce3565b62003caf565b82815260059290921b8401810191818101908684111562003d5557600080fd5b8286015b8481101562003d7d57803562003d6f8162003ac6565b835291830191830162003d59565b509695505050505050565b60008060006060848603121562003d9e57600080fd5b833567ffffffffffffffff81111562003db657600080fd5b62003dc48682870162003d0a565b9660208601359650604090950135949350505050565b60005b8381101562003df757818101518382015260200162003ddd565b50506000910152565b6000815180845262003e1a81602086016020860162003dda565b601f01601f19169290920160200192915050565b602081526001600160a01b038251166020820152600060208301516080604084015262003e5f60a084018262003e00565b9050604084015115156060840152606084015160808401528091505092915050565b6020808252825182820181905260009190848201906040850190845b8181101562003ebb5783518352928401929184019160010162003e9d565b50909695505050505050565b6000806040838503121562003edb57600080fd5b82359150602083013562003eef8162003ac6565b809150509250929050565b6000806040838503121562003f0e57600080fd5b823562003f1b8162003ac6565b946020939093013593505050565b600081518084526020808501945080840160005b8381101562003f675762003f5387835162003bc5565b60a096909601959082019060010162003f3d565b509495945050505050565b600081518084526020808501945080840160005b8381101562003f675781516001600160a01b03168752958201959082019060010162003f86565b600081518084526020808501808196508360051b8101915082860160005b858110156200404957828403895281516040815181875262003ff08288018262003f72565b90508783015192508681038888015260c08351825288840151620040178a84018262003ba0565b508284015193508060a0830152620040328183018562003f72565b9c89019c9750505092860192505060010162003fcb565b5091979650505050505050565b60208152815160208201526020820151604082015260408201516060820152606082015160808201526000608083015161018060a08401526200409e6101a084018262003f29565b905060a0840151601f19808584030160c0860152620040be838362003f72565b925060c08601519150808584030160e086015250620040de828262003fad565b91505060e0840151610100620040f78186018315159052565b85015190506200410c61012085018262003ba0565b509392505050565b600082601f8301126200412657600080fd5b813567ffffffffffffffff81111562004143576200414362003c6d565b62004158601f8201601f191660200162003caf565b8181528460208386010111156200416e57600080fd5b816020850160208301376000918101602001919091529392505050565b6000602082840312156200419e57600080fd5b813567ffffffffffffffff80821115620041b757600080fd5b9083019060a08286031215620041cc57600080fd5b620041d662003c83565b8235815260208301356020820152604083013582811115620041f757600080fd5b620042058782860162004114565b6040830152506060830135828111156200421e57600080fd5b6200422c8782860162004114565b6060830152506080830135828111156200424557600080fd5b620042538782860162003d0a565b60808301525095945050505050565b6000602082840312156200427557600080fd5b5051919050565b6000602082840312156200428f57600080fd5b81518060000b811462003afc57600080fd5b600082601f830112620042b357600080fd5b81516020620042c662003d2f8362003ce3565b82815260059290921b84018101918181019086841115620042e657600080fd5b8286015b8481101562003d7d578051620043008162003ac6565b8352918301918301620042ea565b600082601f8301126200432057600080fd5b815160206200433362003d2f8362003ce3565b82815260059290921b840181019181810190868411156200435357600080fd5b8286015b8481101562003d7d578051835291830191830162004357565b600080604083850312156200438457600080fd5b825167ffffffffffffffff808211156200439d57600080fd5b620043ab86838701620042a1565b93506020850151915080821115620043c257600080fd5b50620043d1858286016200430e565b9150509250929050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000600182016200441c576200441c620043f1565b5060010190565b8082018082111562000cf05762000cf0620043f1565b8181038181111562000cf05762000cf0620043f1565b600080604083850312156200446357600080fd5b505080516020909101519092909150565b6000602082840312156200448757600080fd5b815167ffffffffffffffff8111156200449f57600080fd5b6200371d848285016200430e565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6020815260006200371d602083018486620044ad565b600060808284031215620044ff57600080fd5b82601f8301126200450f57600080fd5b6040516080810181811067ffffffffffffffff8211171562004535576200453562003c6d565b6040528060808401858111156200454b57600080fd5b845b81811015620045675780518352602092830192016200454d565b509195945050505050565b6080810162000cf0828462003ba0565b805180151581146200459357600080fd5b919050565b600060208284031215620045ab57600080fd5b62003afc8262004582565b600181811c90821680620045cb57607f821691505b602082108103620045ec57634e487b7160e01b600052602260045260246000fd5b50919050565b601f82111562000e2157600081815260208120601f850160051c810160208610156200461b5750805b601f850160051c820191505b8181101562002ad25782815560010162004627565b67ffffffffffffffff83111562004657576200465762003c6d565b6200466f83620046688354620045b6565b83620045f2565b6000601f841160018114620046a657600085156200468d5750838201355b600019600387901b1c1916600186901b17835562004703565b600083815260209020601f19861690835b82811015620046d95786850135825560209485019460019092019101620046b7565b5086821015620046f75760001960f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b600080604083850312156200471e57600080fd5b82519150602083015167ffffffffffffffff8111156200473d57600080fd5b620043d1858286016200430e565b60408152600062004761604083018587620044ad565b9050826020830152949350505050565b60208152600062003afc602083018462003e00565b8381526000602084818401526060604084015261012083018451606085015281850151620047b8608086018262003ba0565b50604085015160c06101008601528051918290528201906000906101408601905b80831015620048045783516001600160a01b03168252928401926001929092019190840190620047d9565b5098975050505050505050565b600080604083850312156200482557600080fd5b620048308362004582565b9150602083015167ffffffffffffffff8111156200484d57600080fd5b620043d185828601620042a1565b60408152600062004870604083018562003f72565b6020838203818501528185518084528284019150828160051b85010183880160005b83811015620048c457601f19878403018552620048b183835162003e00565b9486019492509085019060010162004892565b50909998505050505050505050565b85815284602082015260a060408201526000620048f460a083018662003f72565b90508360608301526001600160a01b03831660808301529695505050505050565b600082516200492981846020870162003dda565b919091019291505056fe60c0604052600060065534801561001557600080fd5b5060405161168d38038061168d8339810160408190526100349161009b565b61003d3361004b565b60a0919091526080526100bf565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600080604083850312156100ae57600080fd5b505080516020909101519092909150565b60805160a05161157161011c6000396000818161027f0152610775015260008181610243015281816103aa015281816103dc015281816104150152818161044e015281816108a80152818161094b01526109ff01526115716000f3fe608060405234801561001057600080fd5b506004361061012c5760003560e01c80638da5cb5b116100ad578063cc5ef00911610071578063cc5ef009146102a1578063cd5e3837146102a9578063ce7c2ac2146102bc578063d73fe0aa146102cf578063f2fde38b146102d757600080fd5b80638da5cb5b146102255780639cb8a26a14610236578063ac5553ce1461023e578063b0ef817914610265578063c27040241461027a57600080fd5b80634e3874a0116100f45780634e3874a0146101cc5780635aa68ac0146101e2578063670d14b2146101f7578063715018a61461020a5780637fd283461461021257600080fd5b80630ea6564814610131578063221f95111461015a57806335c1d3491461017557806337f8d5ff146101a057806348cd4cb1146101b5575b600080fd5b61014461013f366004611081565b6102ea565b60405161015191906110f7565b60405180910390f35b610162610384565b60405160009190910b8152602001610151565b61018861018336600461110a565b61048b565b6040516001600160a01b039091168152602001610151565b6101b36101ae36600461116f565b6104b5565b005b6101be60065481565b604051908152602001610151565b6101d4610617565b604051610151929190611233565b6101ea61079c565b6040516101519190611254565b610144610205366004611081565b6107fe565b6101b3610817565b6101b36102203660046112a1565b61082b565b6000546001600160a01b0316610188565b6101b3610afb565b6101be7f000000000000000000000000000000000000000000000000000000000000000081565b61026d610b11565b6040516101519190611313565b6101be7f000000000000000000000000000000000000000000000000000000000000000081565b61026d610c6f565b6101446102b7366004611081565b610dc7565b6101446102ca366004611081565b610de0565b61026d610df9565b6101b36102e5366004611081565b610f51565b6003602052600090815260409020805461030390611326565b80601f016020809104026020016040519081016040528092919081815260200182805461032f90611326565b801561037c5780601f106103515761010080835404028352916020019161037c565b820191906000526020600020905b81548152906001019060200180831161035f57829003601f168201915b505050505081565b60006006546000036103965750600090565b6000600654436103a69190611370565b90507f000000000000000000000000000000000000000000000000000000000000000081116103d757600191505090565b6104027f00000000000000000000000000000000000000000000000000000000000000006002611389565b811161041057600291505090565b61043b7f00000000000000000000000000000000000000000000000000000000000000006003611389565b811161044957600391505090565b6104747f00000000000000000000000000000000000000000000000000000000000000006004611389565b811161048257600491505090565b60001991505090565b6005818154811061049b57600080fd5b6000918252602090912001546001600160a01b0316905081565b6006541561050a5760405162461bcd60e51b815260206004820152601760248201527f444b472068617320616c7265616479207374617274656400000000000000000060448201526064015b60405180910390fd5b610512610fca565b60005b8381101561060c576005858583818110610531576105316113a0565b90506020020160208101906105469190611081565b815460018101835560009283526020909220909101805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03909216919091179055828282818110610597576105976113a0565b90506020028101906105a991906113b6565b600160008888868181106105bf576105bf6113a0565b90506020020160208101906105d49190611081565b6001600160a01b031681526020810191909152604001600020916105f9919083611461565b508061060481611522565b915050610515565b505043600655505050565b60006060600060058054905067ffffffffffffffff81111561063b5761063b6113fd565b60405190808252806020026020018201604052801561066e57816020015b60608152602001906001900390816106595790505b50905060005b600554811015610772576001600060058381548110610695576106956113a0565b60009182526020808320909101546001600160a01b03168352820192909252604001902080546106c490611326565b80601f01602080910402602001604051908101604052809291908181526020018280546106f090611326565b801561073d5780601f106107125761010080835404028352916020019161073d565b820191906000526020600020905b81548152906001019060200180831161072057829003601f168201915b5050505050828281518110610754576107546113a0565b6020026020010181905250808061076a90611522565b915050610674565b507f0000000000000000000000000000000000000000000000000000000000000000939092509050565b606060058054806020026020016040519081016040528092919081815260200182805480156107f457602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116107d6575b5050505050905090565b6001602052600090815260409020805461030390611326565b61081f610fca565b6108296000611024565b565b336000908152600160205260408120805461084590611326565b9050116108945760405162461bcd60e51b815260206004820152601b60248201527f796f7520617265206e6f7420612067726f7570206d656d6265722100000000006044820152606401610501565b6000600654436108a49190611370565b90507f000000000000000000000000000000000000000000000000000000000000000081116109465733600090815260026020526040902080546108e790611326565b1590506109265760405162461bcd60e51b815260206004820152600d60248201526c1cda185c9948195e1a5cdd1959609a1b6044820152606401610501565b336000908152600260205260409020610940838583611461565b50505050565b6109717f00000000000000000000000000000000000000000000000000000000000000006002611389565b81116109fa57336000908152600360205260409020805461099190611326565b1590506109e05760405162461bcd60e51b815260206004820152601060248201527f726573706f6e73652065786973746564000000000000000000000000000000006044820152606401610501565b336000908152600360205260409020610940838583611461565b610a257f00000000000000000000000000000000000000000000000000000000000000006003611389565b8111610aae573360009081526004602052604090208054610a4590611326565b159050610a945760405162461bcd60e51b815260206004820152601560248201527f6a757374696669636174696f6e206578697374656400000000000000000000006044820152606401610501565b336000908152600460205260409020610940838583611461565b60405162461bcd60e51b815260206004820152601560248201527f444b47205075626c6973682068617320656e64656400000000000000000000006044820152606401610501565b505050565b610b03610fca565b6000546001600160a01b0316ff5b60055460609060009067ffffffffffffffff811115610b3257610b326113fd565b604051908082528060200260200182016040528015610b6557816020015b6060815260200190600190039081610b505790505b50905060005b600554811015610c69576004600060058381548110610b8c57610b8c6113a0565b60009182526020808320909101546001600160a01b0316835282019290925260400190208054610bbb90611326565b80601f0160208091040260200160405190810160405280929190818152602001828054610be790611326565b8015610c345780601f10610c0957610100808354040283529160200191610c34565b820191906000526020600020905b815481529060010190602001808311610c1757829003601f168201915b5050505050828281518110610c4b57610c4b6113a0565b60200260200101819052508080610c6190611522565b915050610b6b565b50919050565b60055460609060009067ffffffffffffffff811115610c9057610c906113fd565b604051908082528060200260200182016040528015610cc357816020015b6060815260200190600190039081610cae5790505b50905060005b600554811015610c69576003600060058381548110610cea57610cea6113a0565b60009182526020808320909101546001600160a01b0316835282019290925260400190208054610d1990611326565b80601f0160208091040260200160405190810160405280929190818152602001828054610d4590611326565b8015610d925780601f10610d6757610100808354040283529160200191610d92565b820191906000526020600020905b815481529060010190602001808311610d7557829003601f168201915b5050505050828281518110610da957610da96113a0565b60200260200101819052508080610dbf90611522565b915050610cc9565b6004602052600090815260409020805461030390611326565b6002602052600090815260409020805461030390611326565b60055460609060009067ffffffffffffffff811115610e1a57610e1a6113fd565b604051908082528060200260200182016040528015610e4d57816020015b6060815260200190600190039081610e385790505b50905060005b600554811015610c69576002600060058381548110610e7457610e746113a0565b60009182526020808320909101546001600160a01b0316835282019290925260400190208054610ea390611326565b80601f0160208091040260200160405190810160405280929190818152602001828054610ecf90611326565b8015610f1c5780601f10610ef157610100808354040283529160200191610f1c565b820191906000526020600020905b815481529060010190602001808311610eff57829003601f168201915b5050505050828281518110610f3357610f336113a0565b60200260200101819052508080610f4990611522565b915050610e53565b610f59610fca565b6001600160a01b038116610fbe5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610501565b610fc781611024565b50565b6000546001600160a01b031633146108295760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610501565b600080546001600160a01b0383811673ffffffffffffffffffffffffffffffffffffffff19831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60006020828403121561109357600080fd5b81356001600160a01b03811681146110aa57600080fd5b9392505050565b6000815180845260005b818110156110d7576020818501810151868301820152016110bb565b506000602082860101526020601f19601f83011685010191505092915050565b6020815260006110aa60208301846110b1565b60006020828403121561111c57600080fd5b5035919050565b60008083601f84011261113557600080fd5b50813567ffffffffffffffff81111561114d57600080fd5b6020830191508360208260051b850101111561116857600080fd5b9250929050565b6000806000806040858703121561118557600080fd5b843567ffffffffffffffff8082111561119d57600080fd5b6111a988838901611123565b909650945060208701359150808211156111c257600080fd5b506111cf87828801611123565b95989497509550505050565b600082825180855260208086019550808260051b84010181860160005b8481101561122657601f198684030189526112148383516110b1565b988401989250908301906001016111f8565b5090979650505050505050565b82815260406020820152600061124c60408301846111db565b949350505050565b6020808252825182820181905260009190848201906040850190845b818110156112955783516001600160a01b031683529284019291840191600101611270565b50909695505050505050565b600080602083850312156112b457600080fd5b823567ffffffffffffffff808211156112cc57600080fd5b818501915085601f8301126112e057600080fd5b8135818111156112ef57600080fd5b86602082850101111561130157600080fd5b60209290920196919550909350505050565b6020815260006110aa60208301846111db565b600181811c9082168061133a57607f821691505b602082108103610c6957634e487b7160e01b600052602260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b818103818111156113835761138361135a565b92915050565b80820281158282048414176113835761138361135a565b634e487b7160e01b600052603260045260246000fd5b6000808335601e198436030181126113cd57600080fd5b83018035915067ffffffffffffffff8211156113e857600080fd5b60200191503681900382131561116857600080fd5b634e487b7160e01b600052604160045260246000fd5b601f821115610af657600081815260208120601f850160051c8101602086101561143a5750805b601f850160051c820191505b8181101561145957828155600101611446565b505050505050565b67ffffffffffffffff831115611479576114796113fd565b61148d836114878354611326565b83611413565b6000601f8411600181146114c157600085156114a95750838201355b600019600387901b1c1916600186901b17835561151b565b600083815260209020601f19861690835b828110156114f257868501358255602094850194600190920191016114d2565b508682101561150f5760001960f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b6000600182016115345761153461135a565b506001019056fea2646970667358221220f3e6e3e93788ae67c1eaf31cb805370313ba096ed5aa792e2b15c335a3903e5a64736f6c63430008120033a2646970667358221220452028a72bf515ef364f752d379d36e460edada7991f7fdb8d560ed8e00d58f964736f6c63430008120033
Deployed Bytecode
0x60806040523480156200001157600080fd5b5060043610620001dd5760003560e01c80638da5cb5b116200010d578063ceb6065411620000a3578063e37eb96c116200007a578063e37eb96c146200048e578063f2fde38b14620004a5578063f3df080214620004bc578063f49e0ba914620004d357600080fd5b8063ceb6065414620003dd578063d11b8e681462000403578063e275cde6146200047757600080fd5b80639d20904811620000e45780639d209048146200035f578063b330a0fd1462000385578063c2db900b146200039e578063cd6dc68714620003c657600080fd5b80638da5cb5b146200032c578063914eb34d146200033e5780639a075bc3146200035557600080fd5b80634d79a8931162000183578063715018a6116200015a578063715018a614620002f85780637a2af56e14620003025780637ee49cfd146200030c57806380110e4e146200031557600080fd5b80634d79a89314620002b25780634ecea80d14620002d857806351a2b9a014620002ef57600080fd5b80632ff9e52011620001b85780632ff9e520146200023f5780633b6c00b0146200025657806342424d6f146200026d57600080fd5b806306545a9314620001e25780630bf9c5c614620001f9578063227d0f461462000212575b600080fd5b6072545b6040519081526020015b60405180910390f35b620002106200020a36600462003aa3565b62000501565b005b620002296200022336600462003adc565b62000999565b60408051928352602083019190915201620001f0565b620002106200025036600462003b03565b62000a42565b620002296200026736600462003adc565b62000bcf565b620002996200027e36600462003b86565b6000908152607060205260409020546001600160a01b031690565b6040516001600160a01b039091168152602001620001f0565b620002c9620002c336600462003aa3565b62000c59565b604051620001f0919062003be6565b62000210620002e936600462003adc565b62000cf6565b607754620001e6565b6200021062000e26565b6200021062000e3e565b607154620001e6565b620002106200032636600462003bf6565b62000ff1565b6033546001600160a01b031662000299565b620002106200034f36600462003d88565b62001336565b62000210620014a7565b620003766200037036600462003adc565b62001751565b604051620001f0919062003e2e565b6200038f62001875565b604051620001f0919062003e81565b620003b5620003af36600462003ec7565b620018f8565b6040519015158152602001620001f0565b62000210620003d736600462003efa565b62001cc4565b620003f4620003ee36600462003b86565b62001e0e565b604051620001f0919062004056565b606554606654606754606854607654606954607554607454606a54606b54604080516001600160a01b039b8c1681529a90991660208b0152978901969096526060880194909452608087019290925260a086015260c085015260e084015261010083015261012082015261014001620001f0565b620002106200048836600462003bf6565b6200212c565b620002106200049f3660046200418b565b620022fe565b62000210620004b636600462003adc565b62002ada565b62000210620004cd36600462003b86565b62002b59565b62000229620004e436600462003b86565b600090815260736020526040902060038101546002909101549091565b60725482106200052c57604051637f6efcb560e11b8152600481018390526024015b60405180910390fd5b6040516358914d0360e01b8152607160048201526024810183905233604482015273cd97ed85f6eddc535a4f55a4c67c2e02800c2e67906358914d0390606401602060405180830381865af41580156200058a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620005b0919062004262565b19620005d95760405163eb51f5f960e01b81526004810183905233602482015260440162000523565b6000828152607360205260409020600181015482146200062457600181015460405163048b63c360e11b81526004810185905260248101849052604481019190915260640162000523565b6000838152607060205260409020546001600160a01b03166200065e57604051635291bbcf60e01b81526004810184905260240162000523565b60008381526070602090815260409182902054825163221f951160e01b815292516001600160a01b0390911692839263221f9511926004808401938290030181865afa158015620006b3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620006d991906200427c565b60000b60001914620007715783816001600160a01b031663221f95116040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000725573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200074b91906200427c565b60405163f7c06f9160e01b8152600481019290925260000b602482015260440162000523565b806001600160a01b0316639cb8a26a6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015620007ad57600080fd5b505af1158015620007c2573d6000803e3d6000fd5b505050600085815260706020526040902080546001600160a01b031916905550600782015460ff166200092457607754604051630295316d60e51b815260716004820152602481018690526044810191909152600090819073cd97ed85f6eddc535a4f55a4c67c2e02800c2e67906352a62da090606401600060405180830381865af415801562000857573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405262000881919081019062004370565b9150915060005b8251811015620008d657620008c1838281518110620008ab57620008ab620043db565b6020026020010151606560030154600062002b8a565b80620008cd8162004407565b91505062000888565b5060005b815181101562000920576200090b828281518110620008fd57620008fd620043db565b602002602001015162002c47565b80620009178162004407565b915050620008da565b5050505b606b54336000908152606f6020526040812080549091906200094890849062004423565b9091555050606b5460405133917f8353a804115421789f3ab2eeb3f5215943906ce12100c91d40fc865caf742b6f916200098b9160008252602082015260400190565b60405180910390a250505050565b6001600160a01b0381166000908152606e6020526040812054819015620009e7576001600160a01b0383166000908152606e6020526040902054620009e19060019062004439565b620009ea565b60005b6001600160a01b0384166000908152606f60205260409020541562000a36576001600160a01b0384166000908152606f602052604090205462000a309060019062004439565b62000a39565b60005b91509150915091565b62000a4c620032ba565b6040805160e0810182526001600160a01b038c8116808352908c16602083018190528284018c9052606083018b90526080830189905260a0830186905260c0909201849052606580546001600160a01b03199081169092179055606680549091169091179055606789905560688890556069869055606a839055606b829055516301a79f6360e71b81526071600482015260248101849052604481018590526064810187905273cd97ed85f6eddc535a4f55a4c67c2e02800c2e679063d3cfb1809060840160006040518083038186803b15801562000b2a57600080fd5b505af415801562000b3f573d6000803e3d6000fd5b5050604080516001600160a01b03808f1682528d1660208201529081018b9052606081018a90526080810189905260a0810188905260c0810187905260e08101869052610100810185905261012081018490527f3202ca2a288846b65f27bc3e13c1e38aaf2e4356b80b963d67aea8a822645e1f925061014001905060405180910390a150505050505050505050565b60405163787c576760e01b8152607160048201526001600160a01b0382166024820152600090819073cd97ed85f6eddc535a4f55a4c67c2e02800c2e679063787c5767906044016040805180830381865af415801562000c33573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000a3991906200444f565b62000c63620038af565b600083815260736020526040902060040180548390811062000c895762000c89620043db565b6000918252602091829020604080518082018252600590930290910180546001600160a01b0316835281516080810190925291928301906001830160048282826020028201915b81548152602001906001019080831162000cd05750505050508152505090505b92915050565b6001600160a01b03811662000d1e5760405163f6b2911f60e01b815260040160405180910390fd5b336000908152606e6020908152604080832054606f90925290912054600181111562000d8057336000908152606f6020526040902060019081905562000d8090849062000d6c908462004439565b606c546001600160a01b0316919062003316565b600182111562000e2157336000908152606e602052604090206001908190556066546001600160a01b031690630ad98f6a90859062000dc0908662004439565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401600060405180830381600087803b15801562000e0757600080fd5b505af115801562000e1c573d6000803e3d6000fd5b505050505b505050565b62000e30620032ba565b62000e3c60006200337f565b565b336000818152606d60205260409020805490916001600160a01b039091161462000e7a576040516229eaad60e31b815260040160405180910390fd5b60775460405163a6ae8a8160e01b815260716004820152336024820152604481019190915260009073cd97ed85f6eddc535a4f55a4c67c2e02800c2e679063a6ae8a8190606401600060405180830381865af415801562000edf573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405262000f09919081019062004474565b905060005b815181101562000f465762000f31828281518110620008fd57620008fd620043db565b8062000f3d8162004407565b91505062000f0e565b5062000f5833606560050154620033d1565b606554606754604051637eee288d60e01b815233600482015260248101919091526001600160a01b0390911690637eee288d90604401600060405180830381600087803b15801562000fa957600080fd5b505af115801562000fbe573d6000803e3d6000fd5b50506040513392507f68577adbb6b0647e21353ff032be5797d9fa0879ce7e05fe617e40368441f97d9150600090a25050565b336000908152606d60205260409020546001600160a01b0316156200102957604051630eb0d31360e11b815260040160405180910390fd5b6040516316f6db8160e01b81526000907334e6885e0e9bbea0bae36d00d4d9b4ed873f2ca8906316f6db8190620010679086908690600401620044d6565b608060405180830381865af415801562001085573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620010ab9190620044ec565b604051636fda2c7960e01b81529091507334e6885e0e9bbea0bae36d00d4d9b4ed873f2ca890636fda2c7990620010e790849060040162004572565b602060405180830381865af415801562001105573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200112b919062004598565b620011495760405163145a1fdd60e31b815260040160405180910390fd5b60655460675460405163282d3fdf60e01b815233600482015260248101919091526001600160a01b039091169063282d3fdf90604401600060405180830381600087803b1580156200119a57600080fd5b505af1158015620011af573d6000803e3d6000fd5b5050336000818152606d6020526040902080546001600160a01b031916909117815591505060018101620011e58486836200463c565b5060028101805460ff19166001908117909155336000818152606e60209081526040808320859055606f909152808220939093556077549251629bf68360e11b81526071600482015260248101929092526044820192909252819073cd97ed85f6eddc535a4f55a4c67c2e02800c2e6790630137ed0690606401600060405180830381865af41580156200127d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052620012a791908101906200470a565b9150915060005b8151811015620012e657620012d1828281518110620008fd57620008fd620043db565b80620012dd8162004407565b915050620012ae565b50336001600160a01b03167fd4ec586f4f9f417f99e20fe821fbaa10a10a4b95f8712a0c57c6d8ed970e98bd87878560405162001326939291906200474b565b60405180910390a2505050505050565b6066546001600160a01b03163314620013625760405163469666c560e01b815260040160405180910390fd5b60005b8351811015620014a15782606e6000868481518110620013895762001389620043db565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020016000206000828254620013c2919062004423565b9250508190555081606f6000868481518110620013e357620013e3620043db565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060008282546200141c919062004423565b92505081905550838181518110620014385762001438620043db565b60200260200101516001600160a01b03167f8353a804115421789f3ab2eeb3f5215943906ce12100c91d40fc865caf742b6f848460405162001484929190918252602082015260400190565b60405180910390a280620014988162004407565b91505062001365565b50505050565b336000818152606d60205260409020805490916001600160a01b0390911614620014e3576040516229eaad60e31b815260040160405180910390fd5b600281015460ff16156200150a576040516324a228bb60e21b815260040160405180910390fd5b4381600301541115620015395780600301546040516363525acb60e11b81526004016200052391815260200190565b60655460405163929ec53760e01b81523360048201526000916001600160a01b03169063929ec53790602401602060405180830381865afa15801562001583573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620015a9919062004262565b6067549091508110156200163f576065546067546001600160a01b039091169063282d3fdf903390620015de90859062004439565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401600060405180830381600087803b1580156200162557600080fd5b505af11580156200163a573d6000803e3d6000fd5b505050505b60028201805460ff19166001179055607754604051629bf68360e11b8152607160048201523360248201526044810191909152600090819073cd97ed85f6eddc535a4f55a4c67c2e02800c2e6790630137ed0690606401600060405180830381865af4158015620016b4573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052620016de91908101906200470a565b9150915060005b81518110156200171d5762001708828281518110620008fd57620008fd620043db565b80620017148162004407565b915050620016e5565b5060405182815233907ffc97cd9154b40031874ef09a9436a4b60052e4dcf40f21b1258be265fac4a397906020016200098b565b62001788604051806080016040528060006001600160a01b0316815260200160608152602001600015158152602001600081525090565b6001600160a01b038083166000908152606d60209081526040918290208251608081019093528054909316825260018301805492939291840191620017cd90620045b6565b80601f0160208091040260200160405190810160405280929190818152602001828054620017fb90620045b6565b80156200184c5780601f1062001820576101008083540402835291602001916200184c565b820191906000526020600020905b8154815290600101906020018083116200182e57829003601f168201915b5050509183525050600282015460ff161515602082015260039091015460409091015292915050565b604051631c2da66560e31b81526071600482015260609073cd97ed85f6eddc535a4f55a4c67c2e02800c2e679063e16d332890602401600060405180830381865af4158015620018c9573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052620018f3919081019062004474565b905090565b6000828152607360209081526040808320815161012081018352815481526001820154818501526002820154818401526003820154606082015260048201805484518187028101870190955280855286959294608086019390929190879084015b82821015620019d55760008481526020908190206040805180820182526005860290920180546001600160a01b0316835281516080810190925291928301906001830160048282826020028201915b815481526020019060010190808311620019a8575050505050815250508152602001906001019062001959565b5050505081526020016005820180548060200260200160405190810160405280929190818152602001828054801562001a3857602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831162001a19575b5050505050815260200160068201805480602002602001604051908101604052809291908181526020016000905b8282101562001bb657838290600052602060002090600702016040518060400160405290816000820180548060200260200160405190810160405280929190818152602001828054801562001ae557602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831162001ac6575b50505091835250506040805160608101825260018401805482528251608081019384905260209485019492939192840191600287019060049082845b81548152602001906001019080831162001b2157505050505081526020016005820180548060200260200160405190810160405280929190818152602001828054801562001b9957602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831162001b7a575b505050505081525050815250508152602001906001019062001a66565b50505090825250600782015460ff1615156020820152604080516080810182529101906008830160048282826020028201915b81548152602001906001019080831162001be957505050505081525050905060005b81608001515181101562001cb957836001600160a01b03168260800151828151811062001c3c5762001c3c620043db565b6020026020010151600001516001600160a01b03160362001ca4578160800151818151811062001c705762001c70620043db565b60200260200101516020015160006004811062001c915762001c91620043db565b6020020151600014159250505062000cf0565b8062001cb08162004407565b91505062001c0b565b506000949350505050565b600054610100900460ff161580801562001ce55750600054600160ff909116105b8062001d015750303b15801562001d01575060005460ff166001145b62001d755760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a6564000000000000000000000000000000000000606482015260840162000523565b6000805460ff19166001179055801562001d99576000805461ff0019166101001790555b606c80546001600160a01b0319166001600160a01b038516179055607782905562001dc362003469565b801562000e21576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a1505050565b62001e18620038d9565b60008281526073602090815260408083208151610120810183528154815260018201548185015260028201548184015260038201546060820152600482018054845181870281018701909552808552919592946080870194939192919084015b8282101562001ef45760008481526020908190206040805180820182526005860290920180546001600160a01b0316835281516080810190925291928301906001830160048282826020028201915b81548152602001906001019080831162001ec7575050505050815250508152602001906001019062001e78565b5050505081526020016005820180548060200260200160405190810160405280929190818152602001828054801562001f5757602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831162001f38575b5050505050815260200160068201805480602002602001604051908101604052809291908181526020016000905b82821015620020d55783829060005260206000209060070201604051806040016040529081600082018054806020026020016040519081016040528092919081815260200182805480156200200457602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831162001fe5575b50505091835250506040805160608101825260018401805482528251608081019384905260209485019492939192840191600287019060049082845b81548152602001906001019080831162002040575050505050815260200160058201805480602002602001604051908101604052809291908181526020018280548015620020b857602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831162002099575b505050505081525050815250508152602001906001019062001f85565b50505090825250600782015460ff1615156020820152604080516080810182529101906008830160048282826020028201915b81548152602001906001019080831162002108575050505050815250509050919050565b336000818152606d60205260409020805490916001600160a01b039091161462002168576040516229eaad60e31b815260040160405180910390fd5b600281015460ff16156200218f576040516324a228bb60e21b815260040160405180910390fd5b6040516316f6db8160e01b81526000907334e6885e0e9bbea0bae36d00d4d9b4ed873f2ca8906316f6db8190620021cd9087908790600401620044d6565b608060405180830381865af4158015620021eb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620022119190620044ec565b604051636fda2c7960e01b81529091507334e6885e0e9bbea0bae36d00d4d9b4ed873f2ca890636fda2c79906200224d90849060040162004572565b602060405180830381865af41580156200226b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062002291919062004598565b620022af5760405163145a1fdd60e31b815260040160405180910390fd5b60018201620022c08486836200463c565b50336001600160a01b03167f4a327ac4843af7a9586b5a2a2c312bd17289ae1d70da32855ed539fe39f86a5085856040516200098b929190620044d6565b60725481511062002329578051604051637f6efcb560e11b8152600481019190915260240162000523565b80516000908152607060205260409020546001600160a01b031662002368578051604051635291bbcf60e01b8152600481019190915260240162000523565b805160009081526070602090815260409182902054825163221f951160e01b815292516001600160a01b0390911692839263221f9511926004808401938290030181865afa158015620023bf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620023e591906200427c565b60000b196200240e5781516040516343609fe160e01b8152600481019190915260240162000523565b81516000908152607360209081526040909120600181015491840151909114620024695782516020840151600183015460405163048b63c360e11b815260048101939093526024830191909152604482015260640162000523565b82516040516358914d0360e01b815260716004820152602481019190915233604482015273cd97ed85f6eddc535a4f55a4c67c2e02800c2e67906358914d0390606401602060405180830381865af4158015620024ca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620024f0919062004262565b196200251c57825160405163eb51f5f960e01b8152600481019190915233602482015260440162000523565b82516200252a9033620018f8565b156200255657825160405163173ca10960e31b8152600481019190915233602482015260440162000523565b60608301516040516316f6db8160e01b81526000917334e6885e0e9bbea0bae36d00d4d9b4ed873f2ca8916316f6db8191620025959160040162004771565b608060405180830381865af4158015620025b3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620025d99190620044ec565b604051636fda2c7960e01b81529091507334e6885e0e9bbea0bae36d00d4d9b4ed873f2ca890636fda2c79906200261590849060040162004572565b602060405180830381865af415801562002633573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062002659919062004598565b6200267757604051631886185760e01b815260040160405180910390fd5b60408085015190516316f6db8160e01b81526000917334e6885e0e9bbea0bae36d00d4d9b4ed873f2ca8916316f6db8191620026b69160040162004771565b608060405180830381865af4158015620026d4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620026fa9190620044ec565b604051636fda2c7960e01b81529091507334e6885e0e9bbea0bae36d00d4d9b4ed873f2ca890636fda2c79906200273690849060040162004572565b602060405180830381865af415801562002754573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200277a919062004598565b620027985760405163145a1fdd60e31b815260040160405180910390fd5b604080516060810182526020808801518252810183905260808701518183015286519151636aba6eeb60e11b8152909173cd97ed85f6eddc535a4f55a4c67c2e02800c2e679163d574ddd691620027f89160719190869060040162004786565b602060405180830381865af415801562002816573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200283c919062004598565b6200292357604080516001818301818152608083019093526000928291606083016020803683375050508152602001839052805180519192503391600090620028895762002889620043db565b6001600160a01b03909216602092830291909101820152600686018054600181018255600091825290829020835180518594600790940290920192620028d59284929091019062003929565b5060208281015180516001840190815591810151909190620028fe906002850190600462003993565b50604082015180516200291c91600584019160209091019062003929565b5050505050505b85516040516358914d0360e01b815260716004808301919091526024820192909252336044820152849186019073cd97ed85f6eddc535a4f55a4c67c2e02800c2e67906358914d0390606401602060405180830381865af41580156200298d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620029b3919062004262565b81548110620029c657620029c6620043db565b9060005260206000209060050201600101906004620029e792919062003993565b50600784015460ff1662002ad257855160775460405163449cf2fd60e11b81526071600482015260248101929092526044820152600090819073cd97ed85f6eddc535a4f55a4c67c2e02800c2e6790638939e5fa90606401600060405180830381865af415801562002a5d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405262002a87919081019062004811565b91509150811562002acf5760005b815181101562002acd5762002ab8828281518110620008ab57620008ab620043db565b8062002ac48162004407565b91505062002a95565b505b50505b505050505050565b62002ae4620032ba565b6001600160a01b03811662002b4b5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840162000523565b62002b56816200337f565b50565b6066546001600160a01b0316331462002b855760405163469666c560e01b815260040160405180910390fd5b607755565b606554604051638899fdeb60e01b81526001600160a01b0385811660048301526024820185905290911690638899fdeb90604401600060405180830381600087803b15801562002bd957600080fd5b505af115801562002bee573d6000803e3d6000fd5b5050505062002bfe8382620033d1565b60408051838152602081018390526001600160a01b038516917fa8d720d0a0a2e7c96bf9eb87433901ebb6331356c8f3283b2568de34478703cc910160405180910390a2505050565b62002c54607182620034e0565b60008181526073602090815260408083208151610120810183528154815260018201548185015260028201548184015260038201546060820152600482018054845181870281018701909552808552919492936080860193909290879084015b8282101562002d305760008481526020908190206040805180820182526005860290920180546001600160a01b0316835281516080810190925291928301906001830160048282826020028201915b81548152602001906001019080831162002d03575050505050815250508152602001906001019062002cb4565b5050505081526020016005820180548060200260200160405190810160405280929190818152602001828054801562002d9357602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831162002d74575b5050505050815260200160068201805480602002602001604051908101604052809291908181526020016000905b8282101562002f1157838290600052602060002090600702016040518060400160405290816000820180548060200260200160405190810160405280929190818152602001828054801562002e4057602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831162002e21575b50505091835250506040805160608101825260018401805482528251608081019384905260209485019492939192840191600287019060049082845b81548152602001906001019080831162002e7c57505050505081526020016005820180548060200260200160405190810160405280929190818152602001828054801562002ef457602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831162002ed5575b505050505081525050815250508152602001906001019062002dc1565b50505090825250600782015460ff1615156020820152604080516080810182529101906008830160048282826020028201915b81548152602001906001019080831162002f445750505050508152505090506000816060015160656004015460405162002f7e90620039c4565b9182526020820152604001604051809103906000f08015801562002fa6573d6000803e3d6000fd5b5060008481526070602052604080822080546001600160a01b0319166001600160a01b0385161790558401519192509067ffffffffffffffff81111562002ff15762002ff162003c6d565b6040519080825280602002602001820160405280156200301b578160200160208202803683370190505b5090506000836040015167ffffffffffffffff81111562003040576200304062003c6d565b6040519080825280602002602001820160405280156200307557816020015b60608152602001906001900390816200305f5790505b50905060005b8460400151811015620031f55784608001518181518110620030a157620030a1620043db565b602002602001015160000151838281518110620030c257620030c2620043db565b60200260200101906001600160a01b031690816001600160a01b031681525050606d600086608001518381518110620030ff57620030ff620043db565b6020026020010151600001516001600160a01b03166001600160a01b0316815260200190815260200160002060010180546200313b90620045b6565b80601f01602080910402602001604051908101604052809291908181526020018280546200316990620045b6565b8015620031ba5780601f106200318e57610100808354040283529160200191620031ba565b820191906000526020600020905b8154815290600101906020018083116200319c57829003601f168201915b5050505050828281518110620031d457620031d4620043db565b60200260200101819052508080620031ec9062004407565b9150506200307b565b506040516337f8d5ff60e01b81526001600160a01b038416906337f8d5ff906200322690859085906004016200485b565b600060405180830381600087803b1580156200324157600080fd5b505af115801562003256573d6000803e3d6000fd5b50505050836020015184600001516071600001547fbbd25d64683f157b2e3544d3d6430e14102db1e49592cf4dcaf827e2ded517ee8760400151886060015187438a604051620032ab959493929190620048d3565b60405180910390a45050505050565b6033546001600160a01b0316331462000e3c5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640162000523565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1663a9059cbb60e01b17905262000e21908490620035bb565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6001600160a01b0382166000908152606d6020526040902060028101805460ff191690556003015443908110156200343c576001600160a01b0383166000908152606d6020526040812060030180548492906200343090849062004423565b9091555062000e219050565b62003448828262004423565b6001600160a01b0384166000908152606d6020526040902060030155505050565b600054610100900460ff16620034d65760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b606482015260840162000523565b62000e3c62003694565b8154826000620034f08362004407565b9091555050600081815260028301602052604081206001810180549192620035188362004407565b909155505060078101805460ff1916905562003539600582016000620039d2565b62003549600682016000620039f2565b60005b6004820154811015620014a157816004018181548110620035715762003571620043db565b90600052602060002090600502016001016000620035a691905060008155600101600081556001016000815560010160009055565b80620035b28162004407565b9150506200354c565b600062003612826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166200370c9092919063ffffffff16565b80519091501562000e21578080602001905181019062003633919062004598565b62000e215760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840162000523565b600054610100900460ff16620037015760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b606482015260840162000523565b62000e3c336200337f565b60606200371d848460008562003725565b949350505050565b606082471015620037885760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840162000523565b600080866001600160a01b03168587604051620037a6919062004915565b60006040518083038185875af1925050503d8060008114620037e5576040519150601f19603f3d011682016040523d82523d6000602084013e620037ea565b606091505b5091509150620037fd8783838762003808565b979650505050505050565b606083156200387c57825160000362003874576001600160a01b0385163b620038745760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640162000523565b50816200371d565b6200371d8383815115620038935781518083602001fd5b8060405162461bcd60e51b815260040162000523919062004771565b604051806040016040528060006001600160a01b03168152602001620038d462003a15565b905290565b60405180610120016040528060008152602001600081526020016000815260200160008152602001606081526020016060815260200160608152602001600015158152602001620038d462003a15565b82805482825590600052602060002090810192821562003981579160200282015b828111156200398157825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906200394a565b506200398f92915062003a33565b5090565b826004810192821562003981579160200282015b8281111562003981578251825591602001919060010190620039a7565b61168d806200493483390190565b508054600082559060005260206000209081019062002b56919062003a33565b508054600082556007029060005260206000209081019062002b56919062003a4a565b60405180608001604052806004906020820280368337509192915050565b5b808211156200398f576000815560010162003a34565b808211156200398f57600062003a618282620039d2565b600060018301818155600284018290556003840182905560048401829055600584018290559062003a97600583016000620039d2565b50505060070162003a4a565b6000806040838503121562003ab757600080fd5b50508035926020909101359150565b6001600160a01b038116811462002b5657600080fd5b60006020828403121562003aef57600080fd5b813562003afc8162003ac6565b9392505050565b6000806000806000806000806000806101408b8d03121562003b2457600080fd5b8a3562003b318162003ac6565b995060208b013562003b438162003ac6565b999c999b505050506040880135976060810135976080820135975060a0820135965060c0820135955060e082013594506101008201359350610120909101359150565b60006020828403121562003b9957600080fd5b5035919050565b8060005b6004811015620014a157815184526020938401939091019060010162003ba4565b6001600160a01b038151168252602081015162000e21602084018262003ba0565b60a0810162000cf0828462003bc5565b6000806020838503121562003c0a57600080fd5b823567ffffffffffffffff8082111562003c2357600080fd5b818501915085601f83011262003c3857600080fd5b81358181111562003c4857600080fd5b86602082850101111562003c5b57600080fd5b60209290920196919550909350505050565b634e487b7160e01b600052604160045260246000fd5b60405160a0810167ffffffffffffffff8111828210171562003ca95762003ca962003c6d565b60405290565b604051601f8201601f1916810167ffffffffffffffff8111828210171562003cdb5762003cdb62003c6d565b604052919050565b600067ffffffffffffffff82111562003d005762003d0062003c6d565b5060051b60200190565b600082601f83011262003d1c57600080fd5b8135602062003d3562003d2f8362003ce3565b62003caf565b82815260059290921b8401810191818101908684111562003d5557600080fd5b8286015b8481101562003d7d57803562003d6f8162003ac6565b835291830191830162003d59565b509695505050505050565b60008060006060848603121562003d9e57600080fd5b833567ffffffffffffffff81111562003db657600080fd5b62003dc48682870162003d0a565b9660208601359650604090950135949350505050565b60005b8381101562003df757818101518382015260200162003ddd565b50506000910152565b6000815180845262003e1a81602086016020860162003dda565b601f01601f19169290920160200192915050565b602081526001600160a01b038251166020820152600060208301516080604084015262003e5f60a084018262003e00565b9050604084015115156060840152606084015160808401528091505092915050565b6020808252825182820181905260009190848201906040850190845b8181101562003ebb5783518352928401929184019160010162003e9d565b50909695505050505050565b6000806040838503121562003edb57600080fd5b82359150602083013562003eef8162003ac6565b809150509250929050565b6000806040838503121562003f0e57600080fd5b823562003f1b8162003ac6565b946020939093013593505050565b600081518084526020808501945080840160005b8381101562003f675762003f5387835162003bc5565b60a096909601959082019060010162003f3d565b509495945050505050565b600081518084526020808501945080840160005b8381101562003f675781516001600160a01b03168752958201959082019060010162003f86565b600081518084526020808501808196508360051b8101915082860160005b858110156200404957828403895281516040815181875262003ff08288018262003f72565b90508783015192508681038888015260c08351825288840151620040178a84018262003ba0565b508284015193508060a0830152620040328183018562003f72565b9c89019c9750505092860192505060010162003fcb565b5091979650505050505050565b60208152815160208201526020820151604082015260408201516060820152606082015160808201526000608083015161018060a08401526200409e6101a084018262003f29565b905060a0840151601f19808584030160c0860152620040be838362003f72565b925060c08601519150808584030160e086015250620040de828262003fad565b91505060e0840151610100620040f78186018315159052565b85015190506200410c61012085018262003ba0565b509392505050565b600082601f8301126200412657600080fd5b813567ffffffffffffffff81111562004143576200414362003c6d565b62004158601f8201601f191660200162003caf565b8181528460208386010111156200416e57600080fd5b816020850160208301376000918101602001919091529392505050565b6000602082840312156200419e57600080fd5b813567ffffffffffffffff80821115620041b757600080fd5b9083019060a08286031215620041cc57600080fd5b620041d662003c83565b8235815260208301356020820152604083013582811115620041f757600080fd5b620042058782860162004114565b6040830152506060830135828111156200421e57600080fd5b6200422c8782860162004114565b6060830152506080830135828111156200424557600080fd5b620042538782860162003d0a565b60808301525095945050505050565b6000602082840312156200427557600080fd5b5051919050565b6000602082840312156200428f57600080fd5b81518060000b811462003afc57600080fd5b600082601f830112620042b357600080fd5b81516020620042c662003d2f8362003ce3565b82815260059290921b84018101918181019086841115620042e657600080fd5b8286015b8481101562003d7d578051620043008162003ac6565b8352918301918301620042ea565b600082601f8301126200432057600080fd5b815160206200433362003d2f8362003ce3565b82815260059290921b840181019181810190868411156200435357600080fd5b8286015b8481101562003d7d578051835291830191830162004357565b600080604083850312156200438457600080fd5b825167ffffffffffffffff808211156200439d57600080fd5b620043ab86838701620042a1565b93506020850151915080821115620043c257600080fd5b50620043d1858286016200430e565b9150509250929050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000600182016200441c576200441c620043f1565b5060010190565b8082018082111562000cf05762000cf0620043f1565b8181038181111562000cf05762000cf0620043f1565b600080604083850312156200446357600080fd5b505080516020909101519092909150565b6000602082840312156200448757600080fd5b815167ffffffffffffffff8111156200449f57600080fd5b6200371d848285016200430e565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6020815260006200371d602083018486620044ad565b600060808284031215620044ff57600080fd5b82601f8301126200450f57600080fd5b6040516080810181811067ffffffffffffffff8211171562004535576200453562003c6d565b6040528060808401858111156200454b57600080fd5b845b81811015620045675780518352602092830192016200454d565b509195945050505050565b6080810162000cf0828462003ba0565b805180151581146200459357600080fd5b919050565b600060208284031215620045ab57600080fd5b62003afc8262004582565b600181811c90821680620045cb57607f821691505b602082108103620045ec57634e487b7160e01b600052602260045260246000fd5b50919050565b601f82111562000e2157600081815260208120601f850160051c810160208610156200461b5750805b601f850160051c820191505b8181101562002ad25782815560010162004627565b67ffffffffffffffff83111562004657576200465762003c6d565b6200466f83620046688354620045b6565b83620045f2565b6000601f841160018114620046a657600085156200468d5750838201355b600019600387901b1c1916600186901b17835562004703565b600083815260209020601f19861690835b82811015620046d95786850135825560209485019460019092019101620046b7565b5086821015620046f75760001960f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b600080604083850312156200471e57600080fd5b82519150602083015167ffffffffffffffff8111156200473d57600080fd5b620043d1858286016200430e565b60408152600062004761604083018587620044ad565b9050826020830152949350505050565b60208152600062003afc602083018462003e00565b8381526000602084818401526060604084015261012083018451606085015281850151620047b8608086018262003ba0565b50604085015160c06101008601528051918290528201906000906101408601905b80831015620048045783516001600160a01b03168252928401926001929092019190840190620047d9565b5098975050505050505050565b600080604083850312156200482557600080fd5b620048308362004582565b9150602083015167ffffffffffffffff8111156200484d57600080fd5b620043d185828601620042a1565b60408152600062004870604083018562003f72565b6020838203818501528185518084528284019150828160051b85010183880160005b83811015620048c457601f19878403018552620048b183835162003e00565b9486019492509085019060010162004892565b50909998505050505050505050565b85815284602082015260a060408201526000620048f460a083018662003f72565b90508360608301526001600160a01b03831660808301529695505050505050565b600082516200492981846020870162003dda565b919091019291505056fe60c0604052600060065534801561001557600080fd5b5060405161168d38038061168d8339810160408190526100349161009b565b61003d3361004b565b60a0919091526080526100bf565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600080604083850312156100ae57600080fd5b505080516020909101519092909150565b60805160a05161157161011c6000396000818161027f0152610775015260008181610243015281816103aa015281816103dc015281816104150152818161044e015281816108a80152818161094b01526109ff01526115716000f3fe608060405234801561001057600080fd5b506004361061012c5760003560e01c80638da5cb5b116100ad578063cc5ef00911610071578063cc5ef009146102a1578063cd5e3837146102a9578063ce7c2ac2146102bc578063d73fe0aa146102cf578063f2fde38b146102d757600080fd5b80638da5cb5b146102255780639cb8a26a14610236578063ac5553ce1461023e578063b0ef817914610265578063c27040241461027a57600080fd5b80634e3874a0116100f45780634e3874a0146101cc5780635aa68ac0146101e2578063670d14b2146101f7578063715018a61461020a5780637fd283461461021257600080fd5b80630ea6564814610131578063221f95111461015a57806335c1d3491461017557806337f8d5ff146101a057806348cd4cb1146101b5575b600080fd5b61014461013f366004611081565b6102ea565b60405161015191906110f7565b60405180910390f35b610162610384565b60405160009190910b8152602001610151565b61018861018336600461110a565b61048b565b6040516001600160a01b039091168152602001610151565b6101b36101ae36600461116f565b6104b5565b005b6101be60065481565b604051908152602001610151565b6101d4610617565b604051610151929190611233565b6101ea61079c565b6040516101519190611254565b610144610205366004611081565b6107fe565b6101b3610817565b6101b36102203660046112a1565b61082b565b6000546001600160a01b0316610188565b6101b3610afb565b6101be7f000000000000000000000000000000000000000000000000000000000000000081565b61026d610b11565b6040516101519190611313565b6101be7f000000000000000000000000000000000000000000000000000000000000000081565b61026d610c6f565b6101446102b7366004611081565b610dc7565b6101446102ca366004611081565b610de0565b61026d610df9565b6101b36102e5366004611081565b610f51565b6003602052600090815260409020805461030390611326565b80601f016020809104026020016040519081016040528092919081815260200182805461032f90611326565b801561037c5780601f106103515761010080835404028352916020019161037c565b820191906000526020600020905b81548152906001019060200180831161035f57829003601f168201915b505050505081565b60006006546000036103965750600090565b6000600654436103a69190611370565b90507f000000000000000000000000000000000000000000000000000000000000000081116103d757600191505090565b6104027f00000000000000000000000000000000000000000000000000000000000000006002611389565b811161041057600291505090565b61043b7f00000000000000000000000000000000000000000000000000000000000000006003611389565b811161044957600391505090565b6104747f00000000000000000000000000000000000000000000000000000000000000006004611389565b811161048257600491505090565b60001991505090565b6005818154811061049b57600080fd5b6000918252602090912001546001600160a01b0316905081565b6006541561050a5760405162461bcd60e51b815260206004820152601760248201527f444b472068617320616c7265616479207374617274656400000000000000000060448201526064015b60405180910390fd5b610512610fca565b60005b8381101561060c576005858583818110610531576105316113a0565b90506020020160208101906105469190611081565b815460018101835560009283526020909220909101805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03909216919091179055828282818110610597576105976113a0565b90506020028101906105a991906113b6565b600160008888868181106105bf576105bf6113a0565b90506020020160208101906105d49190611081565b6001600160a01b031681526020810191909152604001600020916105f9919083611461565b508061060481611522565b915050610515565b505043600655505050565b60006060600060058054905067ffffffffffffffff81111561063b5761063b6113fd565b60405190808252806020026020018201604052801561066e57816020015b60608152602001906001900390816106595790505b50905060005b600554811015610772576001600060058381548110610695576106956113a0565b60009182526020808320909101546001600160a01b03168352820192909252604001902080546106c490611326565b80601f01602080910402602001604051908101604052809291908181526020018280546106f090611326565b801561073d5780601f106107125761010080835404028352916020019161073d565b820191906000526020600020905b81548152906001019060200180831161072057829003601f168201915b5050505050828281518110610754576107546113a0565b6020026020010181905250808061076a90611522565b915050610674565b507f0000000000000000000000000000000000000000000000000000000000000000939092509050565b606060058054806020026020016040519081016040528092919081815260200182805480156107f457602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116107d6575b5050505050905090565b6001602052600090815260409020805461030390611326565b61081f610fca565b6108296000611024565b565b336000908152600160205260408120805461084590611326565b9050116108945760405162461bcd60e51b815260206004820152601b60248201527f796f7520617265206e6f7420612067726f7570206d656d6265722100000000006044820152606401610501565b6000600654436108a49190611370565b90507f000000000000000000000000000000000000000000000000000000000000000081116109465733600090815260026020526040902080546108e790611326565b1590506109265760405162461bcd60e51b815260206004820152600d60248201526c1cda185c9948195e1a5cdd1959609a1b6044820152606401610501565b336000908152600260205260409020610940838583611461565b50505050565b6109717f00000000000000000000000000000000000000000000000000000000000000006002611389565b81116109fa57336000908152600360205260409020805461099190611326565b1590506109e05760405162461bcd60e51b815260206004820152601060248201527f726573706f6e73652065786973746564000000000000000000000000000000006044820152606401610501565b336000908152600360205260409020610940838583611461565b610a257f00000000000000000000000000000000000000000000000000000000000000006003611389565b8111610aae573360009081526004602052604090208054610a4590611326565b159050610a945760405162461bcd60e51b815260206004820152601560248201527f6a757374696669636174696f6e206578697374656400000000000000000000006044820152606401610501565b336000908152600460205260409020610940838583611461565b60405162461bcd60e51b815260206004820152601560248201527f444b47205075626c6973682068617320656e64656400000000000000000000006044820152606401610501565b505050565b610b03610fca565b6000546001600160a01b0316ff5b60055460609060009067ffffffffffffffff811115610b3257610b326113fd565b604051908082528060200260200182016040528015610b6557816020015b6060815260200190600190039081610b505790505b50905060005b600554811015610c69576004600060058381548110610b8c57610b8c6113a0565b60009182526020808320909101546001600160a01b0316835282019290925260400190208054610bbb90611326565b80601f0160208091040260200160405190810160405280929190818152602001828054610be790611326565b8015610c345780601f10610c0957610100808354040283529160200191610c34565b820191906000526020600020905b815481529060010190602001808311610c1757829003601f168201915b5050505050828281518110610c4b57610c4b6113a0565b60200260200101819052508080610c6190611522565b915050610b6b565b50919050565b60055460609060009067ffffffffffffffff811115610c9057610c906113fd565b604051908082528060200260200182016040528015610cc357816020015b6060815260200190600190039081610cae5790505b50905060005b600554811015610c69576003600060058381548110610cea57610cea6113a0565b60009182526020808320909101546001600160a01b0316835282019290925260400190208054610d1990611326565b80601f0160208091040260200160405190810160405280929190818152602001828054610d4590611326565b8015610d925780601f10610d6757610100808354040283529160200191610d92565b820191906000526020600020905b815481529060010190602001808311610d7557829003601f168201915b5050505050828281518110610da957610da96113a0565b60200260200101819052508080610dbf90611522565b915050610cc9565b6004602052600090815260409020805461030390611326565b6002602052600090815260409020805461030390611326565b60055460609060009067ffffffffffffffff811115610e1a57610e1a6113fd565b604051908082528060200260200182016040528015610e4d57816020015b6060815260200190600190039081610e385790505b50905060005b600554811015610c69576002600060058381548110610e7457610e746113a0565b60009182526020808320909101546001600160a01b0316835282019290925260400190208054610ea390611326565b80601f0160208091040260200160405190810160405280929190818152602001828054610ecf90611326565b8015610f1c5780601f10610ef157610100808354040283529160200191610f1c565b820191906000526020600020905b815481529060010190602001808311610eff57829003601f168201915b5050505050828281518110610f3357610f336113a0565b60200260200101819052508080610f4990611522565b915050610e53565b610f59610fca565b6001600160a01b038116610fbe5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610501565b610fc781611024565b50565b6000546001600160a01b031633146108295760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610501565b600080546001600160a01b0383811673ffffffffffffffffffffffffffffffffffffffff19831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60006020828403121561109357600080fd5b81356001600160a01b03811681146110aa57600080fd5b9392505050565b6000815180845260005b818110156110d7576020818501810151868301820152016110bb565b506000602082860101526020601f19601f83011685010191505092915050565b6020815260006110aa60208301846110b1565b60006020828403121561111c57600080fd5b5035919050565b60008083601f84011261113557600080fd5b50813567ffffffffffffffff81111561114d57600080fd5b6020830191508360208260051b850101111561116857600080fd5b9250929050565b6000806000806040858703121561118557600080fd5b843567ffffffffffffffff8082111561119d57600080fd5b6111a988838901611123565b909650945060208701359150808211156111c257600080fd5b506111cf87828801611123565b95989497509550505050565b600082825180855260208086019550808260051b84010181860160005b8481101561122657601f198684030189526112148383516110b1565b988401989250908301906001016111f8565b5090979650505050505050565b82815260406020820152600061124c60408301846111db565b949350505050565b6020808252825182820181905260009190848201906040850190845b818110156112955783516001600160a01b031683529284019291840191600101611270565b50909695505050505050565b600080602083850312156112b457600080fd5b823567ffffffffffffffff808211156112cc57600080fd5b818501915085601f8301126112e057600080fd5b8135818111156112ef57600080fd5b86602082850101111561130157600080fd5b60209290920196919550909350505050565b6020815260006110aa60208301846111db565b600181811c9082168061133a57607f821691505b602082108103610c6957634e487b7160e01b600052602260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b818103818111156113835761138361135a565b92915050565b80820281158282048414176113835761138361135a565b634e487b7160e01b600052603260045260246000fd5b6000808335601e198436030181126113cd57600080fd5b83018035915067ffffffffffffffff8211156113e857600080fd5b60200191503681900382131561116857600080fd5b634e487b7160e01b600052604160045260246000fd5b601f821115610af657600081815260208120601f850160051c8101602086101561143a5750805b601f850160051c820191505b8181101561145957828155600101611446565b505050505050565b67ffffffffffffffff831115611479576114796113fd565b61148d836114878354611326565b83611413565b6000601f8411600181146114c157600085156114a95750838201355b600019600387901b1c1916600186901b17835561151b565b600083815260209020601f19861690835b828110156114f257868501358255602094850194600190920191016114d2565b508682101561150f5760001960f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b6000600182016115345761153461135a565b506001019056fea2646970667358221220f3e6e3e93788ae67c1eaf31cb805370313ba096ed5aa792e2b15c335a3903e5a64736f6c63430008120033a2646970667358221220452028a72bf515ef364f752d379d36e460edada7991f7fdb8d560ed8e00d58f964736f6c63430008120033
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.