Source Code
Overview
ETH Balance
0 ETH
Token Holdings
More Info
ContractCreator
Multichain Info
N/A
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
CometRewardsV2
Compiler Version
v0.8.15+commit.e14f2714
Optimization Enabled:
Yes with 1 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.15; import "./CometInterface.sol"; import "./IERC20NonStandard.sol"; import "./MerkleProof.sol"; /** * @title Compound's CometRewards Contract * @notice Hold and claim token rewards * @author Compound */ contract CometRewardsV2 { /** * @notice struct for token multiplier * @param token The token address * @param multiplier The multiplier for the token */ struct TokenMultiplier { address token; uint256 multiplier; } /** * @notice The configuration for a reward token * @param multiplier The multiplier for the token * @param rescaleFactor The rescale factor for the token * @dev rescaleFactor = baseAccrualScale / tokenDecimals, * so for example if baseAccrualScale = 1e18 and tokenDecimals = 1e6, rescaleFactor = 1e12 * @param shouldUpscale Whether or not to upscale the token * @dev If the baseAccrualScale is greater than the tokenDecimals, we should upscale the token */ struct AssetConfig { uint256 multiplier; uint128 rescaleFactor; bool shouldUpscale; } /** * @notice The configuration for a campaign * @param startRoot The root of the Merkle tree for the startAccrued * @param finishRoot The root of the Merkle tree for the finishAccrued * @param assets The reward tokens addresses * @param configs The reward tokens configurations * @param claimed The claimed rewards for each user * @param finishTimestamp The timestamp when the campaign ends */ struct Campaign { bytes32 startRoot; bytes32 finishRoot; address[] assets; /// @dev token => AssetConfig mapping(address => AssetConfig)configs; /// @dev user => token => claimed mapping(address => mapping(address => uint256)) claimed; uint256 finishTimestamp; } /** * @notice The reward owed to an account * @param token The reward token address * @param owed The amount of the reward token owed */ struct RewardOwed { address token; uint256 owed; } /** * @notice The proof for a user in the start tree * @param startIndex The index of the user in the start tree * @param finishIndex The index of the user in the finish tree * @param startAccrued The accrued value for the user in the start tree * @param finishAccrued The accrued value for the user in the finish tree * @param startMerkleProof The Merkle proof for the start tree * @param finishMerkleProof The Merkle proof for the finish tree */ struct Proofs { uint256 startIndex; uint256 finishIndex; uint256 startAccrued; uint256 finishAccrued; bytes32[] startMerkleProof; bytes32[] finishMerkleProof; } /** * @notice The proof for 2 users * @param proofs The proofs for each user */ struct MultiProofs{ Proofs[2] proofs; } /** * @notice The proof for a user in the finish tree * @param finishIndex The index of the user in the finish tree * @param finishAccrued The accrued value for the user in the finish tree * @param finishMerkleProof The Merkle proof for the finish tree */ struct FinishProof{ uint256 finishIndex; uint256 finishAccrued; bytes32[] finishMerkleProof; } /// @notice The governor address which controls the contract address public governor; /// @notice Campaigns per Comet instance /// @dev comet => Campaign[] mapping(address => Campaign[]) public campaigns; /// @notice The maximum duration for a campaign uint256 public constant MAX_CAMPAIGN_DURATION = 180 days; /// @dev The scale for factors uint256 internal constant FACTOR_SCALE = 1e18; /** Custom events **/ event GovernorTransferred( address indexed oldGovernor, address indexed newGovernor ); event RewardsClaimedSet( uint256 campaignId, address indexed user, address indexed comet, address indexed token, uint256 amount ); event RewardClaimed( uint256 campaignId, address indexed comet, address indexed src, address indexed recipient, address token, uint256 amount ); event ConfigUpdated( uint256 campaignId, address indexed comet, address indexed token, uint256 multiplier ); event NewCampaign( address comet, uint256 campaignId ); event NewCampaignFinishRoot( address comet, bytes32 finishRoot, uint256 campaignId ); event TokenWithdrawn( address indexed token, address indexed to, uint256 amount ); event TransferOutFailed( address indexed token, address indexed to, uint256 amount ); /** Custom errors **/ error BadData(); error InvalidUint128(uint256); error NotPermitted(address); error NotSupported(address, address); error NullGovernor(); error InvalidProof(); error NotANewMember(address); error CampaignEnded(address, uint256); /** * @notice Construct a new rewards pool * @param governor_ The governor who will control the contract */ constructor(address governor_) { if(governor_ == address(0)) revert NullGovernor(); governor = governor_; } /** * @notice Adds a new campaign to a Comet with custom multipliers for each token * @param comet Comet protocol address * @param startRoot The root of the Merkle tree for the startAccrued * @param assets Reward tokens addresses * @param duration The duration of the campaign * @return campaignId Id of the created campaign */ function setNewCampaignWithCustomTokenMultiplier( address comet, bytes32 startRoot, TokenMultiplier[] memory assets, uint256 duration ) public returns(uint256 campaignId) { if(msg.sender != governor) revert NotPermitted(msg.sender); if(startRoot == bytes32(0)) revert BadData(); if(assets.length == 0) revert BadData(); if(duration > MAX_CAMPAIGN_DURATION) revert BadData(); uint64 accrualScale = CometInterface(comet).baseAccrualScale(); Campaign storage $ = campaigns[comet].push(); campaignId = campaigns[comet].length - 1; $.startRoot = startRoot; for (uint256 i = 0; i < assets.length; i++) { if(assets[i].multiplier == 0) revert BadData(); uint128 tokenScale = safe128(10 ** IERC20NonStandard(assets[i].token).decimals()); emit ConfigUpdated(campaignId, comet, assets[i].token, assets[i].multiplier); if(accrualScale > tokenScale) { $.configs[assets[i].token] = AssetConfig({ multiplier: assets[i].multiplier, rescaleFactor: accrualScale / tokenScale, shouldUpscale: false }); } else { $.configs[assets[i].token] = AssetConfig({ multiplier: assets[i].multiplier, rescaleFactor: tokenScale / accrualScale, shouldUpscale: true }); } $.assets.push(assets[i].token); } $.finishTimestamp = block.timestamp + duration; emit NewCampaign( comet, campaignId ); return(campaignId); } /** * @notice Adds a new campaign to a Comet * @param comet The protocol instance * @param startRoot The root of the Merkle tree for the startAccrued * @param tokens The reward tokens addresses * @return campaignId Id of the created campaign */ function setNewCampaign( address comet, bytes32 startRoot, address[] calldata tokens, uint256 duration ) external returns(uint256 campaignId) { TokenMultiplier[] memory assets = new TokenMultiplier[](tokens.length); for (uint256 i = 0; i < tokens.length; i++) { assets[i] = TokenMultiplier({token: tokens[i], multiplier: FACTOR_SCALE}); } return setNewCampaignWithCustomTokenMultiplier(comet, startRoot, assets, duration); } /** * @notice Set the reward token for a Comet instance for multiple users * @param comet Comet protocol address * @param campaignId Id of the campaign * @param users The list of users to populate the data for * @param tokens The list of tokens to populate the data with * @param claimedAmounts The list of amounts to populate the data with */ function setRewardsClaimed( address comet, uint256 campaignId, address[] calldata users, address[][] calldata tokens, uint256[][] calldata claimedAmounts ) external { if(msg.sender != governor) revert NotPermitted(msg.sender); if(users.length != claimedAmounts.length) revert BadData(); if(tokens.length != claimedAmounts.length) revert BadData(); Campaign storage $ = campaigns[comet][campaignId]; for (uint256 i = 0; i < claimedAmounts.length; i++) { if($.assets.length != claimedAmounts[i].length) revert BadData(); if($.assets.length != tokens[i].length) revert BadData(); for(uint256 j = 0; j < claimedAmounts[i].length; j++){ emit RewardsClaimedSet(campaignId, users[i], comet, tokens[i][j], claimedAmounts[i][j]); $.claimed[users[i]][tokens[i][j]] = claimedAmounts[i][j]; } } } /** * @notice Set finish root for a campaign * @param comet The protocol instance * @param campaignId The id of the campaign * @param finishRoot The root of the Merkle tree for the finishAccrued */ function setCampaignFinishRoot( address comet, uint256 campaignId, bytes32 finishRoot ) public { if(msg.sender != governor) revert NotPermitted(msg.sender); if(finishRoot == bytes32(0)) revert BadData(); if(campaigns[comet].length == 0) revert NotSupported(comet, address(0)); if(campaignId >= campaigns[comet].length) revert BadData(); emit NewCampaignFinishRoot(comet, finishRoot, campaignId); campaigns[comet][campaignId].finishRoot = finishRoot; } /** * @notice Withdraw tokens from the contract * @param token The reward token address * @param to Where to send the tokens * @param amount The number of tokens to withdraw */ function withdrawToken(address token, address to, uint256 amount) external { if(msg.sender != governor) revert NotPermitted(msg.sender); if(doTransferOut(token, to, amount) > 0) emit TokenWithdrawn(token, to, amount); } /** * @notice Transfers the governor rights to a new address * @param newGovernor The address of the new governor */ function transferGovernor(address newGovernor) external { if(msg.sender != governor) revert NotPermitted(msg.sender); if(newGovernor == address(0)) revert NullGovernor(); emit GovernorTransferred(governor, newGovernor); governor = newGovernor; } /** * @notice Calculates the amount of a reward token owed to an account * @param comet Comet protocol address * @param campaignId Id of the campaign * @param token Reward token address * @param account The account to check rewards for * @param startAccrued Start accrued value * @param finishAccrued Finish accrued value if finishRoot is set */ function getRewardsOwed( address comet, uint256 campaignId, address token, address account, uint256 startAccrued, uint256 finishAccrued, bool shouldAccrue ) external returns (RewardOwed memory) { if(campaigns[comet].length == 0) revert NotSupported(comet, address(0)); if(campaignId >= campaigns[comet].length) revert BadData(); Campaign storage $ = campaigns[comet][campaignId]; AssetConfig memory config = $.configs[token]; if(config.multiplier == 0) revert NotSupported(comet, token); if($.finishRoot == bytes32(0) && shouldAccrue) CometInterface(comet).accrueAccount(account); uint256 claimed = $.claimed[account][token]; uint256 accrued = getRewardsAccrued( comet, account, startAccrued, finishAccrued, config ); return RewardOwed( token, accrued > claimed ? accrued - claimed : 0 ); } /** * @notice Calculates the amount of each reward token owed to an account in a batch * @param comet Comet protocol address * @param campaignId Id of the campaign * @param account The account to check rewards for * @param startAccrued Start accrued value * @param finishAccrued Finish accrued value if finishRoot is set * @return owed List of RewardOwed */ function getRewardsOwedBatch( address comet, uint256 campaignId, address account, uint256 startAccrued, uint256 finishAccrued, bool shouldAccrue ) external returns (RewardOwed[] memory) { if(campaigns[comet].length == 0) revert NotSupported(comet, address(0)); if(campaignId >= campaigns[comet].length) revert BadData(); Campaign storage $ = campaigns[comet][campaignId]; RewardOwed[] memory owed = new RewardOwed[]($.assets.length); if($.finishRoot == bytes32(0) && shouldAccrue) CometInterface(comet).accrueAccount(account); for (uint256 j; j < $.assets.length; j++) { address token = $.assets[j]; AssetConfig memory config = $.configs[token]; uint256 claimed = $.claimed[account][token]; uint256 accrued = getRewardsAccrued( comet, account, startAccrued, finishAccrued, config ); owed[j] = RewardOwed( token, accrued > claimed ? accrued - claimed : 0 ); } return owed; } /** * @notice Claim rewards with each token from a comet instance to owner address * @param comet Comet protocol address * @param campaignId Id of the campaign * @param src The owner to claim for * @param shouldAccrue Whether or not to call accrue first * @dev This function is designed for new members (everyone who is not in a startTree) who want to claim rewards. * To prove that they are indeed new members, users need to provide evidence that verifies their status. * We use a Sorted Merkle Tree for this verification process. * This tree is organized based on account addresses. * In order to prove that an account is new, the user must provide the Merkle proofs for the two closest addresses to their own address. * If the user's address is either lower than the first address or higher than the last address in the tree, * the Merkle Tree includes placeholders (zero and maximum address) for comparison, ensuring there are always at least two addresses available for comparison. * Additionally, the Merkle Tree contains the index of each address, serving as proof of existing users' membership. * @param neighbors The neighbors of the account * @param proofs The Merkle proofs for each neighbor * @param finishProof The Merkle proof for the finish accrued if finishRoot is set */ function claimForNewMember( address comet, uint256 campaignId, address src, bool shouldAccrue, address[2] calldata neighbors, Proofs[2] calldata proofs, FinishProof calldata finishProof ) external { if(campaigns[comet].length == 0) revert NotSupported(comet, address(0)); verifyNewMember(comet, src, campaignId, neighbors, proofs); claimInternalForNewMember( comet, src, src, campaignId, shouldAccrue, finishProof ); } /** * @notice Claim rewards for all chosen campaigns for given comet instance * @param comet Comet protocol address * @param campaignIDs The list of campaigns to claim for * @param src The owner to claim for * @param shouldAccrue Whether or not to call accrue first * @param neighbors The neighbors of the account * @param multiProofs The Merkle proofs for each neighbor * @param finishProofs The Merkle proof for the finish accrued if finishRoot is set */ function claimBatchForNewMember( address comet, uint256[] memory campaignIDs, address src, bool shouldAccrue, address[2][] calldata neighbors, MultiProofs[] calldata multiProofs, FinishProof[] calldata finishProofs ) external { if(campaignIDs.length != neighbors.length) revert BadData(); if(campaignIDs.length != multiProofs.length) revert BadData(); if(campaignIDs.length != finishProofs.length) revert BadData(); if(campaigns[comet].length == 0) revert NotSupported(comet, address(0)); if(shouldAccrue) CometInterface(comet).accrueAccount(src); for (uint256 i; i < campaignIDs.length; i++) { verifyNewMember(comet, src, campaignIDs[i], neighbors[i], multiProofs[i].proofs); claimInternalForNewMember( comet, src, src, campaignIDs[i], false, finishProofs[i] ); } } /** * @notice Claim rewards with each token from a comet instance to a target address * @param comet Comet protocol address * @param campaignId Id of the campaign * @param src The owner to claim for * @param to The address to receive the rewards * @param shouldAccrue Whether or not to call accrue first * @param neighbors The neighbors of the account * @param proofs The Merkle proofs for each neighbor * @param finishProof The Merkle proof for the finish accrued if finishRoot is set */ function claimToForNewMember( address comet, uint256 campaignId, address src, address to, bool shouldAccrue, address[2] calldata neighbors, Proofs[2] calldata proofs, FinishProof calldata finishProof ) external { if(campaigns[comet].length == 0) revert NotSupported(comet, address(0)); if(!CometInterface(comet).hasPermission(src, msg.sender)) revert NotPermitted(msg.sender); verifyNewMember(comet, src, campaignId, neighbors, proofs); claimInternalForNewMember( comet, src, to, campaignId, shouldAccrue, finishProof ); } /** * @notice Claim rewards for all chosen campaigns for given comet instance to a target address * @param comet Comet protocol address * @param campaignIDs The list of campaigns to claim for * @param src The owner to claim for * @param to The address to receive the rewards * @param shouldAccrue Whether or not to call accrue first * @param neighbors The neighbors of the account * @param multiProofs The Merkle proofs for each neighbor * @param finishProofs The Merkle proof for the finish accrued if finishRoot is set */ function claimToBatchForNewMember( address comet, uint256[] memory campaignIDs, address src, address to, bool shouldAccrue, address[2][] calldata neighbors, MultiProofs[] calldata multiProofs, FinishProof[] calldata finishProofs ) external { if(campaignIDs.length != neighbors.length) revert BadData(); if(campaignIDs.length != multiProofs.length) revert BadData(); if(campaignIDs.length != finishProofs.length) revert BadData(); if(campaigns[comet].length == 0) revert NotSupported(comet, address(0)); if(shouldAccrue) CometInterface(comet).accrueAccount(src); for (uint256 i; i < campaignIDs.length; i++) { if(!CometInterface(comet).hasPermission(src, msg.sender)) revert NotPermitted(msg.sender); verifyNewMember(comet, src, campaignIDs[i], neighbors[i], multiProofs[i].proofs); claimInternalForNewMember( comet, src, to, campaignIDs[i], false, finishProofs[i] ); } } /** * @notice Claim rewards with each token from a comet instance to owner address * @param comet Comet protocol address * @param campaignId Id of the campaign * @param src The owner to claim for * @param shouldAccrue Whether or not to call accrue first * @param proofs The Merkle proofs for the start and finish accrued */ function claim( address comet, uint256 campaignId, address src, bool shouldAccrue, Proofs calldata proofs ) external { claimInternal(comet, src, src, campaignId, proofs, shouldAccrue); } /** * @notice Claim rewards for all chosen campaigns for given comet instance * @param comet Comet protocol address * @param campaignIds The list of campaigns to claim for * @param src The owner to claim for * @param shouldAccrue Whether or not to call accrue first * @param proofs The Merkle proofs for the start and finish accrued */ function claimBatch( address comet, uint256[] memory campaignIds, address src, bool shouldAccrue, Proofs[] calldata proofs ) external { claimInternalBatch(comet, src, src, campaignIds, proofs, shouldAccrue); } /** * @notice Claim rewards with each token from a comet instance to a target address * @param comet Comet protocol address * @param campaignId Id of the campaign * @param src The owner to claim for * @param to The address to receive the rewards * @param shouldAccrue Whether or not to call accrue first * @param proofs The Merkle proofs for the start and finish accrued */ function claimTo( address comet, uint256 campaignId, address src, address to, bool shouldAccrue, Proofs calldata proofs ) external { if(!CometInterface(comet).hasPermission(src, msg.sender)) revert NotPermitted(msg.sender); claimInternal(comet, src, to, campaignId, proofs, shouldAccrue); } /** * @notice Returns claimed rewards for a user in a specific campaign for a specific token * @param comet Comet protocol address * @param campaignId Id of the campaign * @param src The owner to check for * @param token The reward token address * @return The amount of claimed rewards */ function rewardsClaimed( address comet, uint256 campaignId, address src, address token ) external view returns(uint256) { return campaigns[comet][campaignId].claimed[src][token]; } /** * @notice Returns the reward configuration for all tokens in a specific campaign * @param comet Comet protocol address * @param campaignId Id of the campaign * @return The reward configuration */ function rewardConfig( address comet, uint256 campaignId ) external view returns(address[] memory, AssetConfig[] memory) { Campaign storage $ = campaigns[comet][campaignId]; AssetConfig[] memory configs = new AssetConfig[]($.assets.length); for (uint256 i; i < $.assets.length; i++) { configs[i] = $.configs[$.assets[i]]; } return ($.assets, configs); } /** * @notice Returns all campaigns for a specific Comet instance * @param comet Comet protocol address * @return startRoots The start roots for each campaign * @return finishRoots The finish roots for each campaign * @return assets The reward tokens for each campaign * @return finishTimestamps The finish timestamps for each campaign */ function getCometCampaignsInfo(address comet) external view returns( bytes32[] memory startRoots, bytes32[] memory finishRoots, address[][] memory assets, uint256[] memory finishTimestamps ) { if(campaigns[comet].length == 0) return (startRoots, finishRoots, assets, finishTimestamps); startRoots = new bytes32[](campaigns[comet].length); finishRoots = new bytes32[](campaigns[comet].length); assets = new address[][](campaigns[comet].length); finishTimestamps = new uint256[](campaigns[comet].length); for (uint256 i; i < campaigns[comet].length; i++) { Campaign storage $ = campaigns[comet][i]; startRoots[i] = $.startRoot; finishRoots[i] = $.finishRoot; assets[i] = $.assets; finishTimestamps[i] = $.finishTimestamp; } } /** * @notice Returns true if the proof is valid * @param root The root of the Merkle tree * @param proofs The Merkle proofs * @param account The account to check for * @param index The index of the account * @param accrued The accrued value for the account * @return True if the proof is valid */ function verifyProof( bytes32 root, bytes32[] calldata proofs, address account, uint256 index, uint256 accrued ) external pure returns(bool) { return MerkleProof.verifyCalldata( proofs, root, keccak256(bytes.concat(keccak256(abi.encode(account, index, accrued)))) ); } /** * @notice Returns the reward configuration for a specific token in a specific campaign * @param comet Comet protocol address * @param campaignId Id of the campaign * @param token The reward token address * @return The reward configuration */ function rewardConfigForToken( address comet, uint256 campaignId, address token ) external view returns(AssetConfig memory) { return campaigns[comet][campaignId].configs[token]; } /** * @notice Claim rewards for all chosen campaigns for given comet instance to a target address * @param comet Comet protocol address * @param campaignIds The list of campaigns to claim for * @param src The owner to claim for * @param to The address to receive the rewards * @param shouldAccrue Whether or not to call accrue first * @param proofs The Merkle proofs for the start and finish accrued */ function claimToBatch( address comet, uint256[] memory campaignIds, address src, address to, bool shouldAccrue, Proofs[] calldata proofs ) external { if(!CometInterface(comet).hasPermission(src, msg.sender)) revert NotPermitted(msg.sender); claimInternalBatch(comet, src, to, campaignIds, proofs, shouldAccrue); } /** * @dev Verify the membership of an account */ function verifyNewMember( address comet, address account, uint256 campaignId, address[2] calldata neighbors, Proofs[2] calldata proofs ) internal view returns(bool) { // check if the account is in between the neighbors if(campaigns[comet].length == 0) revert NotSupported(comet, address(0)); if(campaignId >= campaigns[comet].length) revert BadData(); if(!(neighbors[0] < account && account < neighbors[1])) revert BadData(); // check if the neighbors are in the right order if(!((proofs[1].startIndex > proofs[0].startIndex) && (proofs[1].startIndex - proofs[0].startIndex == 1))) revert BadData(); Campaign storage $ = campaigns[comet][campaignId]; bool isValidProof = MerkleProof.verifyCalldata( proofs[0].startMerkleProof, $.startRoot, keccak256(bytes.concat(keccak256(abi.encode(neighbors[0], proofs[0].startIndex, proofs[0].startAccrued))) ) ); if(!isValidProof) revert InvalidProof(); isValidProof = MerkleProof.verifyCalldata( proofs[1].startMerkleProof, $.startRoot, keccak256(bytes.concat(keccak256(abi.encode(neighbors[1], proofs[1].startIndex, proofs[1].startAccrued))) ) ); if(!isValidProof) revert InvalidProof(); return true; } /** * @dev Claim rewards for a new member */ function claimInternalForNewMember( address comet, address src, address to, uint256 campaignId, bool shouldAccrue, FinishProof calldata finishProof ) internal { Campaign storage $ = campaigns[comet][campaignId]; if($.finishRoot != bytes32(0)) { bool isValidProof = MerkleProof.verifyCalldata( finishProof.finishMerkleProof, $.finishRoot, keccak256(bytes.concat(keccak256(abi.encode(src, finishProof.finishIndex, finishProof.finishAccrued)))) ); if(!isValidProof) revert InvalidProof(); } else if($.finishTimestamp < block.timestamp) revert CampaignEnded(comet, campaignId); if(shouldAccrue) { CometInterface(comet).accrueAccount(src); } for (uint256 j; j < $.assets.length; j++) { AssetConfig memory config = $.configs[$.assets[j]]; address token = $.assets[j]; uint256 claimed = $.claimed[src][token]; uint256 accrued = getRewardsAccrued( comet, src, 0, $.finishRoot != bytes32(0) ? finishProof.finishAccrued : 0, config ); if(accrued > claimed) { uint256 owed = accrued - claimed; if(doTransferOut(token, to, owed) > 0){ $.claimed[src][token] = accrued; emit RewardClaimed(campaignId, comet, src, to, token, owed); } } } } /** * @dev Claim rewards for an established member */ function claimInternal( address comet, address src, address to, uint256 campaignId, Proofs calldata proofs, bool shouldAccrue ) internal { if(campaigns[comet].length == 0) revert NotSupported(comet, address(0)); if(campaignId >= campaigns[comet].length) revert BadData(); Campaign storage $ = campaigns[comet][campaignId]; bool isValidProof = MerkleProof.verifyCalldata( proofs.startMerkleProof, $.startRoot, keccak256(bytes.concat(keccak256(abi.encode(src, proofs.startIndex, proofs.startAccrued)))) ); if(!isValidProof) revert InvalidProof(); if($.finishRoot != bytes32(0)) { bool isValidProof2 = MerkleProof.verifyCalldata( proofs.finishMerkleProof, $.finishRoot, keccak256(bytes.concat(keccak256(abi.encode(src, proofs.finishIndex, proofs.finishAccrued)))) ); if(!isValidProof2) revert InvalidProof(); } else if($.finishTimestamp < block.timestamp) revert CampaignEnded(comet, campaignId); if(shouldAccrue) { //remove from loop CometInterface(comet).accrueAccount(src); } for (uint256 j; j < $.assets.length; j++) { address token = $.assets[j]; AssetConfig memory config = $.configs[token]; uint256 claimed = $.claimed[src][token]; uint256 accrued = getRewardsAccrued( comet, src, proofs.startAccrued, $.finishRoot != bytes32(0) ? proofs.finishAccrued : 0, config ); if(accrued > claimed) { uint256 owed = accrued - claimed; if(doTransferOut(token, to, owed) > 0){ $.claimed[src][token] = accrued; emit RewardClaimed(campaignId, comet, src, to, token, owed); } } } } /** * @dev Claim rewards for multiple campaigns */ function claimInternalBatch( address comet, address src, address to, uint256[] memory campaignIds, Proofs[] calldata proofs, bool shouldAccrue ) internal { if(campaignIds.length != proofs.length) revert BadData(); if(campaigns[comet].length == 0) revert NotSupported(comet, address(0)); if(shouldAccrue) CometInterface(comet).accrueAccount(src); for (uint256 i; i < campaignIds.length; i++) { if(campaignIds[i] >= campaigns[comet].length) revert BadData(); claimInternal( comet, src, to, campaignIds[i], proofs[i], false ); } } /** * @dev Calculate the accrued value */ function getRewardsAccrued( address comet, address account, uint256 startAccrued, //if startAccrued = 0 => it is a new member uint256 finishAccrued, AssetConfig memory config ) internal view returns (uint256 accrued) { if(finishAccrued > 0) { accrued = finishAccrued - startAccrued; } else{ accrued = CometInterface(comet).baseTrackingAccrued(account) - startAccrued; } if(config.shouldUpscale) { accrued *= config.rescaleFactor; } else { accrued /= config.rescaleFactor; } return (accrued * config.multiplier) / FACTOR_SCALE; } /** * @dev Safe ERC20 transfer out */ function doTransferOut(address token, address to, uint256 amount) internal returns(uint256 amountOut) { if(amount == 0) return 0; IERC20NonStandard(token).transfer(to, amount); bool success; assembly ("memory-safe") { switch returndatasize() case 0 { // This is a non-standard ERC-20 success := not(0) // set success to true } case 32 { // This is a compliant ERC-20 returndatacopy(0, 0, 32) success := mload(0) // Set `success = returndata` of override external call } default { // This is an excessively non-compliant ERC-20, revert. revert(0, 0) } } if(!success) emit TransferOutFailed(token, to, amount); else return amount; } /** * @dev Safe cast to uint128 */ function safe128(uint256 n) internal pure returns (uint128) { if(n > type(uint128).max) revert InvalidUint128(n); return uint128(n); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.15; /** * @title Compound's Comet Configuration Interface * @author Compound */ contract CometConfiguration { struct ExtConfiguration { bytes32 name32; bytes32 symbol32; } struct Configuration { address governor; address pauseGuardian; address baseToken; address baseTokenPriceFeed; address extensionDelegate; uint64 supplyKink; uint64 supplyPerYearInterestRateSlopeLow; uint64 supplyPerYearInterestRateSlopeHigh; uint64 supplyPerYearInterestRateBase; uint64 borrowKink; uint64 borrowPerYearInterestRateSlopeLow; uint64 borrowPerYearInterestRateSlopeHigh; uint64 borrowPerYearInterestRateBase; uint64 storeFrontPriceFactor; uint64 trackingIndexScale; uint64 baseTrackingSupplySpeed; uint64 baseTrackingBorrowSpeed; uint104 baseMinForRewards; uint104 baseBorrowMin; uint104 targetReserves; AssetConfig[] assetConfigs; } struct AssetConfig { address asset; address priceFeed; uint8 decimals; uint64 borrowCollateralFactor; uint64 liquidateCollateralFactor; uint64 liquidationFactor; uint128 supplyCap; } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.15; import "./CometConfiguration.sol"; import "./CometStorage.sol"; import "./CometMath.sol"; abstract contract CometCore is CometConfiguration, CometStorage, CometMath { struct AssetInfo { uint8 offset; address asset; address priceFeed; uint64 scale; uint64 borrowCollateralFactor; uint64 liquidateCollateralFactor; uint64 liquidationFactor; uint128 supplyCap; } /** Internal constants **/ /// @dev The max number of assets this contract is hardcoded to support /// Do not change this variable without updating all the fields throughout the contract, // including the size of UserBasic.assetsIn and corresponding integer conversions. uint8 internal constant MAX_ASSETS = 15; /// @dev The max number of decimals base token can have /// Note this cannot just be increased arbitrarily. uint8 internal constant MAX_BASE_DECIMALS = 18; /// @dev The max value for a collateral factor (1) uint64 internal constant MAX_COLLATERAL_FACTOR = FACTOR_SCALE; /// @dev Offsets for specific actions in the pause flag bit array uint8 internal constant PAUSE_SUPPLY_OFFSET = 0; uint8 internal constant PAUSE_TRANSFER_OFFSET = 1; uint8 internal constant PAUSE_WITHDRAW_OFFSET = 2; uint8 internal constant PAUSE_ABSORB_OFFSET = 3; uint8 internal constant PAUSE_BUY_OFFSET = 4; /// @dev The decimals required for a price feed uint8 internal constant PRICE_FEED_DECIMALS = 8; /// @dev 365 days * 24 hours * 60 minutes * 60 seconds uint64 internal constant SECONDS_PER_YEAR = 31_536_000; /// @dev The scale for base tracking accrual uint64 internal constant BASE_ACCRUAL_SCALE = 1e6; /// @dev The scale for base index (depends on time/rate scales, not base token) uint64 internal constant BASE_INDEX_SCALE = 1e15; /// @dev The scale for prices (in USD) uint64 internal constant PRICE_SCALE = uint64(10 ** PRICE_FEED_DECIMALS); /// @dev The scale for factors uint64 internal constant FACTOR_SCALE = 1e18; /// @dev The storage slot for reentrancy guard flags bytes32 internal constant REENTRANCY_GUARD_FLAG_SLOT = bytes32(keccak256("comet.reentrancy.guard")); /// @dev The reentrancy guard statuses uint256 internal constant REENTRANCY_GUARD_NOT_ENTERED = 0; uint256 internal constant REENTRANCY_GUARD_ENTERED = 1; /** * @notice Determine if the manager has permission to act on behalf of the owner * @param owner The owner account * @param manager The manager account * @return Whether or not the manager has permission */ function hasPermission(address owner, address manager) public view returns (bool) { return owner == manager || isAllowed[owner][manager]; } /** * @dev The positive present supply balance if positive or the negative borrow balance if negative */ function presentValue(int104 principalValue_) internal view returns (int256) { if (principalValue_ >= 0) { return signed256(presentValueSupply(baseSupplyIndex, uint104(principalValue_))); } else { return -signed256(presentValueBorrow(baseBorrowIndex, uint104(-principalValue_))); } } /** * @dev The principal amount projected forward by the supply index */ function presentValueSupply(uint64 baseSupplyIndex_, uint104 principalValue_) internal pure returns (uint256) { return uint256(principalValue_) * baseSupplyIndex_ / BASE_INDEX_SCALE; } /** * @dev The principal amount projected forward by the borrow index */ function presentValueBorrow(uint64 baseBorrowIndex_, uint104 principalValue_) internal pure returns (uint256) { return uint256(principalValue_) * baseBorrowIndex_ / BASE_INDEX_SCALE; } /** * @dev The positive principal if positive or the negative principal if negative */ function principalValue(int256 presentValue_) internal view returns (int104) { if (presentValue_ >= 0) { return signed104(principalValueSupply(baseSupplyIndex, uint256(presentValue_))); } else { return -signed104(principalValueBorrow(baseBorrowIndex, uint256(-presentValue_))); } } /** * @dev The present value projected backward by the supply index (rounded down) * Note: This will overflow (revert) at 2^104/1e18=~20 trillion principal for assets with 18 decimals. */ function principalValueSupply(uint64 baseSupplyIndex_, uint256 presentValue_) internal pure returns (uint104) { return safe104((presentValue_ * BASE_INDEX_SCALE) / baseSupplyIndex_); } /** * @dev The present value projected backward by the borrow index (rounded up) * Note: This will overflow (revert) at 2^104/1e18=~20 trillion principal for assets with 18 decimals. */ function principalValueBorrow(uint64 baseBorrowIndex_, uint256 presentValue_) internal pure returns (uint104) { return safe104((presentValue_ * BASE_INDEX_SCALE + baseBorrowIndex_ - 1) / baseBorrowIndex_); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.15; import "./CometCore.sol"; /** * @title Compound's Comet Ext Interface * @notice An efficient monolithic money market protocol * @author Compound */ abstract contract CometExtInterface is CometCore { error BadAmount(); error BadNonce(); error BadSignatory(); error InvalidValueS(); error InvalidValueV(); error SignatureExpired(); function allow(address manager, bool isAllowed) virtual external; function allowBySig(address owner, address manager, bool isAllowed, uint256 nonce, uint256 expiry, uint8 v, bytes32 r, bytes32 s) virtual external; function collateralBalanceOf(address account, address asset) virtual external view returns (uint128); function baseTrackingAccrued(address account) virtual external view returns (uint64); function baseAccrualScale() virtual external view returns (uint64); function baseIndexScale() virtual external view returns (uint64); function factorScale() virtual external view returns (uint64); function priceScale() virtual external view returns (uint64); function maxAssets() virtual external view returns (uint8); function totalsBasic() virtual external view returns (TotalsBasic memory); function version() virtual external view returns (string memory); /** * ===== ERC20 interfaces ===== * Does not include the following functions/events, which are defined in `CometMainInterface` instead: * - function decimals() virtual external view returns (uint8) * - function totalSupply() virtual external view returns (uint256) * - function transfer(address dst, uint amount) virtual external returns (bool) * - function transferFrom(address src, address dst, uint amount) virtual external returns (bool) * - function balanceOf(address owner) virtual external view returns (uint256) * - event Transfer(address indexed from, address indexed to, uint256 amount) */ function name() virtual external view returns (string memory); function symbol() virtual external view returns (string memory); /** * @notice Approve `spender` to transfer up to `amount` from `src` * @dev This will overwrite the approval amount for `spender` * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) * @param spender The address of the account which may transfer tokens * @param amount The number of tokens that are approved (-1 means infinite) * @return Whether or not the approval succeeded */ function approve(address spender, uint256 amount) virtual external returns (bool); /** * @notice Get the current allowance from `owner` for `spender` * @param owner The address of the account which owns the tokens to be spent * @param spender The address of the account which may transfer tokens * @return The number of tokens allowed to be spent (-1 means infinite) */ function allowance(address owner, address spender) virtual external view returns (uint256); event Approval(address indexed owner, address indexed spender, uint256 amount); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.15; import "./CometMainInterface.sol"; import "./CometExtInterface.sol"; /** * @title Compound's Comet Interface * @notice An efficient monolithic money market protocol * @author Compound */ abstract contract CometInterface is CometMainInterface, CometExtInterface {}
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.15; import "./CometCore.sol"; /** * @title Compound's Comet Main Interface (without Ext) * @notice An efficient monolithic money market protocol * @author Compound */ abstract contract CometMainInterface is CometCore { error Absurd(); error AlreadyInitialized(); error BadAsset(); error BadDecimals(); error BadDiscount(); error BadMinimum(); error BadPrice(); error BorrowTooSmall(); error BorrowCFTooLarge(); error InsufficientReserves(); error LiquidateCFTooLarge(); error NoSelfTransfer(); error NotCollateralized(); error NotForSale(); error NotLiquidatable(); error Paused(); error ReentrantCallBlocked(); error SupplyCapExceeded(); error TimestampTooLarge(); error TooManyAssets(); error TooMuchSlippage(); error TransferInFailed(); error TransferOutFailed(); error Unauthorized(); event Supply(address indexed from, address indexed dst, uint amount); event Transfer(address indexed from, address indexed to, uint amount); event Withdraw(address indexed src, address indexed to, uint amount); event SupplyCollateral(address indexed from, address indexed dst, address indexed asset, uint amount); event TransferCollateral(address indexed from, address indexed to, address indexed asset, uint amount); event WithdrawCollateral(address indexed src, address indexed to, address indexed asset, uint amount); /// @notice Event emitted when a borrow position is absorbed by the protocol event AbsorbDebt(address indexed absorber, address indexed borrower, uint basePaidOut, uint usdValue); /// @notice Event emitted when a user's collateral is absorbed by the protocol event AbsorbCollateral(address indexed absorber, address indexed borrower, address indexed asset, uint collateralAbsorbed, uint usdValue); /// @notice Event emitted when a collateral asset is purchased from the protocol event BuyCollateral(address indexed buyer, address indexed asset, uint baseAmount, uint collateralAmount); /// @notice Event emitted when an action is paused/unpaused event PauseAction(bool supplyPaused, bool transferPaused, bool withdrawPaused, bool absorbPaused, bool buyPaused); /// @notice Event emitted when reserves are withdrawn by the governor event WithdrawReserves(address indexed to, uint amount); function supply(address asset, uint amount) virtual external; function supplyTo(address dst, address asset, uint amount) virtual external; function supplyFrom(address from, address dst, address asset, uint amount) virtual external; function transfer(address dst, uint amount) virtual external returns (bool); function transferFrom(address src, address dst, uint amount) virtual external returns (bool); function transferAsset(address dst, address asset, uint amount) virtual external; function transferAssetFrom(address src, address dst, address asset, uint amount) virtual external; function withdraw(address asset, uint amount) virtual external; function withdrawTo(address to, address asset, uint amount) virtual external; function withdrawFrom(address src, address to, address asset, uint amount) virtual external; function approveThis(address manager, address asset, uint amount) virtual external; function withdrawReserves(address to, uint amount) virtual external; function absorb(address absorber, address[] calldata accounts) virtual external; function buyCollateral(address asset, uint minAmount, uint baseAmount, address recipient) virtual external; function quoteCollateral(address asset, uint baseAmount) virtual public view returns (uint); function getAssetInfo(uint8 i) virtual public view returns (AssetInfo memory); function getAssetInfoByAddress(address asset) virtual public view returns (AssetInfo memory); function getCollateralReserves(address asset) virtual public view returns (uint); function getReserves() virtual public view returns (int); function getPrice(address priceFeed) virtual public view returns (uint); function isBorrowCollateralized(address account) virtual public view returns (bool); function isLiquidatable(address account) virtual public view returns (bool); function totalSupply() virtual external view returns (uint256); function totalBorrow() virtual external view returns (uint256); function balanceOf(address owner) virtual public view returns (uint256); function borrowBalanceOf(address account) virtual public view returns (uint256); function pause(bool supplyPaused, bool transferPaused, bool withdrawPaused, bool absorbPaused, bool buyPaused) virtual external; function isSupplyPaused() virtual public view returns (bool); function isTransferPaused() virtual public view returns (bool); function isWithdrawPaused() virtual public view returns (bool); function isAbsorbPaused() virtual public view returns (bool); function isBuyPaused() virtual public view returns (bool); function accrueAccount(address account) virtual external; function getSupplyRate(uint utilization) virtual public view returns (uint64); function getBorrowRate(uint utilization) virtual public view returns (uint64); function getUtilization() virtual public view returns (uint); function governor() virtual external view returns (address); function pauseGuardian() virtual external view returns (address); function baseToken() virtual external view returns (address); function baseTokenPriceFeed() virtual external view returns (address); function extensionDelegate() virtual external view returns (address); /// @dev uint64 function supplyKink() virtual external view returns (uint); /// @dev uint64 function supplyPerSecondInterestRateSlopeLow() virtual external view returns (uint); /// @dev uint64 function supplyPerSecondInterestRateSlopeHigh() virtual external view returns (uint); /// @dev uint64 function supplyPerSecondInterestRateBase() virtual external view returns (uint); /// @dev uint64 function borrowKink() virtual external view returns (uint); /// @dev uint64 function borrowPerSecondInterestRateSlopeLow() virtual external view returns (uint); /// @dev uint64 function borrowPerSecondInterestRateSlopeHigh() virtual external view returns (uint); /// @dev uint64 function borrowPerSecondInterestRateBase() virtual external view returns (uint); /// @dev uint64 function storeFrontPriceFactor() virtual external view returns (uint); /// @dev uint64 function baseScale() virtual external view returns (uint); /// @dev uint64 function trackingIndexScale() virtual external view returns (uint); /// @dev uint64 function baseTrackingSupplySpeed() virtual external view returns (uint); /// @dev uint64 function baseTrackingBorrowSpeed() virtual external view returns (uint); /// @dev uint104 function baseMinForRewards() virtual external view returns (uint); /// @dev uint104 function baseBorrowMin() virtual external view returns (uint); /// @dev uint104 function targetReserves() virtual external view returns (uint); function numAssets() virtual external view returns (uint8); function decimals() virtual external view returns (uint8); function initializeStorage() virtual external; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.15; /** * @title Compound's Comet Math Contract * @dev Pure math functions * @author Compound */ contract CometMath { /** Custom errors **/ error InvalidUInt64(); error InvalidUInt104(); error InvalidUInt128(); error InvalidInt104(); error InvalidInt256(); error NegativeNumber(); function safe64(uint n) internal pure returns (uint64) { if (n > type(uint64).max) revert InvalidUInt64(); return uint64(n); } function safe104(uint n) internal pure returns (uint104) { if (n > type(uint104).max) revert InvalidUInt104(); return uint104(n); } function safe128(uint n) internal pure returns (uint128) { if (n > type(uint128).max) revert InvalidUInt128(); return uint128(n); } function signed104(uint104 n) internal pure returns (int104) { if (n > uint104(type(int104).max)) revert InvalidInt104(); return int104(n); } function signed256(uint256 n) internal pure returns (int256) { if (n > uint256(type(int256).max)) revert InvalidInt256(); return int256(n); } function unsigned104(int104 n) internal pure returns (uint104) { if (n < 0) revert NegativeNumber(); return uint104(n); } function unsigned256(int256 n) internal pure returns (uint256) { if (n < 0) revert NegativeNumber(); return uint256(n); } function toUInt8(bool x) internal pure returns (uint8) { return x ? 1 : 0; } function toBool(uint8 x) internal pure returns (bool) { return x != 0; } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.15; /** * @title Compound's Comet Storage Interface * @dev Versions can enforce append-only storage slots via inheritance. * @author Compound */ contract CometStorage { // 512 bits total = 2 slots struct TotalsBasic { // 1st slot uint64 baseSupplyIndex; uint64 baseBorrowIndex; uint64 trackingSupplyIndex; uint64 trackingBorrowIndex; // 2nd slot uint104 totalSupplyBase; uint104 totalBorrowBase; uint40 lastAccrualTime; uint8 pauseFlags; } struct TotalsCollateral { uint128 totalSupplyAsset; uint128 _reserved; } struct UserBasic { int104 principal; uint64 baseTrackingIndex; uint64 baseTrackingAccrued; uint16 assetsIn; uint8 _reserved; } struct UserCollateral { uint128 balance; uint128 _reserved; } struct LiquidatorPoints { uint32 numAbsorbs; uint64 numAbsorbed; uint128 approxSpend; uint32 _reserved; } /// @dev Aggregate variables tracked for the entire market uint64 internal baseSupplyIndex; uint64 internal baseBorrowIndex; uint64 internal trackingSupplyIndex; uint64 internal trackingBorrowIndex; uint104 internal totalSupplyBase; uint104 internal totalBorrowBase; uint40 internal lastAccrualTime; uint8 internal pauseFlags; /// @notice Aggregate variables tracked for each collateral asset mapping(address => TotalsCollateral) public totalsCollateral; /// @notice Mapping of users to accounts which may be permitted to manage the user account mapping(address => mapping(address => bool)) public isAllowed; /// @notice The next expected nonce for an address, for validating authorizations via signature mapping(address => uint) public userNonce; /// @notice Mapping of users to base principal and other basic data mapping(address => UserBasic) public userBasic; /// @notice Mapping of users to collateral data per collateral asset mapping(address => mapping(address => UserCollateral)) public userCollateral; /// @notice Mapping of magic liquidator points mapping(address => LiquidatorPoints) public liquidatorPoints; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.15; /** * @title IERC20NonStandard * @dev Version of ERC20 with no return values for `approve`, `transfer`, and `transferFrom` * See https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca */ interface IERC20NonStandard { function name() external view returns (string memory); function symbol() external view returns (string memory); function decimals() external view returns (uint8); /** * @notice Approve `spender` to transfer up to `amount` from `src` * @dev This will overwrite the approval amount for `spender` * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) * @param spender The address of the account which may transfer tokens * @param amount The number of tokens that are approved (-1 means infinite) */ function approve(address spender, uint256 amount) external; /** * @notice Transfer `value` tokens from `msg.sender` to `to` * @param to The address of the destination account * @param value The number of tokens to transfer */ function transfer(address to, uint256 value) external; /** * @notice Transfer `value` tokens from `from` to `to` * @param from The address of the source account * @param to The address of the destination account * @param value The number of tokens to transfer */ function transferFrom(address from, address to, uint256 value) external; /** * @notice Gets the balance of the specified address * @param account The address from which the balance will be retrieved */ function balanceOf(address account) external view returns (uint256); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/MerkleProof.sol) pragma solidity 0.8.15; /** * @dev These functions deal with verification of Merkle Tree proofs. * * The tree and the proofs can be generated using our * https://github.com/OpenZeppelin/merkle-tree[JavaScript library]. * You will find a quickstart guide in the readme. * * WARNING: You should avoid using leaf values that are 64 bytes long prior to * hashing, or use a hash function other than keccak256 for hashing leaves. * This is because the concatenation of a sorted pair of internal nodes in * the Merkle tree could be reinterpreted as a leaf value. * OpenZeppelin's JavaScript library generates Merkle trees that are safe * against this attack out of the box. */ library MerkleProof { /** *@dev The multiproof provided is not valid. */ error MerkleProofInvalidMultiproof(); /** * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree * defined by `root`. For this, a `proof` must be provided, containing * sibling hashes on the branch from the leaf to the root of the tree. Each * pair of leaves and each pair of pre-images are assumed to be sorted. */ function verify(bytes32[] memory proof, bytes32 root, bytes32 leaf) internal pure returns (bool) { return processProof(proof, leaf) == root; } /** * @dev Calldata version of {verify} */ function verifyCalldata(bytes32[] calldata proof, bytes32 root, bytes32 leaf) internal pure returns (bool) { return processProofCalldata(proof, leaf) == root; } /** * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt * hash matches the root of the tree. When processing the proof, the pairs * of leafs & pre-images are assumed to be sorted. */ function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) { bytes32 computedHash = leaf; for (uint256 i = 0; i < proof.length; i++) { computedHash = _hashPair(computedHash, proof[i]); } return computedHash; } /** * @dev Calldata version of {processProof} */ function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) { bytes32 computedHash = leaf; for (uint256 i = 0; i < proof.length; i++) { computedHash = _hashPair(computedHash, proof[i]); } return computedHash; } /** * @dev Returns true if the `leaves` can be simultaneously proven to be a part of a Merkle tree defined by * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}. * * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details. */ function multiProofVerify( bytes32[] memory proof, bool[] memory proofFlags, bytes32 root, bytes32[] memory leaves ) internal pure returns (bool) { return processMultiProof(proof, proofFlags, leaves) == root; } /** * @dev Calldata version of {multiProofVerify} * * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details. */ function multiProofVerifyCalldata( bytes32[] calldata proof, bool[] calldata proofFlags, bytes32 root, bytes32[] memory leaves ) internal pure returns (bool) { return processMultiProofCalldata(proof, proofFlags, leaves) == root; } /** * @dev Returns the root of a tree reconstructed from `leaves` and sibling nodes in `proof`. The reconstruction * proceeds by incrementally reconstructing all inner nodes by combining a leaf/inner node with either another * leaf/inner node or a proof sibling node, depending on whether each `proofFlags` item is true or false * respectively. * * CAUTION: Not all Merkle trees admit multiproofs. To use multiproofs, it is sufficient to ensure that: 1) the tree * is complete (but not necessarily perfect), 2) the leaves to be proven are in the opposite order they are in the * tree (i.e., as seen from right to left starting at the deepest layer and continuing at the next layer). */ function processMultiProof( bytes32[] memory proof, bool[] memory proofFlags, bytes32[] memory leaves ) internal pure returns (bytes32 merkleRoot) { // This function rebuilds the root hash by traversing the tree up from the leaves. The root is rebuilt by // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of // the Merkle tree. uint256 leavesLen = leaves.length; uint256 proofLen = proof.length; uint256 totalHashes = proofFlags.length; // Check proof validity. if (leavesLen + proofLen != totalHashes + 1) { revert MerkleProofInvalidMultiproof(); } // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop". bytes32[] memory hashes = new bytes32[](totalHashes); uint256 leafPos = 0; uint256 hashPos = 0; uint256 proofPos = 0; // At each step, we compute the next hash using two values: // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we // get the next hash. // - depending on the flag, either another value from the "main queue" (merging branches) or an element from the // `proof` array. for (uint256 i = 0; i < totalHashes; i++) { bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]; bytes32 b = proofFlags[i] ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]) : proof[proofPos++]; hashes[i] = _hashPair(a, b); } if (totalHashes > 0) { if (proofPos != proofLen) { revert MerkleProofInvalidMultiproof(); } unchecked { return hashes[totalHashes - 1]; } } else if (leavesLen > 0) { return leaves[0]; } else { return proof[0]; } } /** * @dev Calldata version of {processMultiProof}. * * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details. */ function processMultiProofCalldata( bytes32[] calldata proof, bool[] calldata proofFlags, bytes32[] memory leaves ) internal pure returns (bytes32 merkleRoot) { // This function rebuilds the root hash by traversing the tree up from the leaves. The root is rebuilt by // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of // the Merkle tree. uint256 leavesLen = leaves.length; uint256 proofLen = proof.length; uint256 totalHashes = proofFlags.length; // Check proof validity. if (leavesLen + proofLen != totalHashes + 1) { revert MerkleProofInvalidMultiproof(); } // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop". bytes32[] memory hashes = new bytes32[](totalHashes); uint256 leafPos = 0; uint256 hashPos = 0; uint256 proofPos = 0; // At each step, we compute the next hash using two values: // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we // get the next hash. // - depending on the flag, either another value from the "main queue" (merging branches) or an element from the // `proof` array. for (uint256 i = 0; i < totalHashes; i++) { bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]; bytes32 b = proofFlags[i] ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]) : proof[proofPos++]; hashes[i] = _hashPair(a, b); } if (totalHashes > 0) { if (proofPos != proofLen) { revert MerkleProofInvalidMultiproof(); } unchecked { return hashes[totalHashes - 1]; } } else if (leavesLen > 0) { return leaves[0]; } else { return proof[0]; } } /** * @dev Sorts the pair (a, b) and hashes the result. */ function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) { return a < b ? _efficientHash(a, b) : _efficientHash(b, a); } /** * @dev Implementation of keccak256(abi.encode(a, b)) that doesn't allocate or expand memory. */ function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) { /// @solidity memory-safe-assembly assembly { mstore(0x00, a) mstore(0x20, b) value := keccak256(0x00, 0x40) } } }
{ "optimizer": { "enabled": true, "runs": 1, "details": { "yulDetails": { "optimizerSteps": "dhfoDgvulfnTUtnIf [xa[r]scLM cCTUtTOntnfDIul Lcul Vcul [j] Tpeul xa[rul] xa[r]cL gvif CTUca[r]LsTOtfDnca[r]Iulc] jmul[jul] VcTOcul jmul" } } }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "viaIR": true, "libraries": {} }
Contract ABI
API[{"inputs":[{"internalType":"address","name":"governor_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"BadData","type":"error"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"CampaignEnded","type":"error"},{"inputs":[],"name":"InvalidProof","type":"error"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"InvalidUint128","type":"error"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"NotANewMember","type":"error"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"NotPermitted","type":"error"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"NotSupported","type":"error"},{"inputs":[],"name":"NullGovernor","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"campaignId","type":"uint256"},{"indexed":true,"internalType":"address","name":"comet","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"multiplier","type":"uint256"}],"name":"ConfigUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldGovernor","type":"address"},{"indexed":true,"internalType":"address","name":"newGovernor","type":"address"}],"name":"GovernorTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"comet","type":"address"},{"indexed":false,"internalType":"uint256","name":"campaignId","type":"uint256"}],"name":"NewCampaign","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"comet","type":"address"},{"indexed":false,"internalType":"bytes32","name":"finishRoot","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"campaignId","type":"uint256"}],"name":"NewCampaignFinishRoot","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"campaignId","type":"uint256"},{"indexed":true,"internalType":"address","name":"comet","type":"address"},{"indexed":true,"internalType":"address","name":"src","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RewardClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"campaignId","type":"uint256"},{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"comet","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RewardsClaimedSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TokenWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TransferOutFailed","type":"event"},{"inputs":[],"name":"MAX_CAMPAIGN_DURATION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"campaigns","outputs":[{"internalType":"bytes32","name":"startRoot","type":"bytes32"},{"internalType":"bytes32","name":"finishRoot","type":"bytes32"},{"internalType":"uint256","name":"finishTimestamp","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"comet","type":"address"},{"internalType":"uint256","name":"campaignId","type":"uint256"},{"internalType":"address","name":"src","type":"address"},{"internalType":"bool","name":"shouldAccrue","type":"bool"},{"components":[{"internalType":"uint256","name":"startIndex","type":"uint256"},{"internalType":"uint256","name":"finishIndex","type":"uint256"},{"internalType":"uint256","name":"startAccrued","type":"uint256"},{"internalType":"uint256","name":"finishAccrued","type":"uint256"},{"internalType":"bytes32[]","name":"startMerkleProof","type":"bytes32[]"},{"internalType":"bytes32[]","name":"finishMerkleProof","type":"bytes32[]"}],"internalType":"struct CometRewardsV2.Proofs","name":"proofs","type":"tuple"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"comet","type":"address"},{"internalType":"uint256[]","name":"campaignIds","type":"uint256[]"},{"internalType":"address","name":"src","type":"address"},{"internalType":"bool","name":"shouldAccrue","type":"bool"},{"components":[{"internalType":"uint256","name":"startIndex","type":"uint256"},{"internalType":"uint256","name":"finishIndex","type":"uint256"},{"internalType":"uint256","name":"startAccrued","type":"uint256"},{"internalType":"uint256","name":"finishAccrued","type":"uint256"},{"internalType":"bytes32[]","name":"startMerkleProof","type":"bytes32[]"},{"internalType":"bytes32[]","name":"finishMerkleProof","type":"bytes32[]"}],"internalType":"struct CometRewardsV2.Proofs[]","name":"proofs","type":"tuple[]"}],"name":"claimBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"comet","type":"address"},{"internalType":"uint256[]","name":"campaignIDs","type":"uint256[]"},{"internalType":"address","name":"src","type":"address"},{"internalType":"bool","name":"shouldAccrue","type":"bool"},{"internalType":"address[2][]","name":"neighbors","type":"address[2][]"},{"components":[{"components":[{"internalType":"uint256","name":"startIndex","type":"uint256"},{"internalType":"uint256","name":"finishIndex","type":"uint256"},{"internalType":"uint256","name":"startAccrued","type":"uint256"},{"internalType":"uint256","name":"finishAccrued","type":"uint256"},{"internalType":"bytes32[]","name":"startMerkleProof","type":"bytes32[]"},{"internalType":"bytes32[]","name":"finishMerkleProof","type":"bytes32[]"}],"internalType":"struct CometRewardsV2.Proofs[2]","name":"proofs","type":"tuple[2]"}],"internalType":"struct CometRewardsV2.MultiProofs[]","name":"multiProofs","type":"tuple[]"},{"components":[{"internalType":"uint256","name":"finishIndex","type":"uint256"},{"internalType":"uint256","name":"finishAccrued","type":"uint256"},{"internalType":"bytes32[]","name":"finishMerkleProof","type":"bytes32[]"}],"internalType":"struct CometRewardsV2.FinishProof[]","name":"finishProofs","type":"tuple[]"}],"name":"claimBatchForNewMember","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"comet","type":"address"},{"internalType":"uint256","name":"campaignId","type":"uint256"},{"internalType":"address","name":"src","type":"address"},{"internalType":"bool","name":"shouldAccrue","type":"bool"},{"internalType":"address[2]","name":"neighbors","type":"address[2]"},{"components":[{"internalType":"uint256","name":"startIndex","type":"uint256"},{"internalType":"uint256","name":"finishIndex","type":"uint256"},{"internalType":"uint256","name":"startAccrued","type":"uint256"},{"internalType":"uint256","name":"finishAccrued","type":"uint256"},{"internalType":"bytes32[]","name":"startMerkleProof","type":"bytes32[]"},{"internalType":"bytes32[]","name":"finishMerkleProof","type":"bytes32[]"}],"internalType":"struct CometRewardsV2.Proofs[2]","name":"proofs","type":"tuple[2]"},{"components":[{"internalType":"uint256","name":"finishIndex","type":"uint256"},{"internalType":"uint256","name":"finishAccrued","type":"uint256"},{"internalType":"bytes32[]","name":"finishMerkleProof","type":"bytes32[]"}],"internalType":"struct CometRewardsV2.FinishProof","name":"finishProof","type":"tuple"}],"name":"claimForNewMember","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"comet","type":"address"},{"internalType":"uint256","name":"campaignId","type":"uint256"},{"internalType":"address","name":"src","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"shouldAccrue","type":"bool"},{"components":[{"internalType":"uint256","name":"startIndex","type":"uint256"},{"internalType":"uint256","name":"finishIndex","type":"uint256"},{"internalType":"uint256","name":"startAccrued","type":"uint256"},{"internalType":"uint256","name":"finishAccrued","type":"uint256"},{"internalType":"bytes32[]","name":"startMerkleProof","type":"bytes32[]"},{"internalType":"bytes32[]","name":"finishMerkleProof","type":"bytes32[]"}],"internalType":"struct CometRewardsV2.Proofs","name":"proofs","type":"tuple"}],"name":"claimTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"comet","type":"address"},{"internalType":"uint256[]","name":"campaignIds","type":"uint256[]"},{"internalType":"address","name":"src","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"shouldAccrue","type":"bool"},{"components":[{"internalType":"uint256","name":"startIndex","type":"uint256"},{"internalType":"uint256","name":"finishIndex","type":"uint256"},{"internalType":"uint256","name":"startAccrued","type":"uint256"},{"internalType":"uint256","name":"finishAccrued","type":"uint256"},{"internalType":"bytes32[]","name":"startMerkleProof","type":"bytes32[]"},{"internalType":"bytes32[]","name":"finishMerkleProof","type":"bytes32[]"}],"internalType":"struct CometRewardsV2.Proofs[]","name":"proofs","type":"tuple[]"}],"name":"claimToBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"comet","type":"address"},{"internalType":"uint256[]","name":"campaignIDs","type":"uint256[]"},{"internalType":"address","name":"src","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"shouldAccrue","type":"bool"},{"internalType":"address[2][]","name":"neighbors","type":"address[2][]"},{"components":[{"components":[{"internalType":"uint256","name":"startIndex","type":"uint256"},{"internalType":"uint256","name":"finishIndex","type":"uint256"},{"internalType":"uint256","name":"startAccrued","type":"uint256"},{"internalType":"uint256","name":"finishAccrued","type":"uint256"},{"internalType":"bytes32[]","name":"startMerkleProof","type":"bytes32[]"},{"internalType":"bytes32[]","name":"finishMerkleProof","type":"bytes32[]"}],"internalType":"struct CometRewardsV2.Proofs[2]","name":"proofs","type":"tuple[2]"}],"internalType":"struct CometRewardsV2.MultiProofs[]","name":"multiProofs","type":"tuple[]"},{"components":[{"internalType":"uint256","name":"finishIndex","type":"uint256"},{"internalType":"uint256","name":"finishAccrued","type":"uint256"},{"internalType":"bytes32[]","name":"finishMerkleProof","type":"bytes32[]"}],"internalType":"struct CometRewardsV2.FinishProof[]","name":"finishProofs","type":"tuple[]"}],"name":"claimToBatchForNewMember","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"comet","type":"address"},{"internalType":"uint256","name":"campaignId","type":"uint256"},{"internalType":"address","name":"src","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bool","name":"shouldAccrue","type":"bool"},{"internalType":"address[2]","name":"neighbors","type":"address[2]"},{"components":[{"internalType":"uint256","name":"startIndex","type":"uint256"},{"internalType":"uint256","name":"finishIndex","type":"uint256"},{"internalType":"uint256","name":"startAccrued","type":"uint256"},{"internalType":"uint256","name":"finishAccrued","type":"uint256"},{"internalType":"bytes32[]","name":"startMerkleProof","type":"bytes32[]"},{"internalType":"bytes32[]","name":"finishMerkleProof","type":"bytes32[]"}],"internalType":"struct CometRewardsV2.Proofs[2]","name":"proofs","type":"tuple[2]"},{"components":[{"internalType":"uint256","name":"finishIndex","type":"uint256"},{"internalType":"uint256","name":"finishAccrued","type":"uint256"},{"internalType":"bytes32[]","name":"finishMerkleProof","type":"bytes32[]"}],"internalType":"struct CometRewardsV2.FinishProof","name":"finishProof","type":"tuple"}],"name":"claimToForNewMember","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"comet","type":"address"}],"name":"getCometCampaignsInfo","outputs":[{"internalType":"bytes32[]","name":"startRoots","type":"bytes32[]"},{"internalType":"bytes32[]","name":"finishRoots","type":"bytes32[]"},{"internalType":"address[][]","name":"assets","type":"address[][]"},{"internalType":"uint256[]","name":"finishTimestamps","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"comet","type":"address"},{"internalType":"uint256","name":"campaignId","type":"uint256"},{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"startAccrued","type":"uint256"},{"internalType":"uint256","name":"finishAccrued","type":"uint256"},{"internalType":"bool","name":"shouldAccrue","type":"bool"}],"name":"getRewardsOwed","outputs":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"owed","type":"uint256"}],"internalType":"struct CometRewardsV2.RewardOwed","name":"","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"comet","type":"address"},{"internalType":"uint256","name":"campaignId","type":"uint256"},{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"startAccrued","type":"uint256"},{"internalType":"uint256","name":"finishAccrued","type":"uint256"},{"internalType":"bool","name":"shouldAccrue","type":"bool"}],"name":"getRewardsOwedBatch","outputs":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"owed","type":"uint256"}],"internalType":"struct CometRewardsV2.RewardOwed[]","name":"","type":"tuple[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"governor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"comet","type":"address"},{"internalType":"uint256","name":"campaignId","type":"uint256"}],"name":"rewardConfig","outputs":[{"internalType":"address[]","name":"","type":"address[]"},{"components":[{"internalType":"uint256","name":"multiplier","type":"uint256"},{"internalType":"uint128","name":"rescaleFactor","type":"uint128"},{"internalType":"bool","name":"shouldUpscale","type":"bool"}],"internalType":"struct CometRewardsV2.AssetConfig[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"comet","type":"address"},{"internalType":"uint256","name":"campaignId","type":"uint256"},{"internalType":"address","name":"token","type":"address"}],"name":"rewardConfigForToken","outputs":[{"components":[{"internalType":"uint256","name":"multiplier","type":"uint256"},{"internalType":"uint128","name":"rescaleFactor","type":"uint128"},{"internalType":"bool","name":"shouldUpscale","type":"bool"}],"internalType":"struct CometRewardsV2.AssetConfig","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"comet","type":"address"},{"internalType":"uint256","name":"campaignId","type":"uint256"},{"internalType":"address","name":"src","type":"address"},{"internalType":"address","name":"token","type":"address"}],"name":"rewardsClaimed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"comet","type":"address"},{"internalType":"uint256","name":"campaignId","type":"uint256"},{"internalType":"bytes32","name":"finishRoot","type":"bytes32"}],"name":"setCampaignFinishRoot","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"comet","type":"address"},{"internalType":"bytes32","name":"startRoot","type":"bytes32"},{"internalType":"address[]","name":"tokens","type":"address[]"},{"internalType":"uint256","name":"duration","type":"uint256"}],"name":"setNewCampaign","outputs":[{"internalType":"uint256","name":"campaignId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"comet","type":"address"},{"internalType":"bytes32","name":"startRoot","type":"bytes32"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"multiplier","type":"uint256"}],"internalType":"struct CometRewardsV2.TokenMultiplier[]","name":"assets","type":"tuple[]"},{"internalType":"uint256","name":"duration","type":"uint256"}],"name":"setNewCampaignWithCustomTokenMultiplier","outputs":[{"internalType":"uint256","name":"campaignId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"comet","type":"address"},{"internalType":"uint256","name":"campaignId","type":"uint256"},{"internalType":"address[]","name":"users","type":"address[]"},{"internalType":"address[][]","name":"tokens","type":"address[][]"},{"internalType":"uint256[][]","name":"claimedAmounts","type":"uint256[][]"}],"name":"setRewardsClaimed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newGovernor","type":"address"}],"name":"transferGovernor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"root","type":"bytes32"},{"internalType":"bytes32[]","name":"proofs","type":"bytes32[]"},{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint256","name":"accrued","type":"uint256"}],"name":"verifyProof","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawToken","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
608080604052346200009757601f620032a338819003918201601f19168301916001600160401b038311848410176200009c578084926020946040528339810103126200009757516001600160a01b03811690819003620000975780156200008557600080546001600160a01b0319169190911790556040516131f09081620000b38239f35b604051630d804a6760e41b8152600490fd5b600080fd5b634e487b7160e01b600052604160045260246000fdfe608080604052600436101561001357600080fd5b600090813560e01c90816301e3366714611a8557508063099cc91d146119555780630c340a241461192e57806311555dbc146118c05780631ae8b385146117b95780631d68b74d146116e25780632b8bbd0c1461160d5780634a18481a146115305780635e59ea90146113445780636a775f4f146110ea57806389a3284a146110445780638c7bc838146110265780639880dec214610fa3578063a62f91a614610f1e578063a9cdc9ee14610ce9578063ac80075014610c1e578063b8cc9ce614610b99578063bea0981214610af2578063c126fabe14610a82578063c7b33f4014610878578063d91c8e59146106b3578063e03e2f0014610573578063f1871f24146104495763ff5ad3991461012957600080fd5b346104465760c0366003190112610446576004356001600160a01b0381169003610441576044356024356001600160a01b03821682036104415760a435151560a43503610441576004356001600160a01b03168352600160205260408320541561041f576004356001600160a01b031683526001602052604083205481101561040d576004356001600160a01b031683526001602052604083206101cd9190611b5d565b50906002820154916101f76101e184611bf8565b936101ef6040519586611bbf565b808552611bf8565b601f1901845b8181106103e6575050600181015415806103dd575b610366575b60028101549160643591608435865b85811061027e578688604051918291602083016020845282518091526020604085019301915b81811061025a575050500390f35b9193509160206040826102706001948851611cc1565b01940191019184939261024c565b8061028f6103599260028601611d6a565b90549060039160018060a01b0391831b1c1690816000528501602052604060002060ff6001604051926102c3606085611bbf565b80548452015460018060801b038116602084015260801c161515604082015260018060a01b0387166000526004860160205260406000208260005260205261031660406000205491868a8a600435612f64565b908082111561035e5761032891611cf8565b60405191610337604084611bbf565b82526020820152610348828a611d28565b526103538189611d28565b50611d19565b610226565b505089610328565b6004356001600160a01b03163b156103ce578360405163bfe69c8d60e01b815260018060a01b038416600482015281816024818360018060a01b03600435165af180156103d2576103b9575b5050610217565b816103c391611bbf565b6103ce5783386103b2565b8380fd5b6040513d84823e3d90fd5b5060a435610212565b6020906040516103f7604082611bbf565b60008152600083820152828288010152016101fd565b60405163a554dcdf60e01b8152600490fd5b60405163a034dbb160e01b81528061043d8560048035908401612241565b0390fd5b600080fd5b80fd5b50346104465760c0366003190112610446576004356001600160a01b0380821690818303610441576001600160401b039160243583811161056f57610492903690600401611c0f565b604435928084168403610441576064359081168103610441576084359485151586036104415760a43590811161056b576104d0903690600401611b8f565b9490936020604051809263cde6804160e01b825281806104f4338860048401612241565b03915afa908115610560578991610532575b501561051a5761051596612dfa565b604051f35b6040516319b1d90760e31b8152336004820152602490fd5b610553915060203d8111610559575b61054b8183611bbf565b8101906122c4565b38610506565b503d610541565b6040513d8b823e3d90fd5b8780fd5b8580fd5b503461044657600319610120368201126106af576004356001600160a01b0381811692908383036104415760243590604435818116810361044157606435918216820361044157608435938415158503610441573660e41161056b5760e435966001600160401b03918289116106ab573660448a01116106ab57610104359283116106ab5760609083360301126106a757808952600160205260408920541561068b576020604051809263cde6804160e01b82528180610637338960048401612241565b03915afa90811561056057899161066d575b501561051a576106636105159760040160a486858a61255b565b50600401946127b8565b610685915060203d81116105595761054b8183611bbf565b38610649565b60405163a034dbb160e01b81528061043d8b8a60048401612241565b8880fd5b8980fd5b5080fd5b5034610446576040366003190112610446576001600160a01b039060043582811690819003610441578192915260016020928184526106f760243560408320611b5d565b509160028301805461070881611bf8565b946107166040519687611bbf565b818652601f1961072583611bf8565b01855b818110610853575050600390810190855b8381106107dd575050505061074d906122fd565b604051958695604087019060408852835180925260609183838a0195019187905b8282106107c3575050505086830382880152818087519485815201960194905b83821061079b5787870388f35b9185975082876107b18799849895979951611c9d565b0197019201879695939194929461078e565b8351811687528b9a5095850195928501929087019061076e565b80896107f161084993889d999b9c9d611d6a565b905490851b1c16600052838752604060002060ff8a60405192610815606085611bbf565b8054845201546001600160801b0381168a84015260801c161515604082015261083e828c611d28565b52610353818b611d28565b9897969498610739565b9880959798996108649493946122dc565b82828c010152019897969498929192610728565b50346104465760e036600319011261044657600435906001600160a01b03908183169081840361044157602435936044359380851694858103610441576064359182168083036104415760c43595861515870361044157604051966108de604089611bbf565b60008852600060208099015281875260018852604087205415610a66578187526001885260408720548a101561040d5761092360019a8389528b8a5260408920611b5d565b509389600052600385018952604060002060ff6040519c8d92610947606085611bbf565b80549384905201546001600160801b0381168c8f015260801c16151560408d015215610a4857506001840154159081610a40575b506109ec575b50916004604098926109b0946000520186528760002087600052865287600020549360a4359160843591612f64565b818111156109e4576109c29250611cf8565b905b8351926109d18585611bbf565b83528201526109e282518092611cc1565bf35b5050906109c4565b803b1561056f5785809160246040518094819363bfe69c8d60e01b83528760048401525af18015610a35571561098157610a27868092611bbf565b610a315738610981565b8480fd5b6040513d88823e3d90fd5b90503861097b565b60405163a034dbb160e01b815290819061043d908960048401612241565b60405163a034dbb160e01b81528061043d898960048401612241565b50346104465760031960a0368201126106af576004356001600160a01b0380821682036104415760443590811681036104415760643591821515830361044157608435936001600160401b03851161056f5760c0908536030112610a315761051593600401918060243592612a8b565b50346104465760a0366003190112610446576024356001600160401b0381116106af57610b23903690600401611b8f565b604435906001600160a01b038216820361044157602092610b8f92604051610b6881610b5a8882019460843590606435908761250d565b03601f198101835282611bbf565b519020604051858101918252858152610b82604082611bbf565b519020916004359161313c565b6040519015158152f35b5034610446576020366003190112610446576001600160a01b03600435818116908190036104415782549182169182330361051a578115610c0c5781604051937f6fadb1c244276388aee22be93b919985a18748c021e5d48553957a48101a25608686a36001600160a01b031916178255f35b604051630d804a6760e41b8152600490fd5b503461044657600319610100368201126106af576004356001600160a01b03808216908183036104415760243590604435908116810361044157606435928315158403610441573660c411610ce5576001600160401b039560c43591908783116106a7573660448401116106a75760e4359788116106a757606090883603011261056b5787526001602052604087205415610cc957610515956106638392600401608486858a61255b565b60405163a034dbb160e01b81528061043d898860048401612241565b8680fd5b50346104465760a0366003190112610446576004356001600160a01b0381168103610441576001600160401b03906044358281116103ce57610d2f903690600401611b8f565b909260643581811161056f57610d49903690600401611b8f565b9091608435908111610ce557610d63903690600401611b8f565b8754919690916001600160a01b0316330361051a5781850361040d5781830361040d576001600160a01b0386168852600160205260408820610da89060243590611b5d565b509188975b818910610dba5789604051f35b9091929394959697986002850154610dd38b8585612226565b9050810361040d57610de68b888a612226565b9190500361040d57805b610dfb8b8585612226565b9050811015610f045780898982610eed8f8f818e60048f8f8f8f86610eff9f808f8f9c610ecb96610e5196610e519f9e610ede9f610e628f610ebb99610e5c8f610e5193610e56610e518c610e5c9e81956121cd565b6121dd565b96612226565b906121cd565b7fa56b67569cae558523428bceed457ecebd24ee97a55b8161266bbf9d23c8e6026040610e948a610e5c8a8a8a612226565b81516024358152903560208201526001600160a01b039384169584169490931692a4612226565b359d6001600160a01b03946121cd565b1660005201602052604060002096612226565b6001600160a01b0394916121cd565b16600052602052604060002055611d19565b610df0565b5098610f1890989796959493929198611d19565b97610dad565b50346104465760a0366003190112610446576001600160a01b036004358181168103610441576001600160401b0391602435838111610a3157610f65903690600401611c0f565b916044359182168203610441576064359283151584036104415760843594851161056f5782610f9b610515963690600401611b8f565b949093612dfa565b5034610446576080366003190112610446576001600160a01b03906004358281169081900361044157604435908382168092036104415760643593841680940361044157826110019160049452600160205260406024359120611b5d565b5090600052016020526040600020906000526020526020604060002054604051908152f35b5034610446578060031936011261044657602060405162ed4e008152f35b5034610446576060366003190112610446576001600160a01b0360043581811690819003610441576044359182168092036104415760039261109c916110886122dc565b508152600160205260406024359120611b5d565b5090600052016020526060604060002060ff6001604051926110be8585611bbf565b80548452015460018060801b038116602084015260801c16151560408201526109e26040518092611c9d565b503461044657610100366003190112610446576001600160a01b036004358082169003610441576001600160401b036024358181116103ce57611131903690600401611c0f565b9082604435166044350361044157826064351660643503610441576084351515608435036104415760a435818111610a3157611171903690600401611c6d565b949060c4358381116113405761118b903690600401611b8f565b91909360e4359081116103ce576111a6903690600401611b8f565b90948887510361040d578387510361040d578187510361040d57876004351685526001602052604085205415611322576084356112c9575b845b87518110156112c35760405163cde6804160e01b81526020818061120a3360443560048401612241565b03818d600435165afa9081156112b8578791611299575b501561051a57806112658b6112458361123d611294968e611d28565b51928961225b565b611259611253858b8961226b565b8061228d565b9160443560043561255b565b5061128f611273828b611d28565b518861128084888d6122a2565b916064356044356004356127b8565b611d19565b6111e0565b6112b2915060203d6020116105595761054b8183611bbf565b38611221565b6040513d89823e3d90fd5b85604051f35b87600435163b15610a315760405163bfe69c8d60e01b8152886044351660048201528581602481838d600435165af18015610a355790869161130d575b50506111de565b8161131791611bbf565b610a31578438611306565b60405163a034dbb160e01b81528061043d8760048035908401612241565b8280fd5b50346104465760e0366003190112610446576004356001600160a01b03818116918281036103ce576001600160401b039260243584811161056f5761138d903690600401611c0f565b92604435908116808203610ce55760643594851515860361056b576084358781116106a7576113c0903690600401611c6d565b60a43589811161152c576113d8903690600401611b8f565b91909960c435908111611528576113f3903690600401611b8f565b9590978286510361040d578386510361040d578686510361040d578c9a818c52604060019c8d60205220541561150a57908d92916114b4575b5050508a8981905b61143f575b50604051f35b85518110156114af5761128f8a6114a7938b8f8c6114a1878e61149a8f8f908f8f889987948a8f9361125388611494976114888261148e95611481828e611d28565b519861225b565b9661226b565b9361255b565b50611d28565b51956122a2565b946127b8565b8b908a611434565b611439565b803b156113405760248392604051948593849263bfe69c8d60e01b845260048401525af180156114ff576114eb575b808c9161142c565b8b6114f8919c929c611bbf565b99386114e3565b6040513d8e823e3d90fd5b6044828f6040519163a034dbb160e01b835260048301526024820152fd5b8b80fd5b8a80fd5b5034610446576080366003190112610446576001600160a01b036004358181168103611340576044356001600160401b0381116103ce57366023820112156103ce5780600401359061158182611bf8565b9161158f6040519384611bbf565b80835260209460248685019260061b8401019236841161056b57602401915b8383106115ce57866115c6606435876024358a611d9d565b604051908152f35b60408336031261056b57604051906115e7604083611bbf565b83359083821682036106ab578289926040945282860135838201528152019201916115ae565b50346104465760031960c0368201126106af576004356001600160a01b0381811691828103610a315760443591808316830361056f57606435908116810361056f57608435938415158503610ce55760a435956001600160401b03871161056b5760c0908736030112610ce5576020604051809263cde6804160e01b8252818061169b338a60048401612241565b03915afa9081156112b85787916116c4575b501561051a57610515946004019260243592612a8b565b6116dc915060203d81116105595761054b8183611bbf565b386116ad565b5034610446576060366003190112610446576001600160a01b0360043581811690819003611340576024359060443592845416330361051a57821561040d57808452600160205260408420541561179b578084526001602052604084205482101561040d57600191611793917f86dc3da9b2bb25c8eea35197f01417ff78934ff53c99d1ace0375462e9c46c496060604051838152876020820152846040820152a185528260205260408520611b5d565b500155604051f35b604490846040519163a034dbb160e01b835260048301526024820152fd5b503461044657608036600319011261044657600435906001600160a01b0380831683036106af576044356001600160401b038111611340576117ff903690600401611b8f565b61180b81939293611bf8565b936118196040519586611bbf565b818552601f1961182883611bf8565b01815b81811061189b5750505b81811061184e5760206115c6606435876024358a611d9d565b80611860610e516118969385886121cd565b8460405191611870604084611bbf565b168152670de0b6b3a7640000602082015261188b8288611d28565b526103538187611d28565b611835565b6020906040516118ac604082611bbf565b848152828581830152828a0101520161182b565b5034610446576040366003190112610446576004356001600160a01b03811691908290036104465760243591815260016020526040812090815483101561044657606061190d8484611b5d565b50805490600560018201549101549060405192835260208301526040820152f35b5034610446578060031936011261044657546040516001600160a01b039091168152602090f35b50346104465760209081600319360112610446576001600160a01b0391600435838116810361134057916119b761198f6119aa9594612389565b9592969160409491945198899860808a5260808a0190611b29565b90888203858a0152611b29565b868103604088015283519081815283810184808460051b84010196019387925b848410611a1f5750505050505084820360608601528080855193848152019401925b828110611a0857505050500390f35b8351855286955093810193928101926001016119f9565b919395979688919395999a50601f1983820301855289519082808351928381520192019089905b808210611a6a5750505090806001929a0194019401918a99989697959394916119d7565b9193806001929488875116815201940192018a939291611a46565b9050346106af5760603660031901126106af576004356001600160a01b0381811691828103610a31576024359082821694858303610ce557604435938754163303611b145750611ad6918391613059565b611ae1575b83604051f35b60207f8210728e7c071f615b840ee026032693858fbcd5e5359e67e438c890f59e562091604051908152a3388080611adb565b6319b1d90760e31b8152336004820152602490fd5b90815180825260208080930193019160005b828110611b49575050505090565b835185529381019392810192600101611b3b565b8054821015611b79576000526006602060002091020190600090565b634e487b7160e01b600052603260045260246000fd5b9181601f84011215610441578235916001600160401b038311610441576020808501948460051b01011161044157565b601f909101601f19168101906001600160401b03821190821017611be257604052565b634e487b7160e01b600052604160045260246000fd5b6001600160401b038111611be25760051b60200190565b81601f8201121561044157803591611c2683611bf8565b92611c346040519485611bbf565b808452602092838086019260051b820101928311610441578301905b828210611c5e575050505090565b81358152908301908301611c50565b9181601f84011215610441578235916001600160401b038311610441576020808501948460061b01011161044157565b805182526020808201516001600160801b0316908301526040908101511515910152565b80516001600160a01b03168252602090810151910152565b9081602091031261044157516001600160401b03811681036104415790565b818110611d03570390565b634e487b7160e01b600052601160045260246000fd5b6000198114611d035760010190565b8051821015611b795760209160051b010190565b6001600160801b0391821691908215611d5457160490565b634e487b7160e01b600052601260045260246000fd5b8054821015611b795760005260206000200190600090565b6001600160a01b039091168152602081019190915260400190565b91909260018060a01b0390600082815416330361051a57851561040d5783511561040d5762ed4e00821161040d57604080516351076acb60e11b815296909486851694600492916020808b86818b5afa9a8b156121c357869b612194575b5087865260019a8b8252898720805490600160401b8210156121815790611e26918e82018155611b5d565b50988088528c83528a882054958d871061216e578a556000199095019b9487865b611eaf575b5050505050505082194211611e9c5750504201600590910155517fc0b232d318f3e59a207ea5731c6a79d5ae9dd78078bad277630b16a59f797422918190611e9690859083611d82565b0390a190565b634e487b7160e01b825260119052602490fd5b84518110156121695783611ec38287611d28565b510151156121595787848d88611ed9858a611d28565b51511690519283809263313ce56760e01b82525afa801561214f578a90612117575b60ff915016604d8111612104576001600160801b0390600a0a8181116120ee578f91898f8f818f8d928d8b7f809f126df209d3752da0eebe9cd87056d63a3cd3297d3a8756a8b630dc5578c88f9b978d988d80611f6a879f8f169c8c611f61828b611d28565b51511698611d28565b510151908351928352820152a36001600160401b038c1693878a8c8b8989111561207a5791611fa260039798999a92611fab94611d28565b51015198611d3c565b9a865197611fba60608a611bbf565b885287019a168a52611fd28b8688019a868c52611d28565b5151168352018b52209051815593519301805492516001600160881b0319909316919093161790151560801b60ff60801b161790555b856120138287611d28565b51511660028c01805490600160401b82101561206757916120428261205d948c809b9a99989795018155611d6a565b819291549060031b8b811b9283911b16911916179055611d19565b9091929394611e47565b634e487b7160e01b8c5260418b5260248cfd5b91611fa260039798999261208d94611d28565b9a86519761209c60608a611bbf565b885287019a168a526120b48b8688019a898c52611d28565b5151168352018b52209051815593519301805492516001600160881b0319909316919093161790151560801b60ff60801b16179055612008565b896024918f51916352a4b44160e01b8352820152fd5b634e487b7160e01b8a526011895260248afd5b508481813d8311612148575b61212d8183611bbf565b810103126106ab575160ff811681036106ab5760ff90611efb565b503d612123565b8d513d8c823e3d90fd5b8b5163a554dcdf60e01b81528890fd5b611e4c565b634e487b7160e01b895260118852602489fd5b634e487b7160e01b895260418852602489fd5b816121b5929c503d8d116121bc575b6121ad8183611bbf565b810190611cd9565b9938611dfb565b503d6121a3565b89513d88823e3d90fd5b9190811015611b795760051b0190565b356001600160a01b03811681036104415790565b903590601e198136030182121561044157018035906001600160401b03821161044157602001918160051b3603831361044157565b90821015611b795761223d9160051b8101906121f1565b9091565b6001600160a01b0391821681529116602082015260400190565b9190811015611b795760061b0190565b9190811015611b795760051b81013590601e1981360301821215610441570190565b903590603e1981360301821215610441570190565b9190811015611b795760051b81013590605e1981360301821215610441570190565b90816020910312610441575180151581036104415790565b604051906122eb606083611bbf565b60006040838281528260208201520152565b9060405191828154918282526020928383019160005283600020936000905b8282106123345750505061233292500383611bbf565b565b85546001600160a01b03168452600195860195889550938101939091019061231c565b9061236182611bf8565b61236e6040519182611bbf565b828152809261237f601f1991611bf8565b0190602036910137565b60018060a01b031660009181835260019160209183835260409384862054156124fd578286528084526124056123c186882054612357565b968481528286526123d487822054612357565b809786835284885280832054926123ea84611bf8565b936123f783519586611bbf565b808552601f19958691611bf8565b0189825b8281106124ea575050508398888252868152828220549561244161242c88611bf8565b976124398651998a611bbf565b808952611bf8565b01368288013785988c8884905b61245f575b50505050505050505050565b828552898452858520548110156124e55760056124dc928b9885885289875261248a848a8a20611b5d565b509161249885845492611d28565b526124a7848b84015492611d28565b526124b4600282016122fd565b6124be848c611d28565b526124c9838b611d28565b5001546124d6828b611d28565b52611d19565b8d908d9661244e565b612453565b60608782018301528c95508b9101612409565b5060609450849350839250829150565b604091949392606082019560018060a01b0316825260208201520152565b90359060be1981360301821215610441570190565b6002821015611b79576125589160051b81019061252b565b90565b939092919360018060a01b0380911694600090868252600196602093888552604097888520541561277a5782855289865288852054841015612769578190816125a38a6121dd565b911691829116109182612752575b50501561271a576125c28886612540565b356125cd8487612540565b35108061272b575b1561271a57906125ec918352878452868320611b5d565b50926126756126086125fe8484612540565b60808101906121f1565b95548096612615896121dd565b8a61262b6126238989612540565b359888612540565b0135966126408c519889928b8401948561250d565b0396612654601f1998898101835282611bbf565b5190208a5188810191825288815261266c8c82611bbf565b5190209261313c565b1561270957918091836126d761269f6126966125fe8c6126f09b9a99612540565b969098016121dd565b92896126b68c6126af8187612540565b3595612540565b0135926126cb8b51948592888401978861250d565b03908101835282611bbf565b51902090865190808201928352815261266c8782611bbf565b156126f9575090565b516309bde33960e01b8152600490fd5b85516309bde33960e01b8152600490fd5b865163a554dcdf60e01b8152600490fd5b508761274c61273a8288612540565b356127458689612540565b3590611cf8565b146125d5565b9091506127608689016121dd565b161138806125b1565b885163a554dcdf60e01b8152600490fd5b604483868b519163a034dbb160e01b835260048301526024820152fd5b9081526001600160a01b039091166020820152604081019190915260600190565b929095949193600060018060a01b03851681526001956020928784526127e18560408520611b5d565b508881018054919290918c8115612a615761283e91612824898c61280860408201826121f1565b939095610b5a604051938492868401968201359135908761250d565b5190206040518b81019182528b815261266c604082611bbf565b15612a4f575b6129d9575b88999a84995b612861575b5050505050505050505050565b6002830180548b10156129d3578a8a8a8a8f9e8f8a8a8a8f948f948c8c6128e98461294c9f6129359661289391611d6a565b9390549360039460018060a01b0391861b1c166000528389018c5260ff604060002096604051976128c560608a611bbf565b8054895201546001600160801b0381168e89015260801c1615156040870152611d6a565b60018060a09493941b039254911b1c16968860018060a01b0383169b8c60005260048801825260406000208a6000528252604060002054965415156000146129ca570135915b8c612f64565b90808211612952575b505050505050505050611d19565b9961284f565b61295c9082611cf8565b90612968828587613059565b1561293e5760008051602061319b8339815191529560046129b9948a600052018152604060002090866000525260406000205560405193849360018060a01b03169860018060a01b03169684612797565b0390a48a388a8a828a8a828061293e565b5050809161292f565b50612854565b6001600160a01b0388163b156103ce5760405163bfe69c8d60e01b81526001600160a01b03808d166004830152909b9085908d90602490829084908e165af19b8c15612a44578a9b9c612a30575b509a9950612849565b85612a3d91969296611bbf565b9338612a27565b6040513d87823e3d90fd5b6040516309bde33960e01b8152600490fd5b505060058301544211156128445760405163e8c6942b60e01b81528061043d898c60048401611d82565b6001600160a01b038116600090815260016020526040812054929591949193909215612dd2576001600160a01b03851683526001602052604083205482101561040d576001600160a01b0385168352600160205260408320612aee908390611b5d565b5096612b51612b0060808701876121f1565b91908a54604051938b85612b218c602083019360408201359135908561250d565b0395612b35601f1997888101835282611bbf565b519020604051602081019182526020815261266c604082611bbf565b15612a4f576001890154908115612da857612b9a91612b358a6126cb612b7a60a08c018c6121f1565b9390958c604051938491602083019660206060830135920135908861250d565b15612a4f575b612d3c575b825b6002880154811015612d32578087878a87612bc8612c899660028401611d6a565b92905460039160018060a01b038286851b1c16600052828101602052612c738d60406000209060ff600160405193612c01606086611bbf565b80548552015460018060801b038116602085015260801c161515604083015260018060a01b038a1660005260048401602052604060002060018060a01b03868a891b1c166000526020526040600020549660018501541515600014612d29575060406060820135915b01358a8a612f64565b93808511612c8e575b5050505050505050611d19565b612ba7565b612c989085611cf8565b612cb1818c88871b86901c6001600160a01b0316613059565b15612c7c576001600160a01b039788166000818152600493909301602090815260408085209890961b9490941c891680845296909352908390209390935590518886169591949091169260008051602061319b833981519152928291612d1991908c84612797565b0390a48787388080808e81612c7c565b60409091612c6a565b5050505050505050565b6001600160a01b0385163b156113405760405163bfe69c8d60e01b81526001600160a01b03878116600483015284908290602490829084908b165af18015612d9d57612d89575b50612ba5565b83612d9691949294611bbf565b9138612d83565b6040513d86823e3d90fd5b50506005880154421115612ba05760405163e8c6942b60e01b81528061043d858960048401611d82565b60405163a034dbb160e01b81526001600160a01b038616600482015260248101849052604490fd5b93959492958387510361040d5760009660018060a01b0396878716808a526001986020908a8252604093848d205415612f3457908b9291612edc575b5090508a8a5b612e4f575b505050505050505050505050565b8451811015612ed757612e628186611d28565b51838d528b8352848d20541115612ec657612e7d8186611d28565b5189821015612eb2578161128f8e8d8f9695948d8d612ea58e612eab9960051b81019061252b565b93612a8b565b9091612e3c565b634e487b7160e01b8d52603260045260248dfd5b835163a554dcdf60e01b8152600490fd5b612e41565b909150823b1561152857835163bfe69c8d60e01b815290871660048201528b8160248183875af18015612f2a57612f16575b908a91612e36565b9a612f23818c939d611bbf565b9a90612f0e565b84513d8e823e3d90fd5b6044848e87519163a034dbb160e01b835260048301526024820152fd5b8060001904821181151516611d03570290565b9092908115612fdd5750612f789250611cf8565b604082015115612fb357670de0b6b3a764000091612fa6612faf9260018060801b0360208401511690612f51565b905b5190612f51565b0490565b60208201516001600160801b0316918215611d5457670de0b6b3a764000092612faf920490612fa8565b604051632ae6e9fd60e21b81526001600160a01b039485166004820152936020925084916024918391165afa801561304d5761302a9260009161302f575b506001600160401b0316611cf8565b612f78565b613047915060203d81116121bc576121ad8183611bbf565b3861301b565b6040513d6000823e3d90fd5b9192909260009260009081958315613132576001600160a01b0391821692833b156104465760405163a9059cbb60e01b815281818061309c898760048401611d82565b038183895af180156103d25761311c575b50503d8060001461310c576020146130c3578680fd5b909192939495602081803e515b613104577f8cdf3b7225378a44288992d46fdd440ed9c8fc556b68962dfc6de79ae7b7c631916020916040519586521693a3565b509193505050565b50909192939495506000196130d0565b819298509061312a91611bbf565b9538806130ad565b5050925050915090565b9192916000915b808310613151575050501490565b90919261315f8483856121cd565b3590600082821015613188575060005260205261318160406000205b93611d19565b9190613143565b6040916131819382526020522061317b56fe66d900e943b127cf94bd5fbf6b921691d1993cceda8ba20d63b1cd54b7e1af8aa2646970667358221220cf6a1b672c491a6072444dad943ac842312614d03dd61da465d4c3236e9220d364736f6c634300080f003300000000000000000000000005ed81814be2d9731c8906133236ffe9c62b013e
Deployed Bytecode
0x608080604052600436101561001357600080fd5b600090813560e01c90816301e3366714611a8557508063099cc91d146119555780630c340a241461192e57806311555dbc146118c05780631ae8b385146117b95780631d68b74d146116e25780632b8bbd0c1461160d5780634a18481a146115305780635e59ea90146113445780636a775f4f146110ea57806389a3284a146110445780638c7bc838146110265780639880dec214610fa3578063a62f91a614610f1e578063a9cdc9ee14610ce9578063ac80075014610c1e578063b8cc9ce614610b99578063bea0981214610af2578063c126fabe14610a82578063c7b33f4014610878578063d91c8e59146106b3578063e03e2f0014610573578063f1871f24146104495763ff5ad3991461012957600080fd5b346104465760c0366003190112610446576004356001600160a01b0381169003610441576044356024356001600160a01b03821682036104415760a435151560a43503610441576004356001600160a01b03168352600160205260408320541561041f576004356001600160a01b031683526001602052604083205481101561040d576004356001600160a01b031683526001602052604083206101cd9190611b5d565b50906002820154916101f76101e184611bf8565b936101ef6040519586611bbf565b808552611bf8565b601f1901845b8181106103e6575050600181015415806103dd575b610366575b60028101549160643591608435865b85811061027e578688604051918291602083016020845282518091526020604085019301915b81811061025a575050500390f35b9193509160206040826102706001948851611cc1565b01940191019184939261024c565b8061028f6103599260028601611d6a565b90549060039160018060a01b0391831b1c1690816000528501602052604060002060ff6001604051926102c3606085611bbf565b80548452015460018060801b038116602084015260801c161515604082015260018060a01b0387166000526004860160205260406000208260005260205261031660406000205491868a8a600435612f64565b908082111561035e5761032891611cf8565b60405191610337604084611bbf565b82526020820152610348828a611d28565b526103538189611d28565b50611d19565b610226565b505089610328565b6004356001600160a01b03163b156103ce578360405163bfe69c8d60e01b815260018060a01b038416600482015281816024818360018060a01b03600435165af180156103d2576103b9575b5050610217565b816103c391611bbf565b6103ce5783386103b2565b8380fd5b6040513d84823e3d90fd5b5060a435610212565b6020906040516103f7604082611bbf565b60008152600083820152828288010152016101fd565b60405163a554dcdf60e01b8152600490fd5b60405163a034dbb160e01b81528061043d8560048035908401612241565b0390fd5b600080fd5b80fd5b50346104465760c0366003190112610446576004356001600160a01b0380821690818303610441576001600160401b039160243583811161056f57610492903690600401611c0f565b604435928084168403610441576064359081168103610441576084359485151586036104415760a43590811161056b576104d0903690600401611b8f565b9490936020604051809263cde6804160e01b825281806104f4338860048401612241565b03915afa908115610560578991610532575b501561051a5761051596612dfa565b604051f35b6040516319b1d90760e31b8152336004820152602490fd5b610553915060203d8111610559575b61054b8183611bbf565b8101906122c4565b38610506565b503d610541565b6040513d8b823e3d90fd5b8780fd5b8580fd5b503461044657600319610120368201126106af576004356001600160a01b0381811692908383036104415760243590604435818116810361044157606435918216820361044157608435938415158503610441573660e41161056b5760e435966001600160401b03918289116106ab573660448a01116106ab57610104359283116106ab5760609083360301126106a757808952600160205260408920541561068b576020604051809263cde6804160e01b82528180610637338960048401612241565b03915afa90811561056057899161066d575b501561051a576106636105159760040160a486858a61255b565b50600401946127b8565b610685915060203d81116105595761054b8183611bbf565b38610649565b60405163a034dbb160e01b81528061043d8b8a60048401612241565b8880fd5b8980fd5b5080fd5b5034610446576040366003190112610446576001600160a01b039060043582811690819003610441578192915260016020928184526106f760243560408320611b5d565b509160028301805461070881611bf8565b946107166040519687611bbf565b818652601f1961072583611bf8565b01855b818110610853575050600390810190855b8381106107dd575050505061074d906122fd565b604051958695604087019060408852835180925260609183838a0195019187905b8282106107c3575050505086830382880152818087519485815201960194905b83821061079b5787870388f35b9185975082876107b18799849895979951611c9d565b0197019201879695939194929461078e565b8351811687528b9a5095850195928501929087019061076e565b80896107f161084993889d999b9c9d611d6a565b905490851b1c16600052838752604060002060ff8a60405192610815606085611bbf565b8054845201546001600160801b0381168a84015260801c161515604082015261083e828c611d28565b52610353818b611d28565b9897969498610739565b9880959798996108649493946122dc565b82828c010152019897969498929192610728565b50346104465760e036600319011261044657600435906001600160a01b03908183169081840361044157602435936044359380851694858103610441576064359182168083036104415760c43595861515870361044157604051966108de604089611bbf565b60008852600060208099015281875260018852604087205415610a66578187526001885260408720548a101561040d5761092360019a8389528b8a5260408920611b5d565b509389600052600385018952604060002060ff6040519c8d92610947606085611bbf565b80549384905201546001600160801b0381168c8f015260801c16151560408d015215610a4857506001840154159081610a40575b506109ec575b50916004604098926109b0946000520186528760002087600052865287600020549360a4359160843591612f64565b818111156109e4576109c29250611cf8565b905b8351926109d18585611bbf565b83528201526109e282518092611cc1565bf35b5050906109c4565b803b1561056f5785809160246040518094819363bfe69c8d60e01b83528760048401525af18015610a35571561098157610a27868092611bbf565b610a315738610981565b8480fd5b6040513d88823e3d90fd5b90503861097b565b60405163a034dbb160e01b815290819061043d908960048401612241565b60405163a034dbb160e01b81528061043d898960048401612241565b50346104465760031960a0368201126106af576004356001600160a01b0380821682036104415760443590811681036104415760643591821515830361044157608435936001600160401b03851161056f5760c0908536030112610a315761051593600401918060243592612a8b565b50346104465760a0366003190112610446576024356001600160401b0381116106af57610b23903690600401611b8f565b604435906001600160a01b038216820361044157602092610b8f92604051610b6881610b5a8882019460843590606435908761250d565b03601f198101835282611bbf565b519020604051858101918252858152610b82604082611bbf565b519020916004359161313c565b6040519015158152f35b5034610446576020366003190112610446576001600160a01b03600435818116908190036104415782549182169182330361051a578115610c0c5781604051937f6fadb1c244276388aee22be93b919985a18748c021e5d48553957a48101a25608686a36001600160a01b031916178255f35b604051630d804a6760e41b8152600490fd5b503461044657600319610100368201126106af576004356001600160a01b03808216908183036104415760243590604435908116810361044157606435928315158403610441573660c411610ce5576001600160401b039560c43591908783116106a7573660448401116106a75760e4359788116106a757606090883603011261056b5787526001602052604087205415610cc957610515956106638392600401608486858a61255b565b60405163a034dbb160e01b81528061043d898860048401612241565b8680fd5b50346104465760a0366003190112610446576004356001600160a01b0381168103610441576001600160401b03906044358281116103ce57610d2f903690600401611b8f565b909260643581811161056f57610d49903690600401611b8f565b9091608435908111610ce557610d63903690600401611b8f565b8754919690916001600160a01b0316330361051a5781850361040d5781830361040d576001600160a01b0386168852600160205260408820610da89060243590611b5d565b509188975b818910610dba5789604051f35b9091929394959697986002850154610dd38b8585612226565b9050810361040d57610de68b888a612226565b9190500361040d57805b610dfb8b8585612226565b9050811015610f045780898982610eed8f8f818e60048f8f8f8f86610eff9f808f8f9c610ecb96610e5196610e519f9e610ede9f610e628f610ebb99610e5c8f610e5193610e56610e518c610e5c9e81956121cd565b6121dd565b96612226565b906121cd565b7fa56b67569cae558523428bceed457ecebd24ee97a55b8161266bbf9d23c8e6026040610e948a610e5c8a8a8a612226565b81516024358152903560208201526001600160a01b039384169584169490931692a4612226565b359d6001600160a01b03946121cd565b1660005201602052604060002096612226565b6001600160a01b0394916121cd565b16600052602052604060002055611d19565b610df0565b5098610f1890989796959493929198611d19565b97610dad565b50346104465760a0366003190112610446576001600160a01b036004358181168103610441576001600160401b0391602435838111610a3157610f65903690600401611c0f565b916044359182168203610441576064359283151584036104415760843594851161056f5782610f9b610515963690600401611b8f565b949093612dfa565b5034610446576080366003190112610446576001600160a01b03906004358281169081900361044157604435908382168092036104415760643593841680940361044157826110019160049452600160205260406024359120611b5d565b5090600052016020526040600020906000526020526020604060002054604051908152f35b5034610446578060031936011261044657602060405162ed4e008152f35b5034610446576060366003190112610446576001600160a01b0360043581811690819003610441576044359182168092036104415760039261109c916110886122dc565b508152600160205260406024359120611b5d565b5090600052016020526060604060002060ff6001604051926110be8585611bbf565b80548452015460018060801b038116602084015260801c16151560408201526109e26040518092611c9d565b503461044657610100366003190112610446576001600160a01b036004358082169003610441576001600160401b036024358181116103ce57611131903690600401611c0f565b9082604435166044350361044157826064351660643503610441576084351515608435036104415760a435818111610a3157611171903690600401611c6d565b949060c4358381116113405761118b903690600401611b8f565b91909360e4359081116103ce576111a6903690600401611b8f565b90948887510361040d578387510361040d578187510361040d57876004351685526001602052604085205415611322576084356112c9575b845b87518110156112c35760405163cde6804160e01b81526020818061120a3360443560048401612241565b03818d600435165afa9081156112b8578791611299575b501561051a57806112658b6112458361123d611294968e611d28565b51928961225b565b611259611253858b8961226b565b8061228d565b9160443560043561255b565b5061128f611273828b611d28565b518861128084888d6122a2565b916064356044356004356127b8565b611d19565b6111e0565b6112b2915060203d6020116105595761054b8183611bbf565b38611221565b6040513d89823e3d90fd5b85604051f35b87600435163b15610a315760405163bfe69c8d60e01b8152886044351660048201528581602481838d600435165af18015610a355790869161130d575b50506111de565b8161131791611bbf565b610a31578438611306565b60405163a034dbb160e01b81528061043d8760048035908401612241565b8280fd5b50346104465760e0366003190112610446576004356001600160a01b03818116918281036103ce576001600160401b039260243584811161056f5761138d903690600401611c0f565b92604435908116808203610ce55760643594851515860361056b576084358781116106a7576113c0903690600401611c6d565b60a43589811161152c576113d8903690600401611b8f565b91909960c435908111611528576113f3903690600401611b8f565b9590978286510361040d578386510361040d578686510361040d578c9a818c52604060019c8d60205220541561150a57908d92916114b4575b5050508a8981905b61143f575b50604051f35b85518110156114af5761128f8a6114a7938b8f8c6114a1878e61149a8f8f908f8f889987948a8f9361125388611494976114888261148e95611481828e611d28565b519861225b565b9661226b565b9361255b565b50611d28565b51956122a2565b946127b8565b8b908a611434565b611439565b803b156113405760248392604051948593849263bfe69c8d60e01b845260048401525af180156114ff576114eb575b808c9161142c565b8b6114f8919c929c611bbf565b99386114e3565b6040513d8e823e3d90fd5b6044828f6040519163a034dbb160e01b835260048301526024820152fd5b8b80fd5b8a80fd5b5034610446576080366003190112610446576001600160a01b036004358181168103611340576044356001600160401b0381116103ce57366023820112156103ce5780600401359061158182611bf8565b9161158f6040519384611bbf565b80835260209460248685019260061b8401019236841161056b57602401915b8383106115ce57866115c6606435876024358a611d9d565b604051908152f35b60408336031261056b57604051906115e7604083611bbf565b83359083821682036106ab578289926040945282860135838201528152019201916115ae565b50346104465760031960c0368201126106af576004356001600160a01b0381811691828103610a315760443591808316830361056f57606435908116810361056f57608435938415158503610ce55760a435956001600160401b03871161056b5760c0908736030112610ce5576020604051809263cde6804160e01b8252818061169b338a60048401612241565b03915afa9081156112b85787916116c4575b501561051a57610515946004019260243592612a8b565b6116dc915060203d81116105595761054b8183611bbf565b386116ad565b5034610446576060366003190112610446576001600160a01b0360043581811690819003611340576024359060443592845416330361051a57821561040d57808452600160205260408420541561179b578084526001602052604084205482101561040d57600191611793917f86dc3da9b2bb25c8eea35197f01417ff78934ff53c99d1ace0375462e9c46c496060604051838152876020820152846040820152a185528260205260408520611b5d565b500155604051f35b604490846040519163a034dbb160e01b835260048301526024820152fd5b503461044657608036600319011261044657600435906001600160a01b0380831683036106af576044356001600160401b038111611340576117ff903690600401611b8f565b61180b81939293611bf8565b936118196040519586611bbf565b818552601f1961182883611bf8565b01815b81811061189b5750505b81811061184e5760206115c6606435876024358a611d9d565b80611860610e516118969385886121cd565b8460405191611870604084611bbf565b168152670de0b6b3a7640000602082015261188b8288611d28565b526103538187611d28565b611835565b6020906040516118ac604082611bbf565b848152828581830152828a0101520161182b565b5034610446576040366003190112610446576004356001600160a01b03811691908290036104465760243591815260016020526040812090815483101561044657606061190d8484611b5d565b50805490600560018201549101549060405192835260208301526040820152f35b5034610446578060031936011261044657546040516001600160a01b039091168152602090f35b50346104465760209081600319360112610446576001600160a01b0391600435838116810361134057916119b761198f6119aa9594612389565b9592969160409491945198899860808a5260808a0190611b29565b90888203858a0152611b29565b868103604088015283519081815283810184808460051b84010196019387925b848410611a1f5750505050505084820360608601528080855193848152019401925b828110611a0857505050500390f35b8351855286955093810193928101926001016119f9565b919395979688919395999a50601f1983820301855289519082808351928381520192019089905b808210611a6a5750505090806001929a0194019401918a99989697959394916119d7565b9193806001929488875116815201940192018a939291611a46565b9050346106af5760603660031901126106af576004356001600160a01b0381811691828103610a31576024359082821694858303610ce557604435938754163303611b145750611ad6918391613059565b611ae1575b83604051f35b60207f8210728e7c071f615b840ee026032693858fbcd5e5359e67e438c890f59e562091604051908152a3388080611adb565b6319b1d90760e31b8152336004820152602490fd5b90815180825260208080930193019160005b828110611b49575050505090565b835185529381019392810192600101611b3b565b8054821015611b79576000526006602060002091020190600090565b634e487b7160e01b600052603260045260246000fd5b9181601f84011215610441578235916001600160401b038311610441576020808501948460051b01011161044157565b601f909101601f19168101906001600160401b03821190821017611be257604052565b634e487b7160e01b600052604160045260246000fd5b6001600160401b038111611be25760051b60200190565b81601f8201121561044157803591611c2683611bf8565b92611c346040519485611bbf565b808452602092838086019260051b820101928311610441578301905b828210611c5e575050505090565b81358152908301908301611c50565b9181601f84011215610441578235916001600160401b038311610441576020808501948460061b01011161044157565b805182526020808201516001600160801b0316908301526040908101511515910152565b80516001600160a01b03168252602090810151910152565b9081602091031261044157516001600160401b03811681036104415790565b818110611d03570390565b634e487b7160e01b600052601160045260246000fd5b6000198114611d035760010190565b8051821015611b795760209160051b010190565b6001600160801b0391821691908215611d5457160490565b634e487b7160e01b600052601260045260246000fd5b8054821015611b795760005260206000200190600090565b6001600160a01b039091168152602081019190915260400190565b91909260018060a01b0390600082815416330361051a57851561040d5783511561040d5762ed4e00821161040d57604080516351076acb60e11b815296909486851694600492916020808b86818b5afa9a8b156121c357869b612194575b5087865260019a8b8252898720805490600160401b8210156121815790611e26918e82018155611b5d565b50988088528c83528a882054958d871061216e578a556000199095019b9487865b611eaf575b5050505050505082194211611e9c5750504201600590910155517fc0b232d318f3e59a207ea5731c6a79d5ae9dd78078bad277630b16a59f797422918190611e9690859083611d82565b0390a190565b634e487b7160e01b825260119052602490fd5b84518110156121695783611ec38287611d28565b510151156121595787848d88611ed9858a611d28565b51511690519283809263313ce56760e01b82525afa801561214f578a90612117575b60ff915016604d8111612104576001600160801b0390600a0a8181116120ee578f91898f8f818f8d928d8b7f809f126df209d3752da0eebe9cd87056d63a3cd3297d3a8756a8b630dc5578c88f9b978d988d80611f6a879f8f169c8c611f61828b611d28565b51511698611d28565b510151908351928352820152a36001600160401b038c1693878a8c8b8989111561207a5791611fa260039798999a92611fab94611d28565b51015198611d3c565b9a865197611fba60608a611bbf565b885287019a168a52611fd28b8688019a868c52611d28565b5151168352018b52209051815593519301805492516001600160881b0319909316919093161790151560801b60ff60801b161790555b856120138287611d28565b51511660028c01805490600160401b82101561206757916120428261205d948c809b9a99989795018155611d6a565b819291549060031b8b811b9283911b16911916179055611d19565b9091929394611e47565b634e487b7160e01b8c5260418b5260248cfd5b91611fa260039798999261208d94611d28565b9a86519761209c60608a611bbf565b885287019a168a526120b48b8688019a898c52611d28565b5151168352018b52209051815593519301805492516001600160881b0319909316919093161790151560801b60ff60801b16179055612008565b896024918f51916352a4b44160e01b8352820152fd5b634e487b7160e01b8a526011895260248afd5b508481813d8311612148575b61212d8183611bbf565b810103126106ab575160ff811681036106ab5760ff90611efb565b503d612123565b8d513d8c823e3d90fd5b8b5163a554dcdf60e01b81528890fd5b611e4c565b634e487b7160e01b895260118852602489fd5b634e487b7160e01b895260418852602489fd5b816121b5929c503d8d116121bc575b6121ad8183611bbf565b810190611cd9565b9938611dfb565b503d6121a3565b89513d88823e3d90fd5b9190811015611b795760051b0190565b356001600160a01b03811681036104415790565b903590601e198136030182121561044157018035906001600160401b03821161044157602001918160051b3603831361044157565b90821015611b795761223d9160051b8101906121f1565b9091565b6001600160a01b0391821681529116602082015260400190565b9190811015611b795760061b0190565b9190811015611b795760051b81013590601e1981360301821215610441570190565b903590603e1981360301821215610441570190565b9190811015611b795760051b81013590605e1981360301821215610441570190565b90816020910312610441575180151581036104415790565b604051906122eb606083611bbf565b60006040838281528260208201520152565b9060405191828154918282526020928383019160005283600020936000905b8282106123345750505061233292500383611bbf565b565b85546001600160a01b03168452600195860195889550938101939091019061231c565b9061236182611bf8565b61236e6040519182611bbf565b828152809261237f601f1991611bf8565b0190602036910137565b60018060a01b031660009181835260019160209183835260409384862054156124fd578286528084526124056123c186882054612357565b968481528286526123d487822054612357565b809786835284885280832054926123ea84611bf8565b936123f783519586611bbf565b808552601f19958691611bf8565b0189825b8281106124ea575050508398888252868152828220549561244161242c88611bf8565b976124398651998a611bbf565b808952611bf8565b01368288013785988c8884905b61245f575b50505050505050505050565b828552898452858520548110156124e55760056124dc928b9885885289875261248a848a8a20611b5d565b509161249885845492611d28565b526124a7848b84015492611d28565b526124b4600282016122fd565b6124be848c611d28565b526124c9838b611d28565b5001546124d6828b611d28565b52611d19565b8d908d9661244e565b612453565b60608782018301528c95508b9101612409565b5060609450849350839250829150565b604091949392606082019560018060a01b0316825260208201520152565b90359060be1981360301821215610441570190565b6002821015611b79576125589160051b81019061252b565b90565b939092919360018060a01b0380911694600090868252600196602093888552604097888520541561277a5782855289865288852054841015612769578190816125a38a6121dd565b911691829116109182612752575b50501561271a576125c28886612540565b356125cd8487612540565b35108061272b575b1561271a57906125ec918352878452868320611b5d565b50926126756126086125fe8484612540565b60808101906121f1565b95548096612615896121dd565b8a61262b6126238989612540565b359888612540565b0135966126408c519889928b8401948561250d565b0396612654601f1998898101835282611bbf565b5190208a5188810191825288815261266c8c82611bbf565b5190209261313c565b1561270957918091836126d761269f6126966125fe8c6126f09b9a99612540565b969098016121dd565b92896126b68c6126af8187612540565b3595612540565b0135926126cb8b51948592888401978861250d565b03908101835282611bbf565b51902090865190808201928352815261266c8782611bbf565b156126f9575090565b516309bde33960e01b8152600490fd5b85516309bde33960e01b8152600490fd5b865163a554dcdf60e01b8152600490fd5b508761274c61273a8288612540565b356127458689612540565b3590611cf8565b146125d5565b9091506127608689016121dd565b161138806125b1565b885163a554dcdf60e01b8152600490fd5b604483868b519163a034dbb160e01b835260048301526024820152fd5b9081526001600160a01b039091166020820152604081019190915260600190565b929095949193600060018060a01b03851681526001956020928784526127e18560408520611b5d565b508881018054919290918c8115612a615761283e91612824898c61280860408201826121f1565b939095610b5a604051938492868401968201359135908761250d565b5190206040518b81019182528b815261266c604082611bbf565b15612a4f575b6129d9575b88999a84995b612861575b5050505050505050505050565b6002830180548b10156129d3578a8a8a8a8f9e8f8a8a8a8f948f948c8c6128e98461294c9f6129359661289391611d6a565b9390549360039460018060a01b0391861b1c166000528389018c5260ff604060002096604051976128c560608a611bbf565b8054895201546001600160801b0381168e89015260801c1615156040870152611d6a565b60018060a09493941b039254911b1c16968860018060a01b0383169b8c60005260048801825260406000208a6000528252604060002054965415156000146129ca570135915b8c612f64565b90808211612952575b505050505050505050611d19565b9961284f565b61295c9082611cf8565b90612968828587613059565b1561293e5760008051602061319b8339815191529560046129b9948a600052018152604060002090866000525260406000205560405193849360018060a01b03169860018060a01b03169684612797565b0390a48a388a8a828a8a828061293e565b5050809161292f565b50612854565b6001600160a01b0388163b156103ce5760405163bfe69c8d60e01b81526001600160a01b03808d166004830152909b9085908d90602490829084908e165af19b8c15612a44578a9b9c612a30575b509a9950612849565b85612a3d91969296611bbf565b9338612a27565b6040513d87823e3d90fd5b6040516309bde33960e01b8152600490fd5b505060058301544211156128445760405163e8c6942b60e01b81528061043d898c60048401611d82565b6001600160a01b038116600090815260016020526040812054929591949193909215612dd2576001600160a01b03851683526001602052604083205482101561040d576001600160a01b0385168352600160205260408320612aee908390611b5d565b5096612b51612b0060808701876121f1565b91908a54604051938b85612b218c602083019360408201359135908561250d565b0395612b35601f1997888101835282611bbf565b519020604051602081019182526020815261266c604082611bbf565b15612a4f576001890154908115612da857612b9a91612b358a6126cb612b7a60a08c018c6121f1565b9390958c604051938491602083019660206060830135920135908861250d565b15612a4f575b612d3c575b825b6002880154811015612d32578087878a87612bc8612c899660028401611d6a565b92905460039160018060a01b038286851b1c16600052828101602052612c738d60406000209060ff600160405193612c01606086611bbf565b80548552015460018060801b038116602085015260801c161515604083015260018060a01b038a1660005260048401602052604060002060018060a01b03868a891b1c166000526020526040600020549660018501541515600014612d29575060406060820135915b01358a8a612f64565b93808511612c8e575b5050505050505050611d19565b612ba7565b612c989085611cf8565b612cb1818c88871b86901c6001600160a01b0316613059565b15612c7c576001600160a01b039788166000818152600493909301602090815260408085209890961b9490941c891680845296909352908390209390935590518886169591949091169260008051602061319b833981519152928291612d1991908c84612797565b0390a48787388080808e81612c7c565b60409091612c6a565b5050505050505050565b6001600160a01b0385163b156113405760405163bfe69c8d60e01b81526001600160a01b03878116600483015284908290602490829084908b165af18015612d9d57612d89575b50612ba5565b83612d9691949294611bbf565b9138612d83565b6040513d86823e3d90fd5b50506005880154421115612ba05760405163e8c6942b60e01b81528061043d858960048401611d82565b60405163a034dbb160e01b81526001600160a01b038616600482015260248101849052604490fd5b93959492958387510361040d5760009660018060a01b0396878716808a526001986020908a8252604093848d205415612f3457908b9291612edc575b5090508a8a5b612e4f575b505050505050505050505050565b8451811015612ed757612e628186611d28565b51838d528b8352848d20541115612ec657612e7d8186611d28565b5189821015612eb2578161128f8e8d8f9695948d8d612ea58e612eab9960051b81019061252b565b93612a8b565b9091612e3c565b634e487b7160e01b8d52603260045260248dfd5b835163a554dcdf60e01b8152600490fd5b612e41565b909150823b1561152857835163bfe69c8d60e01b815290871660048201528b8160248183875af18015612f2a57612f16575b908a91612e36565b9a612f23818c939d611bbf565b9a90612f0e565b84513d8e823e3d90fd5b6044848e87519163a034dbb160e01b835260048301526024820152fd5b8060001904821181151516611d03570290565b9092908115612fdd5750612f789250611cf8565b604082015115612fb357670de0b6b3a764000091612fa6612faf9260018060801b0360208401511690612f51565b905b5190612f51565b0490565b60208201516001600160801b0316918215611d5457670de0b6b3a764000092612faf920490612fa8565b604051632ae6e9fd60e21b81526001600160a01b039485166004820152936020925084916024918391165afa801561304d5761302a9260009161302f575b506001600160401b0316611cf8565b612f78565b613047915060203d81116121bc576121ad8183611bbf565b3861301b565b6040513d6000823e3d90fd5b9192909260009260009081958315613132576001600160a01b0391821692833b156104465760405163a9059cbb60e01b815281818061309c898760048401611d82565b038183895af180156103d25761311c575b50503d8060001461310c576020146130c3578680fd5b909192939495602081803e515b613104577f8cdf3b7225378a44288992d46fdd440ed9c8fc556b68962dfc6de79ae7b7c631916020916040519586521693a3565b509193505050565b50909192939495506000196130d0565b819298509061312a91611bbf565b9538806130ad565b5050925050915090565b9192916000915b808310613151575050501490565b90919261315f8483856121cd565b3590600082821015613188575060005260205261318160406000205b93611d19565b9190613143565b6040916131819382526020522061317b56fe66d900e943b127cf94bd5fbf6b921691d1993cceda8ba20d63b1cd54b7e1af8aa2646970667358221220cf6a1b672c491a6072444dad943ac842312614d03dd61da465d4c3236e9220d364736f6c634300080f0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000005ed81814be2d9731c8906133236ffe9c62b013e
-----Decoded View---------------
Arg [0] : governor_ (address): 0x05ED81814BE2D9731c8906133236FFE9C62B013E
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 00000000000000000000000005ed81814be2d9731c8906133236ffe9c62b013e
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ 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.