Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00Latest 25 from a total of 75,615 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Gen Top Root | 424746637 | 7 hrs ago | IN | 0 ETH | 0.00000148 | ||||
| Gen Sub Root | 424746624 | 7 hrs ago | IN | 0 ETH | 0.00021048 | ||||
| Gen Sub Root | 424746607 | 7 hrs ago | IN | 0 ETH | 0.00034458 | ||||
| Gen Sub Root | 424746584 | 7 hrs ago | IN | 0 ETH | 0.00034492 | ||||
| Gen Sub Root | 424746570 | 7 hrs ago | IN | 0 ETH | 0.00034554 | ||||
| Gen Sub Root | 424746557 | 7 hrs ago | IN | 0 ETH | 0.00034661 | ||||
| Gen Sub Root | 424746544 | 7 hrs ago | IN | 0 ETH | 0.00034482 | ||||
| Gen Sub Root | 424746516 | 7 hrs ago | IN | 0 ETH | 0.00034516 | ||||
| Gen Sub Root | 424746503 | 7 hrs ago | IN | 0 ETH | 0.00034457 | ||||
| Gen Sub Root | 424746490 | 7 hrs ago | IN | 0 ETH | 0.00035026 | ||||
| Gen Sub Root | 424746477 | 7 hrs ago | IN | 0 ETH | 0.00034468 | ||||
| Gen Sub Root | 424746464 | 7 hrs ago | IN | 0 ETH | 0.0003447 | ||||
| Mark Rewards Adj... | 424746451 | 7 hrs ago | IN | 0 ETH | 0.00000061 | ||||
| Adjust Cumulativ... | 424746443 | 7 hrs ago | IN | 0 ETH | 0.00000073 | ||||
| Settle | 424746426 | 7 hrs ago | IN | 0 ETH | 0.00001007 | ||||
| Settle | 424746414 | 7 hrs ago | IN | 0 ETH | 0.00003267 | ||||
| Settle | 424746401 | 7 hrs ago | IN | 0 ETH | 0.00003281 | ||||
| Settle | 424746389 | 7 hrs ago | IN | 0 ETH | 0.00003259 | ||||
| Settle | 424746376 | 7 hrs ago | IN | 0 ETH | 0.00003224 | ||||
| Settle | 424746364 | 7 hrs ago | IN | 0 ETH | 0.00003233 | ||||
| Settle | 424746352 | 7 hrs ago | IN | 0 ETH | 0.00003248 | ||||
| Settle | 424746340 | 7 hrs ago | IN | 0 ETH | 0.0000324 | ||||
| Settle | 424746327 | 7 hrs ago | IN | 0 ETH | 0.00003222 | ||||
| Settle | 424746297 | 7 hrs ago | IN | 0 ETH | 0.00003248 | ||||
| Settle | 424746285 | 7 hrs ago | IN | 0 ETH | 0.00003252 |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
RewardsSubmission
Compiler Version
v0.8.28+commit.7893614a
Optimization Enabled:
Yes with 800 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/structs/EnumerableMap.sol";
import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import "@openzeppelin/contracts/utils/math/Math.sol";
import "@openzeppelin/contracts/utils/cryptography/Hashes.sol";
import "./interfaces/IBrevisProof.sol";
import "./result-handlers/AbstractResultHandler.sol";
// A contract that summarizes Usual rewards into Merkle roots, preferably deployed on an L2 with low
// gas costs.
//
// For each reward epoch, the contract
// 1. Records Usual points from each bucket for each user attested by Brevis.
// 2. Converts the points to reward amounts based on the conversion rate for that epoch.
// 3. Summarizes all rewards into a set of Merkle roots.
// 4. Generates a top Merkle root from the sub roots.
contract RewardsSubmission is Ownable {
using EnumerableMap for EnumerableMap.AddressToUintMap;
using EnumerableSet for EnumerableSet.Bytes32Set;
using EnumerableSet for EnumerableSet.UintSet;
modifier onlySubmitter() {
require(submitters[msg.sender], "only submitters allowed");
_;
}
modifier onlyProofHandler() {
require(proofHandlers[msg.sender], "only proof handlers allowed");
_;
}
modifier onlyResultHandler() {
require(resultHandlers[msg.sender], "only result handlers allowed");
_;
}
error InvalidState(State state);
error IncorrectEpoch(uint64 epoch);
error ZeroAddress();
error InvalidInputLengths();
error InvalidVkHash(bytes32 expected, bytes32 actual);
error InvalidAppCommitHash(bytes32 expected, bytes32 actual);
event EpochInfoUpdated(uint64 indexed epoch, uint64 startTime, uint64 endTime, uint256[] bucketAmounts);
event EpochInitialized(uint64 indexed epoch);
event PointsAdded(
uint64 indexed epoch,
uint8 indexed bucket,
address indexed user,
string protocolName,
uint256 addedPoints
);
event SubmissionsComplete(uint64 indexed epoch);
event TotalPointsByBucketAdded(uint64 indexed epoch, uint8 indexed bucket, uint256 points);
event Settled(
uint64 indexed epoch,
address indexed user,
uint8 indexed bucket,
uint256 addedPoints,
uint256 addedRewards,
uint256 newCumulativeRewards
);
event AllSettled(uint64 indexed epoch);
event RewardsAdjustmentComplete(uint64 indexed epoch);
event SubRootLeafProcessed(
uint64 indexed epoch,
uint256 indexed subRootIndex,
uint256 indexed leafIndex,
address user,
uint256 cumulativeRewards,
bytes32 leafHash
);
event SubRootGenerated(uint64 indexed epoch, uint256 indexed subRootIndex, bytes32 subRoot);
event AllSubRootsGenerated(uint64 indexed epoch);
event TopRootGenerated(uint64 indexed epoch, bytes32 topRoot);
event GlobalStateUpdated(uint64 indexed currEpoch, State indexed state);
event CumulativeRewardsUpdated(address indexed user, uint256 cumulativeRewards);
event CumulativeRewardsAdjusted(address indexed user, int256 adjustment, uint256 newCumulativeRewards);
event NumBucketsUpdated(uint8 numBuckets);
event ProtocolInfoUpdated(
uint64 indexed chainId,
uint32 indexed protocolId,
uint8 indexed bucket,
string name,
bytes32 vkHash,
uint256 batchSize,
address resultHandler,
bool enabled,
address taxCollector,
uint256 taxBps,
bytes32[] extraData
);
event ProtocolInfoRemoved(uint32 indexed protocolId, string name);
event ProtocolEnabled(uint32 indexed protocolId, string name);
event ProtocolDisabled(uint32 indexed protocolId, string name);
event BrevisProofUpdated(address prevBrevisProof, address newBrevisProof);
event ProofHandlerAdded(address indexed proofHandler);
event ProofHandlerRemoved(address indexed proofHandler);
event ResultHandlerAdded(address indexed resultHandler);
event ResultHandlerRemoved(address indexed resultHandler);
event SubmitterAdded(address indexed submitter);
event SubmitterRemoved(address indexed submitter);
enum State {
EpochInit,
PointsSubmission,
Settlement,
RewardsAdjustment,
SubRootsGeneration,
TopRootGeneration
}
struct EpochInfo {
uint64 startTime;
uint64 endTime;
uint128 indexingBlockNumber;
uint256[] bucketAmounts;
}
struct ProtocolInfo {
uint64 chainId;
uint8 bucket;
string name;
bytes32 vkHash;
uint16 batchSize;
address resultHandler;
bool enabled;
address taxCollector;
uint256 taxBps;
bytes32[] extraData;
}
uint256 constant BPS_SCALAR = 10_000; // 10000 basis points = 100%
// Configs
uint8 public numBuckets;
// protocol ID => ProtocolInfo
mapping(uint32 => ProtocolInfo) public protocols;
EnumerableSet.UintSet protocolIds;
address public brevisProof;
// Allowed handlers for alternative proof types
mapping(address => bool) public proofHandlers;
// Allowed circuit result handlers
mapping(address => bool) public resultHandlers;
mapping(address => bool) public submitters;
// Global states
State public state;
uint64 public currEpoch;
// epoch => EpochInfo
mapping(uint64 => EpochInfo) public epochInfos;
// Storage for settlement
// bucket => EnumerableMap.AddressToUintMap of (user => points)
mapping(uint8 => EnumerableMap.AddressToUintMap) userPointsByBucket;
// bucket => total points
mapping(uint8 => uint256) public totalPointsByBucket;
// address => cumulative rewards
EnumerableMap.AddressToUintMap cumulativeRewards;
uint8 nextSettleBucket;
uint256 nextSettleUserIndex;
// Storage for merkle roots generation
EnumerableSet.Bytes32Set subRoots;
uint256[] subRootUserIndexStart;
bytes32 public topRoot;
constructor(address _brevisProof) Ownable(msg.sender) {
if (_brevisProof == address(0)) {
revert ZeroAddress();
}
brevisProof = _brevisProof;
}
// ----------- Init Epoch -----------
/**
* @notice Sets epoch info.
* @param epoch The epoch.
* @param startTime The start timestamp of the current epoch.
* @param endTime The end timestamp of the current epoch.
* @param totalRewardAmount The total reward amount for the epoch.
* @param bucketShares The reward share for each bucket.
*/
function setEpochInfo(
uint64 epoch,
uint64 startTime,
uint64 endTime,
uint256 totalRewardAmount,
uint256[] calldata bucketShares
) external onlySubmitter {
if (state != State.EpochInit) {
revert InvalidState(state);
}
if (epoch != currEpoch) {
revert IncorrectEpoch(epoch);
}
require(bucketShares.length == numBuckets, "invalid bucket shares length");
epochInfos[epoch].startTime = startTime;
epochInfos[epoch].endTime = endTime;
epochInfos[epoch].bucketAmounts = new uint256[](bucketShares.length);
uint256 totalBucketShares;
for (uint256 i = 0; i < bucketShares.length; i++) {
uint256 bucketShare = bucketShares[i];
totalBucketShares += bucketShare;
epochInfos[epoch].bucketAmounts[i] = Math.mulDiv(
totalRewardAmount,
bucketShare,
BPS_SCALAR,
Math.Rounding.Floor
);
}
require(totalBucketShares == BPS_SCALAR, "bucket shares not adding up to 100%");
emit EpochInfoUpdated(epoch, startTime, endTime, epochInfos[epoch].bucketAmounts);
}
/**
* @notice Marks the completion of the init stage for the current epoch.
* NOTE: Only call after all chain epoch infos are set!
* @param epoch The epoch to mark submission completion for.
*/
function markEpochInitialized(uint64 epoch) external onlySubmitter {
if (state != State.EpochInit) {
revert InvalidState(state);
}
if (epoch != currEpoch) {
revert IncorrectEpoch(epoch);
}
require(epoch == 0 || block.number > epochInfos[epoch - 1].indexingBlockNumber, "epoch not indexed yet");
// Clear the subRoots
uint256 nSubRoots = subRoots.length();
for (uint256 i = 0; i < nSubRoots; i++) {
bytes32 value = subRoots.at(0);
subRoots.remove(value);
}
emit EpochInitialized(epoch);
state = State.PointsSubmission;
}
// ----------- Submission -----------
/**
* @notice Submits a Brevis ZK proof.
* @param protocolId The protocol ID.
* @param proof The proof.
* @param circuitOutput The circuit output, in bytes.
*/
function submitProof(uint32 protocolId, bytes calldata proof, bytes calldata circuitOutput) public onlySubmitter {
if (state != State.PointsSubmission) {
revert InvalidState(state);
}
ProtocolInfo memory protocol = protocols[protocolId];
(, bytes32 appCommitHash, bytes32 appVkHash) = IBrevisProof(brevisProof).submitProof(protocol.chainId, proof);
// We need to check if the verifying key that Brevis used to verify the proof generated by our circuit is indeed
// our designated verifying key. This proves that the circuitOutput is authentic
if (appVkHash != protocol.vkHash) {
revert InvalidVkHash(protocol.vkHash, appVkHash);
}
bytes32 circuitOutputHash = keccak256(circuitOutput);
if (appCommitHash != circuitOutputHash) {
revert InvalidAppCommitHash(appCommitHash, circuitOutputHash);
}
handleProofResultInternal(protocolId, protocol, circuitOutput);
}
/**
* @notice Batch submits Brevis ZK proofs.
* @param _protocolIds The protocol IDs.
* @param proofs The proofs.
* @param circuitOutputs The circuit outputs, in bytes.
*/
function batchSubmitProofs(
uint32[] calldata _protocolIds,
bytes[] calldata proofs,
bytes[] calldata circuitOutputs
) external onlySubmitter {
if (
_protocolIds.length == 0 || _protocolIds.length != proofs.length || proofs.length != circuitOutputs.length
) {
revert InvalidInputLengths();
}
for (uint256 i = 0; i < _protocolIds.length; i++) {
submitProof(_protocolIds[i], proofs[i], circuitOutputs[i]);
}
}
/**
* @notice Handles proof result from approved external proof handlers.
* @param protocolId The protocol ID.
* @param protocol The protocol info.
* @param circuitOutput The circuit output, in bytes.
*/
function handleProofResult(
uint32 protocolId,
ProtocolInfo memory protocol,
bytes calldata circuitOutput
) external onlyProofHandler {
if (state != State.PointsSubmission) {
revert InvalidState(state);
}
handleProofResultInternal(protocolId, protocol, circuitOutput);
}
function handleProofResultInternal(
uint32 protocolId,
ProtocolInfo memory protocol,
bytes calldata circuitOutput
) internal {
require(protocol.enabled, "protocol disabled");
AbstractResultHandler(protocol.resultHandler).handleResult(protocolId, protocol, circuitOutput);
}
function addPoints(
uint8 bucket,
address user,
uint256 addedPoints,
ProtocolInfo calldata protocol
) external onlyResultHandler {
EnumerableMap.AddressToUintMap storage pointsMap = userPointsByBucket[bucket];
(, uint256 prevPoints) = pointsMap.tryGet(user);
// Taxation
uint256 tax;
if (protocol.taxBps > 0) {
tax = (addedPoints * protocol.taxBps) / 1e4;
(, uint256 prevTax) = pointsMap.tryGet(protocol.taxCollector);
pointsMap.set(protocol.taxCollector, prevTax + tax);
emit PointsAdded(currEpoch, bucket, protocol.taxCollector, protocol.name, tax);
}
uint256 pointsMinusTax = addedPoints - tax;
pointsMap.set(user, prevPoints + pointsMinusTax);
totalPointsByBucket[bucket] += addedPoints;
emit PointsAdded(currEpoch, bucket, user, protocol.name, pointsMinusTax);
}
/**
* @notice Marks the completion of the point submission stage for the current epoch.
* NOTE: Only call after submitting the points for all users in all protocols!
* @param epoch The epoch to mark submission completion for.
*/
function markSubmissionsComplete(uint64 epoch) external onlySubmitter {
if (state != State.PointsSubmission) {
revert InvalidState(state);
}
if (epoch != currEpoch) {
revert IncorrectEpoch(epoch);
}
for (uint256 i = 0; i < protocolIds.length(); i++) {
uint32 protocolId = uint32(protocolIds.at(i));
AbstractResultHandler(protocols[protocolId].resultHandler).resetProtocolState(protocolId);
}
for (uint8 i = 0; i < epochInfos[epoch].bucketAmounts.length; i++) {
emit TotalPointsByBucketAdded(epoch, i, totalPointsByBucket[i]);
}
emit SubmissionsComplete(epoch);
state = State.Settlement;
}
// ----------- Settlement -----------
/**
* @notice Triggers settlement for up to `count` number of times. Should be called
* repeatedly until all (bucket, user) tuples are settled.
* @param epoch The epoch.
* @param count The maximal number of settlements to perform.
*/
function settle(uint64 epoch, uint256 count) external {
if (state != State.Settlement) {
revert InvalidState(state);
}
if (epoch != currEpoch) {
revert IncorrectEpoch(epoch);
}
EpochInfo memory epochInfo = epochInfos[epoch];
uint8 bucket = nextSettleBucket;
uint256 userIndex = nextSettleUserIndex;
bool allDone;
while (count > 0) {
EnumerableMap.AddressToUintMap storage currBucketPoints = userPointsByBucket[uint8(bucket)];
if (currBucketPoints.length() == 0) {
// Empty bucket
if (bucket == epochInfo.bucketAmounts.length - 1) {
// All buckets done
allDone = true;
break;
}
bucket++;
continue;
}
uint256 bucketAmount = epochInfo.bucketAmounts[bucket];
(address user, uint256 addedPoints) = currBucketPoints.at(userIndex);
uint256 addedRewards = Math.mulDiv(
addedPoints,
bucketAmount,
totalPointsByBucket[bucket],
Math.Rounding.Floor
);
(, uint256 prevCumulativeRewards) = cumulativeRewards.tryGet(user);
uint256 newCumulativeRewards = prevCumulativeRewards + addedRewards;
cumulativeRewards.set(user, newCumulativeRewards);
emit Settled(epoch, user, uint8(bucket), addedPoints, addedRewards, newCumulativeRewards);
// Clear the map after settlement for each user
currBucketPoints.set(user, 0);
count--;
if (userIndex == currBucketPoints.length() - 1) {
// One bucket done
if (bucket == epochInfo.bucketAmounts.length - 1) {
// All buckets done
allDone = true;
break;
}
// Reset total points for the bucket
totalPointsByBucket[bucket] = 0;
userIndex = 0;
bucket++;
} else {
userIndex++;
}
}
if (allDone) {
state = State.RewardsAdjustment;
nextSettleBucket = 0;
nextSettleUserIndex = 0;
totalPointsByBucket[bucket] = 0;
emit AllSettled(epoch);
} else {
// Not done, continue in the next settle() call
nextSettleBucket = bucket;
nextSettleUserIndex = userIndex;
}
}
// ----------- Rewards Adjustment -----------
/**
* @notice Adjusts cumulative rewards for a user after settlement, used to adjust rewards for
* special addresses such as the Usual DAO.
* @param user The user.
* @param adjustment The cumulative reward adjustment, positive to add and negative to subtract.
*/
function adjustCumulativeRewards(address user, int256 adjustment) public onlySubmitter {
if (state != State.RewardsAdjustment) {
revert InvalidState(state);
}
(, uint256 prevCumulativeRewards) = cumulativeRewards.tryGet(user);
uint256 newCumulativeRewards = prevCumulativeRewards;
if (adjustment > 0) {
newCumulativeRewards += uint256(adjustment);
} else {
newCumulativeRewards -= uint256(-adjustment);
}
cumulativeRewards.set(user, newCumulativeRewards);
emit CumulativeRewardsAdjusted(user, adjustment, newCumulativeRewards);
}
/**
* @notice Marks the completion of the rewards adjustment stage for the current epoch.
* @param epoch The epoch to mark adjustment completion for.
*/
function markRewardsAdjustmentComplete(uint64 epoch) external onlySubmitter {
if (state != State.RewardsAdjustment) {
revert InvalidState(state);
}
state = State.SubRootsGeneration;
emit RewardsAdjustmentComplete(epoch);
}
// ----------- Merkle Roots Generation -----------
/**
* @notice Generates and records a Merkle root for a subset of users up to `nLeaves`.
* Should be called repeatedly until every user is covered in a subtree.
* @param epoch The epoch.
* @param nLeaves The maximal number of users to include in the current subtree.
*/
function genSubRoot(uint64 epoch, uint256 nLeaves) external {
if (state != State.SubRootsGeneration) {
revert InvalidState(state);
}
if (epoch != currEpoch) {
revert IncorrectEpoch(epoch);
}
require(nLeaves <= 2 ** 32, "too many leaves");
uint256 subRootIndex = subRoots.length();
uint256 indexStart = 0;
if (subRootIndex == 0) {
delete subRootUserIndexStart;
} else {
indexStart = subRootUserIndexStart[subRootIndex - 1];
}
uint256 maxNLeaves = cumulativeRewards.length() - indexStart;
if (nLeaves > maxNLeaves) {
nLeaves = maxNLeaves;
}
bytes32[] memory hashes = new bytes32[](nLeaves);
for (uint256 i = 0; i < nLeaves; i++) {
(address user, uint256 rewards) = cumulativeRewards.at(indexStart + i);
bytes32 leafHash = keccak256(abi.encodePacked(user, rewards));
hashes[i] = leafHash;
emit SubRootLeafProcessed(epoch, subRootIndex, i, user, rewards, leafHash);
}
bytes32 subRoot = genMerkleRoot(hashes);
subRoots.add(subRoot);
emit SubRootGenerated(epoch, subRootIndex, subRoot);
if (nLeaves == maxNLeaves) {
state = State.TopRootGeneration;
emit AllSubRootsGenerated(epoch);
} else {
subRootUserIndexStart.push(indexStart + nLeaves);
}
}
/**
* @notice Generates and records the top Merkle tree root, using the subtree roots as leaves.
* @param epoch The epoch.
*/
function genTopRoot(uint64 epoch) external {
if (state != State.TopRootGeneration) {
revert InvalidState(state);
}
if (epoch != currEpoch) {
revert IncorrectEpoch(epoch);
}
topRoot = genMerkleRoot(subRoots.values());
epochInfos[epoch].indexingBlockNumber = uint128(block.number);
currEpoch++;
state = State.EpochInit;
emit TopRootGenerated(epoch, topRoot);
}
function genMerkleRoot(bytes32[] memory hashes) internal pure returns (bytes32) {
if (hashes.length == 0) {
return bytes32(0);
}
while (hashes.length > 1) {
bytes32[] memory nextHashes = new bytes32[]((hashes.length + 1) / 2);
uint256 i;
for (; i < hashes.length - 1; i += 2) {
nextHashes[i / 2] = Hashes.commutativeKeccak256(hashes[i], hashes[i + 1]);
}
if (i == hashes.length - 1) {
nextHashes[i / 2] = hashes[i];
}
hashes = nextHashes;
}
return hashes[0];
}
function getMerkleProof(
uint64 epoch,
address user
) external view returns (uint256 _cumulativeRewards, bytes32[] memory proof) {
if (state != State.EpochInit) {
revert InvalidState(state);
}
if (epoch != currEpoch - 1) {
revert IncorrectEpoch(epoch);
}
_cumulativeRewards = cumulativeRewards.get(user);
uint256 userIndex = cumulativeRewards._inner._keys._inner._positions[bytes32(uint256(uint160(user)))] - 1;
uint256 subRootIndex;
while (subRootIndex < subRoots.length() - 1 && userIndex >= subRootUserIndexStart[subRootIndex]) {
++subRootIndex;
}
uint256 indexStart = subRootIndex == 0 ? 0 : subRootUserIndexStart[subRootIndex - 1];
uint256 nLeaves = cumulativeRewards.length() - indexStart;
if (subRootIndex < subRoots.length() - 1) {
nLeaves -= cumulativeRewards.length() - subRootUserIndexStart[subRootIndex];
}
bytes32[] memory hashes = new bytes32[](nLeaves);
for (uint256 i = 0; i < hashes.length; i++) {
(address _user, uint256 rewards) = cumulativeRewards.at(indexStart + i);
hashes[i] = keccak256(abi.encodePacked(_user, rewards));
}
bytes32[] memory subProof = genMerkleProof(hashes, userIndex - indexStart);
bytes32[] memory topProof = genMerkleProof(subRoots.values(), subRootIndex);
proof = new bytes32[](subProof.length + topProof.length);
for (uint256 i = 0; i < subProof.length; i++) {
proof[i] = subProof[i];
}
for (uint256 i = 0; i < topProof.length; i++) {
proof[subProof.length + i] = topProof[i];
}
}
function genMerkleProof(bytes32[] memory hashes, uint256 path) internal pure returns (bytes32[] memory proof) {
proof = new bytes32[](32);
uint256 length = 0;
while (hashes.length > 1) {
if (hashes.length % 2 == 0 || path < hashes.length - 1) {
proof[length] = hashes[path ^ 1];
++length;
}
path >>= 1;
bytes32[] memory nextHashes = new bytes32[]((hashes.length + 1) / 2);
uint256 i;
for (; i < hashes.length - 1; i += 2) {
nextHashes[i / 2] = Hashes.commutativeKeccak256(hashes[i], hashes[i + 1]);
}
if (i == hashes.length - 1) {
nextHashes[i / 2] = hashes[i];
}
hashes = nextHashes;
}
assembly ("memory-safe") {
mstore(proof, length)
}
}
/**
* @notice Sets cumulative rewards for a user.
* @param user The user.
* @param _cumulativeRewards The cumulative rewards.
*/
function setCumulativeRewards(address user, uint256 _cumulativeRewards) public onlySubmitter {
if (state != State.EpochInit) {
revert InvalidState(state);
}
require(currEpoch == 0 || block.number > epochInfos[currEpoch - 1].indexingBlockNumber, "wait next block");
cumulativeRewards.set(user, _cumulativeRewards);
emit CumulativeRewardsUpdated(user, _cumulativeRewards);
}
/**
* @notice Batch sets cumulative rewards for users.
* @param users The users.
* @param _cumulativeRewards The cumulative rewards.
*/
function batchSetCumulativeRewards(
address[] calldata users,
uint256[] calldata _cumulativeRewards
) external onlySubmitter {
if (users.length == 0 || users.length != _cumulativeRewards.length) {
revert InvalidInputLengths();
}
for (uint256 i = 0; i < _cumulativeRewards.length; i++) {
setCumulativeRewards(users[i], _cumulativeRewards[i]);
}
}
// ----------- Admin -----------
/**
* @notice Sets the global state.
* @param _currEpoch The current epoch.
* @param _state The state.
*/
function setGlobalState(uint64 _currEpoch, State _state) external onlyOwner {
currEpoch = _currEpoch;
state = _state;
emit GlobalStateUpdated(currEpoch, state);
}
/**
* @notice Sets the protocol info.
* @param chainId The source chain ID.
* @param protocolId The protocol ID.
* @param bucket The bucket the protocol should accrue points to.
* @param name The protocol name.
* @param vkHash The circuit vkHash, which represents the predefined app logic.
* @param batchSize The circuit batch size, should match circuit implementation.
* @param resultHandler The result handler address.
* @param enabled Whether proofs for the protocol are accepted.
* @param taxCollector The tax collector address.
* @param taxBps The tax rate in basis points.
* @param extraData Extra public inputs that need to be verified.
*/
function setProtocolInfo(
uint64 chainId,
uint32 protocolId,
uint8 bucket,
string calldata name,
bytes32 vkHash,
uint16 batchSize,
address resultHandler,
bool enabled,
address taxCollector,
uint256 taxBps,
bytes32[] calldata extraData
) public onlyOwner {
if (state != State.EpochInit) {
revert InvalidState(state);
}
require(resultHandlers[resultHandler], "unauthorized result handler");
require(bucket < numBuckets, "invalid bucket");
protocolIds.add(protocolId);
AbstractResultHandler(resultHandler).resetProtocolState(protocolId);
protocols[protocolId] = ProtocolInfo(
chainId,
bucket,
name,
vkHash,
batchSize,
resultHandler,
enabled,
taxCollector,
taxBps,
extraData
);
emit ProtocolInfoUpdated(
chainId,
protocolId,
bucket,
name,
vkHash,
batchSize,
resultHandler,
enabled,
taxCollector,
taxBps,
extraData
);
}
/**
* @notice Batch sets protocol infos.
* @param chainIds The source chain IDs.
* @param _protocolIds The protocol IDs.
* @param buckets The buckets the protocols should accrue points to.
* @param names The protocol names.
* @param vkHashes The circuit vkHashes, which represent the predefined app logic.
* @param batchSizes The circuit batch sizes, should match circuit implementation.
* @param _resultHandlers The result handler addresses.
* @param enableds Whether proofs for the protocols are accepted.
* @param taxCollectors The tax collector addresses.
* @param taxBpses The tax rates in basis points.
* @param extraDatas Extra public inputs that need to be verified.
*/
function batchSetProtocolInfos(
uint64[] calldata chainIds,
uint32[] calldata _protocolIds,
uint8[] calldata buckets,
string[] calldata names,
bytes32[] calldata vkHashes,
uint16[] calldata batchSizes,
address[] calldata _resultHandlers,
bool[] calldata enableds,
address[] calldata taxCollectors,
uint256[] calldata taxBpses,
bytes32[][] calldata extraDatas
) external onlyOwner {
if (
chainIds.length == 0 ||
chainIds.length != _protocolIds.length ||
_protocolIds.length != buckets.length ||
buckets.length != names.length ||
names.length != vkHashes.length ||
vkHashes.length != batchSizes.length ||
batchSizes.length != _resultHandlers.length ||
_resultHandlers.length != enableds.length ||
enableds.length != taxCollectors.length ||
taxCollectors.length != taxBpses.length ||
taxBpses.length != extraDatas.length
) {
revert InvalidInputLengths();
}
for (uint256 i = 0; i < vkHashes.length; i++) {
setProtocolInfo(
chainIds[i],
_protocolIds[i],
buckets[i],
names[i],
vkHashes[i],
batchSizes[i],
_resultHandlers[i],
enableds[i],
taxCollectors[i],
taxBpses[i],
extraDatas[i]
);
}
}
/**
* @notice Removes the protocol info.
* @param protocolId The protocol ID.
*/
function removeProtocolInfo(uint32 protocolId) public onlyOwner {
if (state != State.EpochInit) {
revert InvalidState(state);
}
ProtocolInfo memory protocol = protocols[protocolId];
AbstractResultHandler(protocol.resultHandler).removeProtocolState(protocolId);
protocolIds.remove(protocolId);
delete protocols[protocolId];
emit ProtocolInfoRemoved(protocolId, protocol.name);
}
/**
* @notice Batch removes protocol infos.
* @param _protocolIds The protocol IDs.
*/
function batchRemoveProtocolInfos(uint32[] calldata _protocolIds) public onlyOwner {
for (uint256 i = 0; i < _protocolIds.length; i++) {
removeProtocolInfo(_protocolIds[i]);
}
}
/**
* @notice Sets the enabled status of a protocol.
* @param protocolId The protocol ID.
* @param enabled Whether the protocol is enabled.
*/
function setProtocolEnabled(uint32 protocolId, bool enabled) public onlyOwner {
if (state != State.EpochInit) {
revert InvalidState(state);
}
ProtocolInfo memory protocol = protocols[protocolId];
protocol.enabled = enabled;
if (enabled) {
emit ProtocolEnabled(protocolId, protocol.name);
} else {
emit ProtocolDisabled(protocolId, protocol.name);
}
}
/**
* @notice Batch sets protocol enabled status.
* @param _protocolIds The protocol IDs.
* @param enableds Whether the protocols are enabled.
*/
function batchSetProtocolsEnabled(uint32[] calldata _protocolIds, bool[] calldata enableds) public onlyOwner {
if (_protocolIds.length != enableds.length) {
revert InvalidInputLengths();
}
for (uint256 i = 0; i < _protocolIds.length; i++) {
setProtocolEnabled(_protocolIds[i], enableds[i]);
}
}
/**
* @notice Sets the BrevisProof contract address.
* @param _brevisProof The new BrevisProof contract address.
*/
function setBrevisProof(address _brevisProof) external onlyOwner {
if (_brevisProof == address(0)) {
revert ZeroAddress();
}
address prevBrevisProof = brevisProof;
brevisProof = _brevisProof;
emit BrevisProofUpdated(prevBrevisProof, _brevisProof);
}
/**
* @notice Adds a proof handler address.
* @param proofHandler The proof handler address.
*/
function addProofHandler(address proofHandler) external onlyOwner {
if (state != State.EpochInit) {
revert InvalidState(state);
}
proofHandlers[proofHandler] = true;
emit ProofHandlerAdded(proofHandler);
}
/**
* @notice Removes a proof handler address.
* @param proofHandler The proof handler address.
*/
function removeProofHandler(address proofHandler) external onlyOwner {
if (state != State.EpochInit) {
revert InvalidState(state);
}
delete proofHandlers[proofHandler];
emit ProofHandlerRemoved(proofHandler);
}
/**
* @notice Adds a result handler address.
* @param resultHandler The result handler address.
*/
function addResultHandler(address resultHandler) external onlyOwner {
if (state != State.EpochInit) {
revert InvalidState(state);
}
resultHandlers[resultHandler] = true;
emit ResultHandlerAdded(resultHandler);
}
/**
* @notice Removes a result handler address.
* @param resultHandler The result handler address.
*/
function removeResultHandler(address resultHandler) external onlyOwner {
if (state != State.EpochInit) {
revert InvalidState(state);
}
delete resultHandlers[resultHandler];
emit ResultHandlerRemoved(resultHandler);
}
/**
* @notice Adds a submitter address.
* @param submitter The submitter address.
*/
function addSubmitter(address submitter) external onlyOwner {
submitters[submitter] = true;
emit SubmitterAdded(submitter);
}
/**
* @notice Removes a submitter address.
* @param submitter The submitter address.
*/
function removeSubmitter(address submitter) external onlyOwner {
delete submitters[submitter];
emit SubmitterRemoved(submitter);
}
/**
* @notice Sets the total number of reward buckets.
* @param _numBuckets The total number of buckets.
*/
function setNumBuckets(uint8 _numBuckets) external onlyOwner {
if (state != State.EpochInit) {
revert InvalidState(state);
}
numBuckets = _numBuckets;
emit NumBucketsUpdated(_numBuckets);
}
// ----------- Convenience view functions -----------
function getProtocolInfo(uint32 protocolId) external view returns (ProtocolInfo memory) {
return protocols[protocolId];
}
/**
* @notice Gets the cumulative rewards for a user at the last indexed epoch.
* @param user The user.
* @return epoch The last indexed reward epoch.
* @return rewards The user's cumulative rewards.
*/
function getCumulativeRewards(address user) external view returns (uint64 epoch, uint256 rewards) {
if (state != State.EpochInit) {
revert InvalidState(state);
}
require(
currEpoch == 0 || block.number > epochInfos[currEpoch - 1].indexingBlockNumber,
"epoch not indexed yet"
);
(, rewards) = cumulativeRewards.tryGet(user);
return (currEpoch - 1, rewards);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is set to the address provided by the deployer. This can
* later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/cryptography/Hashes.sol)
pragma solidity ^0.8.20;
/**
* @dev Library of standard hash functions.
*
* _Available since v5.1._
*/
library Hashes {
/**
* @dev Commutative Keccak256 hash of a sorted pair of bytes32. Frequently used when working with merkle proofs.
*
* NOTE: Equivalent to the `standardNodeHash` in our https://github.com/OpenZeppelin/merkle-tree[JavaScript library].
*/
function commutativeKeccak256(bytes32 a, bytes32 b) internal pure returns (bytes32) {
return a < b ? _efficientKeccak256(a, b) : _efficientKeccak256(b, a);
}
/**
* @dev Implementation of keccak256(abi.encode(a, b)) that doesn't allocate or expand memory.
*/
function _efficientKeccak256(bytes32 a, bytes32 b) private pure returns (bytes32 value) {
assembly ("memory-safe") {
mstore(0x00, a)
mstore(0x20, b)
value := keccak256(0x00, 0x40)
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/Math.sol)
pragma solidity ^0.8.20;
import {Panic} from "../Panic.sol";
import {SafeCast} from "./SafeCast.sol";
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Floor, // Toward negative infinity
Ceil, // Toward positive infinity
Trunc, // Toward zero
Expand // Away from zero
}
/**
* @dev Returns the addition of two unsigned integers, with an success flag (no overflow).
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the subtraction of two unsigned integers, with an success flag (no overflow).
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with an success flag (no overflow).
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the division of two unsigned integers, with a success flag (no division by zero).
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a success flag (no division by zero).
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
/**
* @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant.
*
* IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone.
* However, the compiler may optimize Solidity ternary operations (i.e. `a ? b : c`) to only compute
* one branch when needed, making this function more expensive.
*/
function ternary(bool condition, uint256 a, uint256 b) internal pure returns (uint256) {
unchecked {
// branchless ternary works because:
// b ^ (a ^ b) == a
// b ^ 0 == b
return b ^ ((a ^ b) * SafeCast.toUint(condition));
}
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return ternary(a > b, a, b);
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return ternary(a < b, a, b);
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds towards infinity instead
* of rounding towards zero.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
if (b == 0) {
// Guarantee the same behavior as in a regular Solidity division.
Panic.panic(Panic.DIVISION_BY_ZERO);
}
// The following calculation ensures accurate ceiling division without overflow.
// Since a is non-zero, (a - 1) / b will not overflow.
// The largest possible result occurs when (a - 1) / b is type(uint256).max,
// but the largest value we can obtain is type(uint256).max - 1, which happens
// when a = type(uint256).max and b = 1.
unchecked {
return SafeCast.toUint(a > 0) * ((a - 1) / b + 1);
}
}
/**
* @dev Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
* denominator == 0.
*
* Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
* Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2²⁵⁶ and mod 2²⁵⁶ - 1, then use
// the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2²⁵⁶ + prod0.
uint256 prod0 = x * y; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2²⁵⁶. Also prevents denominator == 0.
if (denominator <= prod1) {
Panic.panic(ternary(denominator == 0, Panic.DIVISION_BY_ZERO, Panic.UNDER_OVERFLOW));
}
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator.
// Always >= 1. See https://cs.stackexchange.com/q/138556/92363.
uint256 twos = denominator & (0 - denominator);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2²⁵⁶ / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2²⁵⁶. Now that denominator is an odd number, it has an inverse modulo 2²⁵⁶ such
// that denominator * inv ≡ 1 mod 2²⁵⁶. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv ≡ 1 mod 2⁴.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also
// works in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2⁸
inverse *= 2 - denominator * inverse; // inverse mod 2¹⁶
inverse *= 2 - denominator * inverse; // inverse mod 2³²
inverse *= 2 - denominator * inverse; // inverse mod 2⁶⁴
inverse *= 2 - denominator * inverse; // inverse mod 2¹²⁸
inverse *= 2 - denominator * inverse; // inverse mod 2²⁵⁶
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2²⁵⁶. Since the preconditions guarantee that the outcome is
// less than 2²⁵⁶, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @dev Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
return mulDiv(x, y, denominator) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0);
}
/**
* @dev Calculate the modular multiplicative inverse of a number in Z/nZ.
*
* If n is a prime, then Z/nZ is a field. In that case all elements are inversible, except 0.
* If n is not a prime, then Z/nZ is not a field, and some elements might not be inversible.
*
* If the input value is not inversible, 0 is returned.
*
* NOTE: If you know for sure that n is (big) a prime, it may be cheaper to use Fermat's little theorem and get the
* inverse using `Math.modExp(a, n - 2, n)`. See {invModPrime}.
*/
function invMod(uint256 a, uint256 n) internal pure returns (uint256) {
unchecked {
if (n == 0) return 0;
// The inverse modulo is calculated using the Extended Euclidean Algorithm (iterative version)
// Used to compute integers x and y such that: ax + ny = gcd(a, n).
// When the gcd is 1, then the inverse of a modulo n exists and it's x.
// ax + ny = 1
// ax = 1 + (-y)n
// ax ≡ 1 (mod n) # x is the inverse of a modulo n
// If the remainder is 0 the gcd is n right away.
uint256 remainder = a % n;
uint256 gcd = n;
// Therefore the initial coefficients are:
// ax + ny = gcd(a, n) = n
// 0a + 1n = n
int256 x = 0;
int256 y = 1;
while (remainder != 0) {
uint256 quotient = gcd / remainder;
(gcd, remainder) = (
// The old remainder is the next gcd to try.
remainder,
// Compute the next remainder.
// Can't overflow given that (a % gcd) * (gcd // (a % gcd)) <= gcd
// where gcd is at most n (capped to type(uint256).max)
gcd - remainder * quotient
);
(x, y) = (
// Increment the coefficient of a.
y,
// Decrement the coefficient of n.
// Can overflow, but the result is casted to uint256 so that the
// next value of y is "wrapped around" to a value between 0 and n - 1.
x - y * int256(quotient)
);
}
if (gcd != 1) return 0; // No inverse exists.
return ternary(x < 0, n - uint256(-x), uint256(x)); // Wrap the result if it's negative.
}
}
/**
* @dev Variant of {invMod}. More efficient, but only works if `p` is known to be a prime greater than `2`.
*
* From https://en.wikipedia.org/wiki/Fermat%27s_little_theorem[Fermat's little theorem], we know that if p is
* prime, then `a**(p-1) ≡ 1 mod p`. As a consequence, we have `a * a**(p-2) ≡ 1 mod p`, which means that
* `a**(p-2)` is the modular multiplicative inverse of a in Fp.
*
* NOTE: this function does NOT check that `p` is a prime greater than `2`.
*/
function invModPrime(uint256 a, uint256 p) internal view returns (uint256) {
unchecked {
return Math.modExp(a, p - 2, p);
}
}
/**
* @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m)
*
* Requirements:
* - modulus can't be zero
* - underlying staticcall to precompile must succeed
*
* IMPORTANT: The result is only valid if the underlying call succeeds. When using this function, make
* sure the chain you're using it on supports the precompiled contract for modular exponentiation
* at address 0x05 as specified in https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise,
* the underlying function will succeed given the lack of a revert, but the result may be incorrectly
* interpreted as 0.
*/
function modExp(uint256 b, uint256 e, uint256 m) internal view returns (uint256) {
(bool success, uint256 result) = tryModExp(b, e, m);
if (!success) {
Panic.panic(Panic.DIVISION_BY_ZERO);
}
return result;
}
/**
* @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m).
* It includes a success flag indicating if the operation succeeded. Operation will be marked as failed if trying
* to operate modulo 0 or if the underlying precompile reverted.
*
* IMPORTANT: The result is only valid if the success flag is true. When using this function, make sure the chain
* you're using it on supports the precompiled contract for modular exponentiation at address 0x05 as specified in
* https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise, the underlying function will succeed given the lack
* of a revert, but the result may be incorrectly interpreted as 0.
*/
function tryModExp(uint256 b, uint256 e, uint256 m) internal view returns (bool success, uint256 result) {
if (m == 0) return (false, 0);
assembly ("memory-safe") {
let ptr := mload(0x40)
// | Offset | Content | Content (Hex) |
// |-----------|------------|--------------------------------------------------------------------|
// | 0x00:0x1f | size of b | 0x0000000000000000000000000000000000000000000000000000000000000020 |
// | 0x20:0x3f | size of e | 0x0000000000000000000000000000000000000000000000000000000000000020 |
// | 0x40:0x5f | size of m | 0x0000000000000000000000000000000000000000000000000000000000000020 |
// | 0x60:0x7f | value of b | 0x<.............................................................b> |
// | 0x80:0x9f | value of e | 0x<.............................................................e> |
// | 0xa0:0xbf | value of m | 0x<.............................................................m> |
mstore(ptr, 0x20)
mstore(add(ptr, 0x20), 0x20)
mstore(add(ptr, 0x40), 0x20)
mstore(add(ptr, 0x60), b)
mstore(add(ptr, 0x80), e)
mstore(add(ptr, 0xa0), m)
// Given the result < m, it's guaranteed to fit in 32 bytes,
// so we can use the memory scratch space located at offset 0.
success := staticcall(gas(), 0x05, ptr, 0xc0, 0x00, 0x20)
result := mload(0x00)
}
}
/**
* @dev Variant of {modExp} that supports inputs of arbitrary length.
*/
function modExp(bytes memory b, bytes memory e, bytes memory m) internal view returns (bytes memory) {
(bool success, bytes memory result) = tryModExp(b, e, m);
if (!success) {
Panic.panic(Panic.DIVISION_BY_ZERO);
}
return result;
}
/**
* @dev Variant of {tryModExp} that supports inputs of arbitrary length.
*/
function tryModExp(
bytes memory b,
bytes memory e,
bytes memory m
) internal view returns (bool success, bytes memory result) {
if (_zeroBytes(m)) return (false, new bytes(0));
uint256 mLen = m.length;
// Encode call args in result and move the free memory pointer
result = abi.encodePacked(b.length, e.length, mLen, b, e, m);
assembly ("memory-safe") {
let dataPtr := add(result, 0x20)
// Write result on top of args to avoid allocating extra memory.
success := staticcall(gas(), 0x05, dataPtr, mload(result), dataPtr, mLen)
// Overwrite the length.
// result.length > returndatasize() is guaranteed because returndatasize() == m.length
mstore(result, mLen)
// Set the memory pointer after the returned data.
mstore(0x40, add(dataPtr, mLen))
}
}
/**
* @dev Returns whether the provided byte array is zero.
*/
function _zeroBytes(bytes memory byteArray) private pure returns (bool) {
for (uint256 i = 0; i < byteArray.length; ++i) {
if (byteArray[i] != 0) {
return false;
}
}
return true;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
* towards zero.
*
* This method is based on Newton's method for computing square roots; the algorithm is restricted to only
* using integer operations.
*/
function sqrt(uint256 a) internal pure returns (uint256) {
unchecked {
// Take care of easy edge cases when a == 0 or a == 1
if (a <= 1) {
return a;
}
// In this function, we use Newton's method to get a root of `f(x) := x² - a`. It involves building a
// sequence x_n that converges toward sqrt(a). For each iteration x_n, we also define the error between
// the current value as `ε_n = | x_n - sqrt(a) |`.
//
// For our first estimation, we consider `e` the smallest power of 2 which is bigger than the square root
// of the target. (i.e. `2**(e-1) ≤ sqrt(a) < 2**e`). We know that `e ≤ 128` because `(2¹²⁸)² = 2²⁵⁶` is
// bigger than any uint256.
//
// By noticing that
// `2**(e-1) ≤ sqrt(a) < 2**e → (2**(e-1))² ≤ a < (2**e)² → 2**(2*e-2) ≤ a < 2**(2*e)`
// we can deduce that `e - 1` is `log2(a) / 2`. We can thus compute `x_n = 2**(e-1)` using a method similar
// to the msb function.
uint256 aa = a;
uint256 xn = 1;
if (aa >= (1 << 128)) {
aa >>= 128;
xn <<= 64;
}
if (aa >= (1 << 64)) {
aa >>= 64;
xn <<= 32;
}
if (aa >= (1 << 32)) {
aa >>= 32;
xn <<= 16;
}
if (aa >= (1 << 16)) {
aa >>= 16;
xn <<= 8;
}
if (aa >= (1 << 8)) {
aa >>= 8;
xn <<= 4;
}
if (aa >= (1 << 4)) {
aa >>= 4;
xn <<= 2;
}
if (aa >= (1 << 2)) {
xn <<= 1;
}
// We now have x_n such that `x_n = 2**(e-1) ≤ sqrt(a) < 2**e = 2 * x_n`. This implies ε_n ≤ 2**(e-1).
//
// We can refine our estimation by noticing that the middle of that interval minimizes the error.
// If we move x_n to equal 2**(e-1) + 2**(e-2), then we reduce the error to ε_n ≤ 2**(e-2).
// This is going to be our x_0 (and ε_0)
xn = (3 * xn) >> 1; // ε_0 := | x_0 - sqrt(a) | ≤ 2**(e-2)
// From here, Newton's method give us:
// x_{n+1} = (x_n + a / x_n) / 2
//
// One should note that:
// x_{n+1}² - a = ((x_n + a / x_n) / 2)² - a
// = ((x_n² + a) / (2 * x_n))² - a
// = (x_n⁴ + 2 * a * x_n² + a²) / (4 * x_n²) - a
// = (x_n⁴ + 2 * a * x_n² + a² - 4 * a * x_n²) / (4 * x_n²)
// = (x_n⁴ - 2 * a * x_n² + a²) / (4 * x_n²)
// = (x_n² - a)² / (2 * x_n)²
// = ((x_n² - a) / (2 * x_n))²
// ≥ 0
// Which proves that for all n ≥ 1, sqrt(a) ≤ x_n
//
// This gives us the proof of quadratic convergence of the sequence:
// ε_{n+1} = | x_{n+1} - sqrt(a) |
// = | (x_n + a / x_n) / 2 - sqrt(a) |
// = | (x_n² + a - 2*x_n*sqrt(a)) / (2 * x_n) |
// = | (x_n - sqrt(a))² / (2 * x_n) |
// = | ε_n² / (2 * x_n) |
// = ε_n² / | (2 * x_n) |
//
// For the first iteration, we have a special case where x_0 is known:
// ε_1 = ε_0² / | (2 * x_0) |
// ≤ (2**(e-2))² / (2 * (2**(e-1) + 2**(e-2)))
// ≤ 2**(2*e-4) / (3 * 2**(e-1))
// ≤ 2**(e-3) / 3
// ≤ 2**(e-3-log2(3))
// ≤ 2**(e-4.5)
//
// For the following iterations, we use the fact that, 2**(e-1) ≤ sqrt(a) ≤ x_n:
// ε_{n+1} = ε_n² / | (2 * x_n) |
// ≤ (2**(e-k))² / (2 * 2**(e-1))
// ≤ 2**(2*e-2*k) / 2**e
// ≤ 2**(e-2*k)
xn = (xn + a / xn) >> 1; // ε_1 := | x_1 - sqrt(a) | ≤ 2**(e-4.5) -- special case, see above
xn = (xn + a / xn) >> 1; // ε_2 := | x_2 - sqrt(a) | ≤ 2**(e-9) -- general case with k = 4.5
xn = (xn + a / xn) >> 1; // ε_3 := | x_3 - sqrt(a) | ≤ 2**(e-18) -- general case with k = 9
xn = (xn + a / xn) >> 1; // ε_4 := | x_4 - sqrt(a) | ≤ 2**(e-36) -- general case with k = 18
xn = (xn + a / xn) >> 1; // ε_5 := | x_5 - sqrt(a) | ≤ 2**(e-72) -- general case with k = 36
xn = (xn + a / xn) >> 1; // ε_6 := | x_6 - sqrt(a) | ≤ 2**(e-144) -- general case with k = 72
// Because e ≤ 128 (as discussed during the first estimation phase), we know have reached a precision
// ε_6 ≤ 2**(e-144) < 1. Given we're operating on integers, then we can ensure that xn is now either
// sqrt(a) or sqrt(a) + 1.
return xn - SafeCast.toUint(xn > a / xn);
}
}
/**
* @dev Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + SafeCast.toUint(unsignedRoundsUp(rounding) && result * result < a);
}
}
/**
* @dev Return the log in base 2 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
uint256 exp;
unchecked {
exp = 128 * SafeCast.toUint(value > (1 << 128) - 1);
value >>= exp;
result += exp;
exp = 64 * SafeCast.toUint(value > (1 << 64) - 1);
value >>= exp;
result += exp;
exp = 32 * SafeCast.toUint(value > (1 << 32) - 1);
value >>= exp;
result += exp;
exp = 16 * SafeCast.toUint(value > (1 << 16) - 1);
value >>= exp;
result += exp;
exp = 8 * SafeCast.toUint(value > (1 << 8) - 1);
value >>= exp;
result += exp;
exp = 4 * SafeCast.toUint(value > (1 << 4) - 1);
value >>= exp;
result += exp;
exp = 2 * SafeCast.toUint(value > (1 << 2) - 1);
value >>= exp;
result += exp;
result += SafeCast.toUint(value > 1);
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << result < value);
}
}
/**
* @dev Return the log in base 10 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 10 ** result < value);
}
}
/**
* @dev Return the log in base 256 of a positive value rounded towards zero.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
uint256 isGt;
unchecked {
isGt = SafeCast.toUint(value > (1 << 128) - 1);
value >>= isGt * 128;
result += isGt * 16;
isGt = SafeCast.toUint(value > (1 << 64) - 1);
value >>= isGt * 64;
result += isGt * 8;
isGt = SafeCast.toUint(value > (1 << 32) - 1);
value >>= isGt * 32;
result += isGt * 4;
isGt = SafeCast.toUint(value > (1 << 16) - 1);
value >>= isGt * 16;
result += isGt * 2;
result += SafeCast.toUint(value > (1 << 8) - 1);
}
return result;
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << (result << 3) < value);
}
}
/**
* @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
*/
function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
return uint8(rounding) % 2 == 1;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.
pragma solidity ^0.8.20;
/**
* @dev Wrappers over Solidity's uintXX/intXX/bool casting operators with added overflow
* checks.
*
* Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
* easily result in undesired exploitation or bugs, since developers usually
* assume that overflows raise errors. `SafeCast` restores this intuition by
* reverting the transaction when such an operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeCast {
/**
* @dev Value doesn't fit in an uint of `bits` size.
*/
error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);
/**
* @dev An int value doesn't fit in an uint of `bits` size.
*/
error SafeCastOverflowedIntToUint(int256 value);
/**
* @dev Value doesn't fit in an int of `bits` size.
*/
error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);
/**
* @dev An uint value doesn't fit in an int of `bits` size.
*/
error SafeCastOverflowedUintToInt(uint256 value);
/**
* @dev Returns the downcasted uint248 from uint256, reverting on
* overflow (when the input is greater than largest uint248).
*
* Counterpart to Solidity's `uint248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*/
function toUint248(uint256 value) internal pure returns (uint248) {
if (value > type(uint248).max) {
revert SafeCastOverflowedUintDowncast(248, value);
}
return uint248(value);
}
/**
* @dev Returns the downcasted uint240 from uint256, reverting on
* overflow (when the input is greater than largest uint240).
*
* Counterpart to Solidity's `uint240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*/
function toUint240(uint256 value) internal pure returns (uint240) {
if (value > type(uint240).max) {
revert SafeCastOverflowedUintDowncast(240, value);
}
return uint240(value);
}
/**
* @dev Returns the downcasted uint232 from uint256, reverting on
* overflow (when the input is greater than largest uint232).
*
* Counterpart to Solidity's `uint232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*/
function toUint232(uint256 value) internal pure returns (uint232) {
if (value > type(uint232).max) {
revert SafeCastOverflowedUintDowncast(232, value);
}
return uint232(value);
}
/**
* @dev Returns the downcasted uint224 from uint256, reverting on
* overflow (when the input is greater than largest uint224).
*
* Counterpart to Solidity's `uint224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*/
function toUint224(uint256 value) internal pure returns (uint224) {
if (value > type(uint224).max) {
revert SafeCastOverflowedUintDowncast(224, value);
}
return uint224(value);
}
/**
* @dev Returns the downcasted uint216 from uint256, reverting on
* overflow (when the input is greater than largest uint216).
*
* Counterpart to Solidity's `uint216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*/
function toUint216(uint256 value) internal pure returns (uint216) {
if (value > type(uint216).max) {
revert SafeCastOverflowedUintDowncast(216, value);
}
return uint216(value);
}
/**
* @dev Returns the downcasted uint208 from uint256, reverting on
* overflow (when the input is greater than largest uint208).
*
* Counterpart to Solidity's `uint208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*/
function toUint208(uint256 value) internal pure returns (uint208) {
if (value > type(uint208).max) {
revert SafeCastOverflowedUintDowncast(208, value);
}
return uint208(value);
}
/**
* @dev Returns the downcasted uint200 from uint256, reverting on
* overflow (when the input is greater than largest uint200).
*
* Counterpart to Solidity's `uint200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*/
function toUint200(uint256 value) internal pure returns (uint200) {
if (value > type(uint200).max) {
revert SafeCastOverflowedUintDowncast(200, value);
}
return uint200(value);
}
/**
* @dev Returns the downcasted uint192 from uint256, reverting on
* overflow (when the input is greater than largest uint192).
*
* Counterpart to Solidity's `uint192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*/
function toUint192(uint256 value) internal pure returns (uint192) {
if (value > type(uint192).max) {
revert SafeCastOverflowedUintDowncast(192, value);
}
return uint192(value);
}
/**
* @dev Returns the downcasted uint184 from uint256, reverting on
* overflow (when the input is greater than largest uint184).
*
* Counterpart to Solidity's `uint184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*/
function toUint184(uint256 value) internal pure returns (uint184) {
if (value > type(uint184).max) {
revert SafeCastOverflowedUintDowncast(184, value);
}
return uint184(value);
}
/**
* @dev Returns the downcasted uint176 from uint256, reverting on
* overflow (when the input is greater than largest uint176).
*
* Counterpart to Solidity's `uint176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*/
function toUint176(uint256 value) internal pure returns (uint176) {
if (value > type(uint176).max) {
revert SafeCastOverflowedUintDowncast(176, value);
}
return uint176(value);
}
/**
* @dev Returns the downcasted uint168 from uint256, reverting on
* overflow (when the input is greater than largest uint168).
*
* Counterpart to Solidity's `uint168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*/
function toUint168(uint256 value) internal pure returns (uint168) {
if (value > type(uint168).max) {
revert SafeCastOverflowedUintDowncast(168, value);
}
return uint168(value);
}
/**
* @dev Returns the downcasted uint160 from uint256, reverting on
* overflow (when the input is greater than largest uint160).
*
* Counterpart to Solidity's `uint160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*/
function toUint160(uint256 value) internal pure returns (uint160) {
if (value > type(uint160).max) {
revert SafeCastOverflowedUintDowncast(160, value);
}
return uint160(value);
}
/**
* @dev Returns the downcasted uint152 from uint256, reverting on
* overflow (when the input is greater than largest uint152).
*
* Counterpart to Solidity's `uint152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*/
function toUint152(uint256 value) internal pure returns (uint152) {
if (value > type(uint152).max) {
revert SafeCastOverflowedUintDowncast(152, value);
}
return uint152(value);
}
/**
* @dev Returns the downcasted uint144 from uint256, reverting on
* overflow (when the input is greater than largest uint144).
*
* Counterpart to Solidity's `uint144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*/
function toUint144(uint256 value) internal pure returns (uint144) {
if (value > type(uint144).max) {
revert SafeCastOverflowedUintDowncast(144, value);
}
return uint144(value);
}
/**
* @dev Returns the downcasted uint136 from uint256, reverting on
* overflow (when the input is greater than largest uint136).
*
* Counterpart to Solidity's `uint136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*/
function toUint136(uint256 value) internal pure returns (uint136) {
if (value > type(uint136).max) {
revert SafeCastOverflowedUintDowncast(136, value);
}
return uint136(value);
}
/**
* @dev Returns the downcasted uint128 from uint256, reverting on
* overflow (when the input is greater than largest uint128).
*
* Counterpart to Solidity's `uint128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*/
function toUint128(uint256 value) internal pure returns (uint128) {
if (value > type(uint128).max) {
revert SafeCastOverflowedUintDowncast(128, value);
}
return uint128(value);
}
/**
* @dev Returns the downcasted uint120 from uint256, reverting on
* overflow (when the input is greater than largest uint120).
*
* Counterpart to Solidity's `uint120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*/
function toUint120(uint256 value) internal pure returns (uint120) {
if (value > type(uint120).max) {
revert SafeCastOverflowedUintDowncast(120, value);
}
return uint120(value);
}
/**
* @dev Returns the downcasted uint112 from uint256, reverting on
* overflow (when the input is greater than largest uint112).
*
* Counterpart to Solidity's `uint112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*/
function toUint112(uint256 value) internal pure returns (uint112) {
if (value > type(uint112).max) {
revert SafeCastOverflowedUintDowncast(112, value);
}
return uint112(value);
}
/**
* @dev Returns the downcasted uint104 from uint256, reverting on
* overflow (when the input is greater than largest uint104).
*
* Counterpart to Solidity's `uint104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*/
function toUint104(uint256 value) internal pure returns (uint104) {
if (value > type(uint104).max) {
revert SafeCastOverflowedUintDowncast(104, value);
}
return uint104(value);
}
/**
* @dev Returns the downcasted uint96 from uint256, reverting on
* overflow (when the input is greater than largest uint96).
*
* Counterpart to Solidity's `uint96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*/
function toUint96(uint256 value) internal pure returns (uint96) {
if (value > type(uint96).max) {
revert SafeCastOverflowedUintDowncast(96, value);
}
return uint96(value);
}
/**
* @dev Returns the downcasted uint88 from uint256, reverting on
* overflow (when the input is greater than largest uint88).
*
* Counterpart to Solidity's `uint88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*/
function toUint88(uint256 value) internal pure returns (uint88) {
if (value > type(uint88).max) {
revert SafeCastOverflowedUintDowncast(88, value);
}
return uint88(value);
}
/**
* @dev Returns the downcasted uint80 from uint256, reverting on
* overflow (when the input is greater than largest uint80).
*
* Counterpart to Solidity's `uint80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*/
function toUint80(uint256 value) internal pure returns (uint80) {
if (value > type(uint80).max) {
revert SafeCastOverflowedUintDowncast(80, value);
}
return uint80(value);
}
/**
* @dev Returns the downcasted uint72 from uint256, reverting on
* overflow (when the input is greater than largest uint72).
*
* Counterpart to Solidity's `uint72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*/
function toUint72(uint256 value) internal pure returns (uint72) {
if (value > type(uint72).max) {
revert SafeCastOverflowedUintDowncast(72, value);
}
return uint72(value);
}
/**
* @dev Returns the downcasted uint64 from uint256, reverting on
* overflow (when the input is greater than largest uint64).
*
* Counterpart to Solidity's `uint64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*/
function toUint64(uint256 value) internal pure returns (uint64) {
if (value > type(uint64).max) {
revert SafeCastOverflowedUintDowncast(64, value);
}
return uint64(value);
}
/**
* @dev Returns the downcasted uint56 from uint256, reverting on
* overflow (when the input is greater than largest uint56).
*
* Counterpart to Solidity's `uint56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*/
function toUint56(uint256 value) internal pure returns (uint56) {
if (value > type(uint56).max) {
revert SafeCastOverflowedUintDowncast(56, value);
}
return uint56(value);
}
/**
* @dev Returns the downcasted uint48 from uint256, reverting on
* overflow (when the input is greater than largest uint48).
*
* Counterpart to Solidity's `uint48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*/
function toUint48(uint256 value) internal pure returns (uint48) {
if (value > type(uint48).max) {
revert SafeCastOverflowedUintDowncast(48, value);
}
return uint48(value);
}
/**
* @dev Returns the downcasted uint40 from uint256, reverting on
* overflow (when the input is greater than largest uint40).
*
* Counterpart to Solidity's `uint40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*/
function toUint40(uint256 value) internal pure returns (uint40) {
if (value > type(uint40).max) {
revert SafeCastOverflowedUintDowncast(40, value);
}
return uint40(value);
}
/**
* @dev Returns the downcasted uint32 from uint256, reverting on
* overflow (when the input is greater than largest uint32).
*
* Counterpart to Solidity's `uint32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*/
function toUint32(uint256 value) internal pure returns (uint32) {
if (value > type(uint32).max) {
revert SafeCastOverflowedUintDowncast(32, value);
}
return uint32(value);
}
/**
* @dev Returns the downcasted uint24 from uint256, reverting on
* overflow (when the input is greater than largest uint24).
*
* Counterpart to Solidity's `uint24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*/
function toUint24(uint256 value) internal pure returns (uint24) {
if (value > type(uint24).max) {
revert SafeCastOverflowedUintDowncast(24, value);
}
return uint24(value);
}
/**
* @dev Returns the downcasted uint16 from uint256, reverting on
* overflow (when the input is greater than largest uint16).
*
* Counterpart to Solidity's `uint16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*/
function toUint16(uint256 value) internal pure returns (uint16) {
if (value > type(uint16).max) {
revert SafeCastOverflowedUintDowncast(16, value);
}
return uint16(value);
}
/**
* @dev Returns the downcasted uint8 from uint256, reverting on
* overflow (when the input is greater than largest uint8).
*
* Counterpart to Solidity's `uint8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*/
function toUint8(uint256 value) internal pure returns (uint8) {
if (value > type(uint8).max) {
revert SafeCastOverflowedUintDowncast(8, value);
}
return uint8(value);
}
/**
* @dev Converts a signed int256 into an unsigned uint256.
*
* Requirements:
*
* - input must be greater than or equal to 0.
*/
function toUint256(int256 value) internal pure returns (uint256) {
if (value < 0) {
revert SafeCastOverflowedIntToUint(value);
}
return uint256(value);
}
/**
* @dev Returns the downcasted int248 from int256, reverting on
* overflow (when the input is less than smallest int248 or
* greater than largest int248).
*
* Counterpart to Solidity's `int248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*/
function toInt248(int256 value) internal pure returns (int248 downcasted) {
downcasted = int248(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(248, value);
}
}
/**
* @dev Returns the downcasted int240 from int256, reverting on
* overflow (when the input is less than smallest int240 or
* greater than largest int240).
*
* Counterpart to Solidity's `int240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*/
function toInt240(int256 value) internal pure returns (int240 downcasted) {
downcasted = int240(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(240, value);
}
}
/**
* @dev Returns the downcasted int232 from int256, reverting on
* overflow (when the input is less than smallest int232 or
* greater than largest int232).
*
* Counterpart to Solidity's `int232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*/
function toInt232(int256 value) internal pure returns (int232 downcasted) {
downcasted = int232(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(232, value);
}
}
/**
* @dev Returns the downcasted int224 from int256, reverting on
* overflow (when the input is less than smallest int224 or
* greater than largest int224).
*
* Counterpart to Solidity's `int224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*/
function toInt224(int256 value) internal pure returns (int224 downcasted) {
downcasted = int224(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(224, value);
}
}
/**
* @dev Returns the downcasted int216 from int256, reverting on
* overflow (when the input is less than smallest int216 or
* greater than largest int216).
*
* Counterpart to Solidity's `int216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*/
function toInt216(int256 value) internal pure returns (int216 downcasted) {
downcasted = int216(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(216, value);
}
}
/**
* @dev Returns the downcasted int208 from int256, reverting on
* overflow (when the input is less than smallest int208 or
* greater than largest int208).
*
* Counterpart to Solidity's `int208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*/
function toInt208(int256 value) internal pure returns (int208 downcasted) {
downcasted = int208(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(208, value);
}
}
/**
* @dev Returns the downcasted int200 from int256, reverting on
* overflow (when the input is less than smallest int200 or
* greater than largest int200).
*
* Counterpart to Solidity's `int200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*/
function toInt200(int256 value) internal pure returns (int200 downcasted) {
downcasted = int200(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(200, value);
}
}
/**
* @dev Returns the downcasted int192 from int256, reverting on
* overflow (when the input is less than smallest int192 or
* greater than largest int192).
*
* Counterpart to Solidity's `int192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*/
function toInt192(int256 value) internal pure returns (int192 downcasted) {
downcasted = int192(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(192, value);
}
}
/**
* @dev Returns the downcasted int184 from int256, reverting on
* overflow (when the input is less than smallest int184 or
* greater than largest int184).
*
* Counterpart to Solidity's `int184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*/
function toInt184(int256 value) internal pure returns (int184 downcasted) {
downcasted = int184(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(184, value);
}
}
/**
* @dev Returns the downcasted int176 from int256, reverting on
* overflow (when the input is less than smallest int176 or
* greater than largest int176).
*
* Counterpart to Solidity's `int176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*/
function toInt176(int256 value) internal pure returns (int176 downcasted) {
downcasted = int176(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(176, value);
}
}
/**
* @dev Returns the downcasted int168 from int256, reverting on
* overflow (when the input is less than smallest int168 or
* greater than largest int168).
*
* Counterpart to Solidity's `int168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*/
function toInt168(int256 value) internal pure returns (int168 downcasted) {
downcasted = int168(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(168, value);
}
}
/**
* @dev Returns the downcasted int160 from int256, reverting on
* overflow (when the input is less than smallest int160 or
* greater than largest int160).
*
* Counterpart to Solidity's `int160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*/
function toInt160(int256 value) internal pure returns (int160 downcasted) {
downcasted = int160(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(160, value);
}
}
/**
* @dev Returns the downcasted int152 from int256, reverting on
* overflow (when the input is less than smallest int152 or
* greater than largest int152).
*
* Counterpart to Solidity's `int152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*/
function toInt152(int256 value) internal pure returns (int152 downcasted) {
downcasted = int152(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(152, value);
}
}
/**
* @dev Returns the downcasted int144 from int256, reverting on
* overflow (when the input is less than smallest int144 or
* greater than largest int144).
*
* Counterpart to Solidity's `int144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*/
function toInt144(int256 value) internal pure returns (int144 downcasted) {
downcasted = int144(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(144, value);
}
}
/**
* @dev Returns the downcasted int136 from int256, reverting on
* overflow (when the input is less than smallest int136 or
* greater than largest int136).
*
* Counterpart to Solidity's `int136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*/
function toInt136(int256 value) internal pure returns (int136 downcasted) {
downcasted = int136(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(136, value);
}
}
/**
* @dev Returns the downcasted int128 from int256, reverting on
* overflow (when the input is less than smallest int128 or
* greater than largest int128).
*
* Counterpart to Solidity's `int128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*/
function toInt128(int256 value) internal pure returns (int128 downcasted) {
downcasted = int128(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(128, value);
}
}
/**
* @dev Returns the downcasted int120 from int256, reverting on
* overflow (when the input is less than smallest int120 or
* greater than largest int120).
*
* Counterpart to Solidity's `int120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*/
function toInt120(int256 value) internal pure returns (int120 downcasted) {
downcasted = int120(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(120, value);
}
}
/**
* @dev Returns the downcasted int112 from int256, reverting on
* overflow (when the input is less than smallest int112 or
* greater than largest int112).
*
* Counterpart to Solidity's `int112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*/
function toInt112(int256 value) internal pure returns (int112 downcasted) {
downcasted = int112(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(112, value);
}
}
/**
* @dev Returns the downcasted int104 from int256, reverting on
* overflow (when the input is less than smallest int104 or
* greater than largest int104).
*
* Counterpart to Solidity's `int104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*/
function toInt104(int256 value) internal pure returns (int104 downcasted) {
downcasted = int104(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(104, value);
}
}
/**
* @dev Returns the downcasted int96 from int256, reverting on
* overflow (when the input is less than smallest int96 or
* greater than largest int96).
*
* Counterpart to Solidity's `int96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*/
function toInt96(int256 value) internal pure returns (int96 downcasted) {
downcasted = int96(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(96, value);
}
}
/**
* @dev Returns the downcasted int88 from int256, reverting on
* overflow (when the input is less than smallest int88 or
* greater than largest int88).
*
* Counterpart to Solidity's `int88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*/
function toInt88(int256 value) internal pure returns (int88 downcasted) {
downcasted = int88(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(88, value);
}
}
/**
* @dev Returns the downcasted int80 from int256, reverting on
* overflow (when the input is less than smallest int80 or
* greater than largest int80).
*
* Counterpart to Solidity's `int80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*/
function toInt80(int256 value) internal pure returns (int80 downcasted) {
downcasted = int80(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(80, value);
}
}
/**
* @dev Returns the downcasted int72 from int256, reverting on
* overflow (when the input is less than smallest int72 or
* greater than largest int72).
*
* Counterpart to Solidity's `int72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*/
function toInt72(int256 value) internal pure returns (int72 downcasted) {
downcasted = int72(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(72, value);
}
}
/**
* @dev Returns the downcasted int64 from int256, reverting on
* overflow (when the input is less than smallest int64 or
* greater than largest int64).
*
* Counterpart to Solidity's `int64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*/
function toInt64(int256 value) internal pure returns (int64 downcasted) {
downcasted = int64(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(64, value);
}
}
/**
* @dev Returns the downcasted int56 from int256, reverting on
* overflow (when the input is less than smallest int56 or
* greater than largest int56).
*
* Counterpart to Solidity's `int56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*/
function toInt56(int256 value) internal pure returns (int56 downcasted) {
downcasted = int56(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(56, value);
}
}
/**
* @dev Returns the downcasted int48 from int256, reverting on
* overflow (when the input is less than smallest int48 or
* greater than largest int48).
*
* Counterpart to Solidity's `int48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*/
function toInt48(int256 value) internal pure returns (int48 downcasted) {
downcasted = int48(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(48, value);
}
}
/**
* @dev Returns the downcasted int40 from int256, reverting on
* overflow (when the input is less than smallest int40 or
* greater than largest int40).
*
* Counterpart to Solidity's `int40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*/
function toInt40(int256 value) internal pure returns (int40 downcasted) {
downcasted = int40(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(40, value);
}
}
/**
* @dev Returns the downcasted int32 from int256, reverting on
* overflow (when the input is less than smallest int32 or
* greater than largest int32).
*
* Counterpart to Solidity's `int32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*/
function toInt32(int256 value) internal pure returns (int32 downcasted) {
downcasted = int32(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(32, value);
}
}
/**
* @dev Returns the downcasted int24 from int256, reverting on
* overflow (when the input is less than smallest int24 or
* greater than largest int24).
*
* Counterpart to Solidity's `int24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*/
function toInt24(int256 value) internal pure returns (int24 downcasted) {
downcasted = int24(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(24, value);
}
}
/**
* @dev Returns the downcasted int16 from int256, reverting on
* overflow (when the input is less than smallest int16 or
* greater than largest int16).
*
* Counterpart to Solidity's `int16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*/
function toInt16(int256 value) internal pure returns (int16 downcasted) {
downcasted = int16(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(16, value);
}
}
/**
* @dev Returns the downcasted int8 from int256, reverting on
* overflow (when the input is less than smallest int8 or
* greater than largest int8).
*
* Counterpart to Solidity's `int8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*/
function toInt8(int256 value) internal pure returns (int8 downcasted) {
downcasted = int8(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(8, value);
}
}
/**
* @dev Converts an unsigned uint256 into a signed int256.
*
* Requirements:
*
* - input must be less than or equal to maxInt256.
*/
function toInt256(uint256 value) internal pure returns (int256) {
// Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
if (value > uint256(type(int256).max)) {
revert SafeCastOverflowedUintToInt(value);
}
return int256(value);
}
/**
* @dev Cast a boolean (false or true) to a uint256 (0 or 1) with no jump.
*/
function toUint(bool b) internal pure returns (uint256 u) {
assembly ("memory-safe") {
u := iszero(iszero(b))
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/Panic.sol)
pragma solidity ^0.8.20;
/**
* @dev Helper library for emitting standardized panic codes.
*
* ```solidity
* contract Example {
* using Panic for uint256;
*
* // Use any of the declared internal constants
* function foo() { Panic.GENERIC.panic(); }
*
* // Alternatively
* function foo() { Panic.panic(Panic.GENERIC); }
* }
* ```
*
* Follows the list from https://github.com/ethereum/solidity/blob/v0.8.24/libsolutil/ErrorCodes.h[libsolutil].
*
* _Available since v5.1._
*/
// slither-disable-next-line unused-state
library Panic {
/// @dev generic / unspecified error
uint256 internal constant GENERIC = 0x00;
/// @dev used by the assert() builtin
uint256 internal constant ASSERT = 0x01;
/// @dev arithmetic underflow or overflow
uint256 internal constant UNDER_OVERFLOW = 0x11;
/// @dev division or modulo by zero
uint256 internal constant DIVISION_BY_ZERO = 0x12;
/// @dev enum conversion error
uint256 internal constant ENUM_CONVERSION_ERROR = 0x21;
/// @dev invalid encoding in storage
uint256 internal constant STORAGE_ENCODING_ERROR = 0x22;
/// @dev empty array pop
uint256 internal constant EMPTY_ARRAY_POP = 0x31;
/// @dev array out of bounds access
uint256 internal constant ARRAY_OUT_OF_BOUNDS = 0x32;
/// @dev resource error (too large allocation or too large array)
uint256 internal constant RESOURCE_ERROR = 0x41;
/// @dev calling invalid internal function
uint256 internal constant INVALID_INTERNAL_FUNCTION = 0x51;
/// @dev Reverts with a panic code. Recommended to use with
/// the internal constants with predefined codes.
function panic(uint256 code) internal pure {
assembly ("memory-safe") {
mstore(0x00, 0x4e487b71)
mstore(0x20, code)
revert(0x1c, 0x24)
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/structs/EnumerableMap.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableMap.js.
pragma solidity ^0.8.20;
import {EnumerableSet} from "./EnumerableSet.sol";
/**
* @dev Library for managing an enumerable variant of Solidity's
* https://solidity.readthedocs.io/en/latest/types.html#mapping-types[`mapping`]
* type.
*
* Maps have the following properties:
*
* - Entries are added, removed, and checked for existence in constant time
* (O(1)).
* - Entries are enumerated in O(n). No guarantees are made on the ordering.
*
* ```solidity
* contract Example {
* // Add the library methods
* using EnumerableMap for EnumerableMap.UintToAddressMap;
*
* // Declare a set state variable
* EnumerableMap.UintToAddressMap private myMap;
* }
* ```
*
* The following map types are supported:
*
* - `uint256 -> address` (`UintToAddressMap`) since v3.0.0
* - `address -> uint256` (`AddressToUintMap`) since v4.6.0
* - `bytes32 -> bytes32` (`Bytes32ToBytes32Map`) since v4.6.0
* - `uint256 -> uint256` (`UintToUintMap`) since v4.7.0
* - `bytes32 -> uint256` (`Bytes32ToUintMap`) since v4.7.0
* - `uint256 -> bytes32` (`UintToBytes32Map`) since v5.1.0
* - `address -> address` (`AddressToAddressMap`) since v5.1.0
* - `address -> bytes32` (`AddressToBytes32Map`) since v5.1.0
* - `bytes32 -> address` (`Bytes32ToAddressMap`) since v5.1.0
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
* unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableMap, you can either remove all elements one by one or create a fresh instance using an
* array of EnumerableMap.
* ====
*/
library EnumerableMap {
using EnumerableSet for EnumerableSet.Bytes32Set;
// To implement this library for multiple types with as little code repetition as possible, we write it in
// terms of a generic Map type with bytes32 keys and values. The Map implementation uses private functions,
// and user-facing implementations such as `UintToAddressMap` are just wrappers around the underlying Map.
// This means that we can only create new EnumerableMaps for types that fit in bytes32.
/**
* @dev Query for a nonexistent map key.
*/
error EnumerableMapNonexistentKey(bytes32 key);
struct Bytes32ToBytes32Map {
// Storage of keys
EnumerableSet.Bytes32Set _keys;
mapping(bytes32 key => bytes32) _values;
}
/**
* @dev Adds a key-value pair to a map, or updates the value for an existing
* key. O(1).
*
* Returns true if the key was added to the map, that is if it was not
* already present.
*/
function set(Bytes32ToBytes32Map storage map, bytes32 key, bytes32 value) internal returns (bool) {
map._values[key] = value;
return map._keys.add(key);
}
/**
* @dev Removes a key-value pair from a map. O(1).
*
* Returns true if the key was removed from the map, that is if it was present.
*/
function remove(Bytes32ToBytes32Map storage map, bytes32 key) internal returns (bool) {
delete map._values[key];
return map._keys.remove(key);
}
/**
* @dev Returns true if the key is in the map. O(1).
*/
function contains(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool) {
return map._keys.contains(key);
}
/**
* @dev Returns the number of key-value pairs in the map. O(1).
*/
function length(Bytes32ToBytes32Map storage map) internal view returns (uint256) {
return map._keys.length();
}
/**
* @dev Returns the key-value pair stored at position `index` in the map. O(1).
*
* Note that there are no guarantees on the ordering of entries inside the
* array, and it may change when more entries are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32ToBytes32Map storage map, uint256 index) internal view returns (bytes32 key, bytes32 value) {
bytes32 atKey = map._keys.at(index);
return (atKey, map._values[atKey]);
}
/**
* @dev Tries to returns the value associated with `key`. O(1).
* Does not revert if `key` is not in the map.
*/
function tryGet(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool exists, bytes32 value) {
bytes32 val = map._values[key];
if (val == bytes32(0)) {
return (contains(map, key), bytes32(0));
} else {
return (true, val);
}
}
/**
* @dev Returns the value associated with `key`. O(1).
*
* Requirements:
*
* - `key` must be in the map.
*/
function get(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bytes32) {
bytes32 value = map._values[key];
if (value == 0 && !contains(map, key)) {
revert EnumerableMapNonexistentKey(key);
}
return value;
}
/**
* @dev Return the an array containing all the keys
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function keys(Bytes32ToBytes32Map storage map) internal view returns (bytes32[] memory) {
return map._keys.values();
}
// UintToUintMap
struct UintToUintMap {
Bytes32ToBytes32Map _inner;
}
/**
* @dev Adds a key-value pair to a map, or updates the value for an existing
* key. O(1).
*
* Returns true if the key was added to the map, that is if it was not
* already present.
*/
function set(UintToUintMap storage map, uint256 key, uint256 value) internal returns (bool) {
return set(map._inner, bytes32(key), bytes32(value));
}
/**
* @dev Removes a value from a map. O(1).
*
* Returns true if the key was removed from the map, that is if it was present.
*/
function remove(UintToUintMap storage map, uint256 key) internal returns (bool) {
return remove(map._inner, bytes32(key));
}
/**
* @dev Returns true if the key is in the map. O(1).
*/
function contains(UintToUintMap storage map, uint256 key) internal view returns (bool) {
return contains(map._inner, bytes32(key));
}
/**
* @dev Returns the number of elements in the map. O(1).
*/
function length(UintToUintMap storage map) internal view returns (uint256) {
return length(map._inner);
}
/**
* @dev Returns the element stored at position `index` in the map. O(1).
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintToUintMap storage map, uint256 index) internal view returns (uint256 key, uint256 value) {
(bytes32 atKey, bytes32 val) = at(map._inner, index);
return (uint256(atKey), uint256(val));
}
/**
* @dev Tries to returns the value associated with `key`. O(1).
* Does not revert if `key` is not in the map.
*/
function tryGet(UintToUintMap storage map, uint256 key) internal view returns (bool exists, uint256 value) {
(bool success, bytes32 val) = tryGet(map._inner, bytes32(key));
return (success, uint256(val));
}
/**
* @dev Returns the value associated with `key`. O(1).
*
* Requirements:
*
* - `key` must be in the map.
*/
function get(UintToUintMap storage map, uint256 key) internal view returns (uint256) {
return uint256(get(map._inner, bytes32(key)));
}
/**
* @dev Return the an array containing all the keys
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function keys(UintToUintMap storage map) internal view returns (uint256[] memory) {
bytes32[] memory store = keys(map._inner);
uint256[] memory result;
assembly ("memory-safe") {
result := store
}
return result;
}
// UintToAddressMap
struct UintToAddressMap {
Bytes32ToBytes32Map _inner;
}
/**
* @dev Adds a key-value pair to a map, or updates the value for an existing
* key. O(1).
*
* Returns true if the key was added to the map, that is if it was not
* already present.
*/
function set(UintToAddressMap storage map, uint256 key, address value) internal returns (bool) {
return set(map._inner, bytes32(key), bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a map. O(1).
*
* Returns true if the key was removed from the map, that is if it was present.
*/
function remove(UintToAddressMap storage map, uint256 key) internal returns (bool) {
return remove(map._inner, bytes32(key));
}
/**
* @dev Returns true if the key is in the map. O(1).
*/
function contains(UintToAddressMap storage map, uint256 key) internal view returns (bool) {
return contains(map._inner, bytes32(key));
}
/**
* @dev Returns the number of elements in the map. O(1).
*/
function length(UintToAddressMap storage map) internal view returns (uint256) {
return length(map._inner);
}
/**
* @dev Returns the element stored at position `index` in the map. O(1).
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintToAddressMap storage map, uint256 index) internal view returns (uint256 key, address value) {
(bytes32 atKey, bytes32 val) = at(map._inner, index);
return (uint256(atKey), address(uint160(uint256(val))));
}
/**
* @dev Tries to returns the value associated with `key`. O(1).
* Does not revert if `key` is not in the map.
*/
function tryGet(UintToAddressMap storage map, uint256 key) internal view returns (bool exists, address value) {
(bool success, bytes32 val) = tryGet(map._inner, bytes32(key));
return (success, address(uint160(uint256(val))));
}
/**
* @dev Returns the value associated with `key`. O(1).
*
* Requirements:
*
* - `key` must be in the map.
*/
function get(UintToAddressMap storage map, uint256 key) internal view returns (address) {
return address(uint160(uint256(get(map._inner, bytes32(key)))));
}
/**
* @dev Return the an array containing all the keys
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function keys(UintToAddressMap storage map) internal view returns (uint256[] memory) {
bytes32[] memory store = keys(map._inner);
uint256[] memory result;
assembly ("memory-safe") {
result := store
}
return result;
}
// UintToBytes32Map
struct UintToBytes32Map {
Bytes32ToBytes32Map _inner;
}
/**
* @dev Adds a key-value pair to a map, or updates the value for an existing
* key. O(1).
*
* Returns true if the key was added to the map, that is if it was not
* already present.
*/
function set(UintToBytes32Map storage map, uint256 key, bytes32 value) internal returns (bool) {
return set(map._inner, bytes32(key), value);
}
/**
* @dev Removes a value from a map. O(1).
*
* Returns true if the key was removed from the map, that is if it was present.
*/
function remove(UintToBytes32Map storage map, uint256 key) internal returns (bool) {
return remove(map._inner, bytes32(key));
}
/**
* @dev Returns true if the key is in the map. O(1).
*/
function contains(UintToBytes32Map storage map, uint256 key) internal view returns (bool) {
return contains(map._inner, bytes32(key));
}
/**
* @dev Returns the number of elements in the map. O(1).
*/
function length(UintToBytes32Map storage map) internal view returns (uint256) {
return length(map._inner);
}
/**
* @dev Returns the element stored at position `index` in the map. O(1).
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintToBytes32Map storage map, uint256 index) internal view returns (uint256 key, bytes32 value) {
(bytes32 atKey, bytes32 val) = at(map._inner, index);
return (uint256(atKey), val);
}
/**
* @dev Tries to returns the value associated with `key`. O(1).
* Does not revert if `key` is not in the map.
*/
function tryGet(UintToBytes32Map storage map, uint256 key) internal view returns (bool exists, bytes32 value) {
(bool success, bytes32 val) = tryGet(map._inner, bytes32(key));
return (success, val);
}
/**
* @dev Returns the value associated with `key`. O(1).
*
* Requirements:
*
* - `key` must be in the map.
*/
function get(UintToBytes32Map storage map, uint256 key) internal view returns (bytes32) {
return get(map._inner, bytes32(key));
}
/**
* @dev Return the an array containing all the keys
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function keys(UintToBytes32Map storage map) internal view returns (uint256[] memory) {
bytes32[] memory store = keys(map._inner);
uint256[] memory result;
assembly ("memory-safe") {
result := store
}
return result;
}
// AddressToUintMap
struct AddressToUintMap {
Bytes32ToBytes32Map _inner;
}
/**
* @dev Adds a key-value pair to a map, or updates the value for an existing
* key. O(1).
*
* Returns true if the key was added to the map, that is if it was not
* already present.
*/
function set(AddressToUintMap storage map, address key, uint256 value) internal returns (bool) {
return set(map._inner, bytes32(uint256(uint160(key))), bytes32(value));
}
/**
* @dev Removes a value from a map. O(1).
*
* Returns true if the key was removed from the map, that is if it was present.
*/
function remove(AddressToUintMap storage map, address key) internal returns (bool) {
return remove(map._inner, bytes32(uint256(uint160(key))));
}
/**
* @dev Returns true if the key is in the map. O(1).
*/
function contains(AddressToUintMap storage map, address key) internal view returns (bool) {
return contains(map._inner, bytes32(uint256(uint160(key))));
}
/**
* @dev Returns the number of elements in the map. O(1).
*/
function length(AddressToUintMap storage map) internal view returns (uint256) {
return length(map._inner);
}
/**
* @dev Returns the element stored at position `index` in the map. O(1).
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressToUintMap storage map, uint256 index) internal view returns (address key, uint256 value) {
(bytes32 atKey, bytes32 val) = at(map._inner, index);
return (address(uint160(uint256(atKey))), uint256(val));
}
/**
* @dev Tries to returns the value associated with `key`. O(1).
* Does not revert if `key` is not in the map.
*/
function tryGet(AddressToUintMap storage map, address key) internal view returns (bool exists, uint256 value) {
(bool success, bytes32 val) = tryGet(map._inner, bytes32(uint256(uint160(key))));
return (success, uint256(val));
}
/**
* @dev Returns the value associated with `key`. O(1).
*
* Requirements:
*
* - `key` must be in the map.
*/
function get(AddressToUintMap storage map, address key) internal view returns (uint256) {
return uint256(get(map._inner, bytes32(uint256(uint160(key)))));
}
/**
* @dev Return the an array containing all the keys
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function keys(AddressToUintMap storage map) internal view returns (address[] memory) {
bytes32[] memory store = keys(map._inner);
address[] memory result;
assembly ("memory-safe") {
result := store
}
return result;
}
// AddressToAddressMap
struct AddressToAddressMap {
Bytes32ToBytes32Map _inner;
}
/**
* @dev Adds a key-value pair to a map, or updates the value for an existing
* key. O(1).
*
* Returns true if the key was added to the map, that is if it was not
* already present.
*/
function set(AddressToAddressMap storage map, address key, address value) internal returns (bool) {
return set(map._inner, bytes32(uint256(uint160(key))), bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a map. O(1).
*
* Returns true if the key was removed from the map, that is if it was present.
*/
function remove(AddressToAddressMap storage map, address key) internal returns (bool) {
return remove(map._inner, bytes32(uint256(uint160(key))));
}
/**
* @dev Returns true if the key is in the map. O(1).
*/
function contains(AddressToAddressMap storage map, address key) internal view returns (bool) {
return contains(map._inner, bytes32(uint256(uint160(key))));
}
/**
* @dev Returns the number of elements in the map. O(1).
*/
function length(AddressToAddressMap storage map) internal view returns (uint256) {
return length(map._inner);
}
/**
* @dev Returns the element stored at position `index` in the map. O(1).
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressToAddressMap storage map, uint256 index) internal view returns (address key, address value) {
(bytes32 atKey, bytes32 val) = at(map._inner, index);
return (address(uint160(uint256(atKey))), address(uint160(uint256(val))));
}
/**
* @dev Tries to returns the value associated with `key`. O(1).
* Does not revert if `key` is not in the map.
*/
function tryGet(AddressToAddressMap storage map, address key) internal view returns (bool exists, address value) {
(bool success, bytes32 val) = tryGet(map._inner, bytes32(uint256(uint160(key))));
return (success, address(uint160(uint256(val))));
}
/**
* @dev Returns the value associated with `key`. O(1).
*
* Requirements:
*
* - `key` must be in the map.
*/
function get(AddressToAddressMap storage map, address key) internal view returns (address) {
return address(uint160(uint256(get(map._inner, bytes32(uint256(uint160(key)))))));
}
/**
* @dev Return the an array containing all the keys
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function keys(AddressToAddressMap storage map) internal view returns (address[] memory) {
bytes32[] memory store = keys(map._inner);
address[] memory result;
assembly ("memory-safe") {
result := store
}
return result;
}
// AddressToBytes32Map
struct AddressToBytes32Map {
Bytes32ToBytes32Map _inner;
}
/**
* @dev Adds a key-value pair to a map, or updates the value for an existing
* key. O(1).
*
* Returns true if the key was added to the map, that is if it was not
* already present.
*/
function set(AddressToBytes32Map storage map, address key, bytes32 value) internal returns (bool) {
return set(map._inner, bytes32(uint256(uint160(key))), value);
}
/**
* @dev Removes a value from a map. O(1).
*
* Returns true if the key was removed from the map, that is if it was present.
*/
function remove(AddressToBytes32Map storage map, address key) internal returns (bool) {
return remove(map._inner, bytes32(uint256(uint160(key))));
}
/**
* @dev Returns true if the key is in the map. O(1).
*/
function contains(AddressToBytes32Map storage map, address key) internal view returns (bool) {
return contains(map._inner, bytes32(uint256(uint160(key))));
}
/**
* @dev Returns the number of elements in the map. O(1).
*/
function length(AddressToBytes32Map storage map) internal view returns (uint256) {
return length(map._inner);
}
/**
* @dev Returns the element stored at position `index` in the map. O(1).
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressToBytes32Map storage map, uint256 index) internal view returns (address key, bytes32 value) {
(bytes32 atKey, bytes32 val) = at(map._inner, index);
return (address(uint160(uint256(atKey))), val);
}
/**
* @dev Tries to returns the value associated with `key`. O(1).
* Does not revert if `key` is not in the map.
*/
function tryGet(AddressToBytes32Map storage map, address key) internal view returns (bool exists, bytes32 value) {
(bool success, bytes32 val) = tryGet(map._inner, bytes32(uint256(uint160(key))));
return (success, val);
}
/**
* @dev Returns the value associated with `key`. O(1).
*
* Requirements:
*
* - `key` must be in the map.
*/
function get(AddressToBytes32Map storage map, address key) internal view returns (bytes32) {
return get(map._inner, bytes32(uint256(uint160(key))));
}
/**
* @dev Return the an array containing all the keys
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function keys(AddressToBytes32Map storage map) internal view returns (address[] memory) {
bytes32[] memory store = keys(map._inner);
address[] memory result;
assembly ("memory-safe") {
result := store
}
return result;
}
// Bytes32ToUintMap
struct Bytes32ToUintMap {
Bytes32ToBytes32Map _inner;
}
/**
* @dev Adds a key-value pair to a map, or updates the value for an existing
* key. O(1).
*
* Returns true if the key was added to the map, that is if it was not
* already present.
*/
function set(Bytes32ToUintMap storage map, bytes32 key, uint256 value) internal returns (bool) {
return set(map._inner, key, bytes32(value));
}
/**
* @dev Removes a value from a map. O(1).
*
* Returns true if the key was removed from the map, that is if it was present.
*/
function remove(Bytes32ToUintMap storage map, bytes32 key) internal returns (bool) {
return remove(map._inner, key);
}
/**
* @dev Returns true if the key is in the map. O(1).
*/
function contains(Bytes32ToUintMap storage map, bytes32 key) internal view returns (bool) {
return contains(map._inner, key);
}
/**
* @dev Returns the number of elements in the map. O(1).
*/
function length(Bytes32ToUintMap storage map) internal view returns (uint256) {
return length(map._inner);
}
/**
* @dev Returns the element stored at position `index` in the map. O(1).
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32ToUintMap storage map, uint256 index) internal view returns (bytes32 key, uint256 value) {
(bytes32 atKey, bytes32 val) = at(map._inner, index);
return (atKey, uint256(val));
}
/**
* @dev Tries to returns the value associated with `key`. O(1).
* Does not revert if `key` is not in the map.
*/
function tryGet(Bytes32ToUintMap storage map, bytes32 key) internal view returns (bool exists, uint256 value) {
(bool success, bytes32 val) = tryGet(map._inner, key);
return (success, uint256(val));
}
/**
* @dev Returns the value associated with `key`. O(1).
*
* Requirements:
*
* - `key` must be in the map.
*/
function get(Bytes32ToUintMap storage map, bytes32 key) internal view returns (uint256) {
return uint256(get(map._inner, key));
}
/**
* @dev Return the an array containing all the keys
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function keys(Bytes32ToUintMap storage map) internal view returns (bytes32[] memory) {
bytes32[] memory store = keys(map._inner);
bytes32[] memory result;
assembly ("memory-safe") {
result := store
}
return result;
}
// Bytes32ToAddressMap
struct Bytes32ToAddressMap {
Bytes32ToBytes32Map _inner;
}
/**
* @dev Adds a key-value pair to a map, or updates the value for an existing
* key. O(1).
*
* Returns true if the key was added to the map, that is if it was not
* already present.
*/
function set(Bytes32ToAddressMap storage map, bytes32 key, address value) internal returns (bool) {
return set(map._inner, key, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a map. O(1).
*
* Returns true if the key was removed from the map, that is if it was present.
*/
function remove(Bytes32ToAddressMap storage map, bytes32 key) internal returns (bool) {
return remove(map._inner, key);
}
/**
* @dev Returns true if the key is in the map. O(1).
*/
function contains(Bytes32ToAddressMap storage map, bytes32 key) internal view returns (bool) {
return contains(map._inner, key);
}
/**
* @dev Returns the number of elements in the map. O(1).
*/
function length(Bytes32ToAddressMap storage map) internal view returns (uint256) {
return length(map._inner);
}
/**
* @dev Returns the element stored at position `index` in the map. O(1).
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32ToAddressMap storage map, uint256 index) internal view returns (bytes32 key, address value) {
(bytes32 atKey, bytes32 val) = at(map._inner, index);
return (atKey, address(uint160(uint256(val))));
}
/**
* @dev Tries to returns the value associated with `key`. O(1).
* Does not revert if `key` is not in the map.
*/
function tryGet(Bytes32ToAddressMap storage map, bytes32 key) internal view returns (bool exists, address value) {
(bool success, bytes32 val) = tryGet(map._inner, key);
return (success, address(uint160(uint256(val))));
}
/**
* @dev Returns the value associated with `key`. O(1).
*
* Requirements:
*
* - `key` must be in the map.
*/
function get(Bytes32ToAddressMap storage map, bytes32 key) internal view returns (address) {
return address(uint160(uint256(get(map._inner, key))));
}
/**
* @dev Return the an array containing all the keys
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function keys(Bytes32ToAddressMap storage map) internal view returns (bytes32[] memory) {
bytes32[] memory store = keys(map._inner);
bytes32[] memory result;
assembly ("memory-safe") {
result := store
}
return result;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.
pragma solidity ^0.8.20;
/**
* @dev Library for managing
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
* types.
*
* Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
*
* ```solidity
* contract Example {
* // Add the library methods
* using EnumerableSet for EnumerableSet.AddressSet;
*
* // Declare a set state variable
* EnumerableSet.AddressSet private mySet;
* }
* ```
*
* As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
* and `uint256` (`UintSet`) are supported.
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
* unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
* array of EnumerableSet.
* ====
*/
library EnumerableSet {
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Set type with
// bytes32 values.
// The Set implementation uses private functions, and user-facing
// implementations (such as AddressSet) are just wrappers around the
// underlying Set.
// This means that we can only create new EnumerableSets for types that fit
// in bytes32.
struct Set {
// Storage of set values
bytes32[] _values;
// Position is the index of the value in the `values` array plus 1.
// Position 0 is used to mean a value is not in the set.
mapping(bytes32 value => uint256) _positions;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._positions[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function _remove(Set storage set, bytes32 value) private returns (bool) {
// We cache the value's position to prevent multiple reads from the same storage slot
uint256 position = set._positions[value];
if (position != 0) {
// Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 valueIndex = position - 1;
uint256 lastIndex = set._values.length - 1;
if (valueIndex != lastIndex) {
bytes32 lastValue = set._values[lastIndex];
// Move the lastValue to the index where the value to delete is
set._values[valueIndex] = lastValue;
// Update the tracked position of the lastValue (that was just moved)
set._positions[lastValue] = position;
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the tracked position for the deleted slot
delete set._positions[value];
return true;
} else {
return false;
}
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._positions[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
// Bytes32Set
struct Bytes32Set {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
bytes32[] memory store = _values(set._inner);
bytes32[] memory result;
assembly ("memory-safe") {
result := store
}
return result;
}
// AddressSet
struct AddressSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
assembly ("memory-safe") {
result := store
}
return result;
}
// UintSet
struct UintSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
assembly ("memory-safe") {
result := store
}
return result;
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
interface IBrevisProof {
struct ProofData {
bytes32 commitHash;
bytes32 vkHash;
bytes32 appCommitHash; // zk-program computing circuit commit hash
bytes32 appVkHash; // zk-program computing circuit Verify Key hash
bytes32 smtRoot;
}
function submitProof(
uint64 _chainId,
bytes calldata _proofWithPubInputs
) external returns (bytes32 requestId, bytes32 appCommitHash, bytes32 appVkHash);
function submitAggProof(
uint64 _chainId,
bytes32[] calldata _requestIds,
bytes calldata _proofWithPubInputs
) external;
function validateAggProofData(uint64 _chainId, ProofData[] calldata _proofDataArray) external view;
function addProvers(address[] memory _accounts) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
import "../RewardsSubmission.sol";
// Handler contract for Brevis proof results
abstract contract AbstractResultHandler {
modifier onlyRewardsSubmission() {
require(msg.sender == rewardsSubmission, "only rewards submission contract allowed");
_;
}
address public immutable rewardsSubmission;
constructor(address _rewardsSubmission) {
if (_rewardsSubmission == address(0)) {
revert RewardsSubmission.ZeroAddress();
}
rewardsSubmission = _rewardsSubmission;
}
/**
* @notice Handles proof result. Processes circuit output.
* @param protocolId The protocol ID.
* @param protocol The protocol info.
* @param circuitOutput The circuit output in bytes.
*/
function handleResult(
uint32 protocolId,
RewardsSubmission.ProtocolInfo memory protocol,
bytes calldata circuitOutput
) external virtual;
/**
* @notice Resets protocol submission state.
* @param protocolId The protocol ID.
*/
function resetProtocolState(uint32 protocolId) external virtual;
/**
* @notice Removes protocol submission state.
* @param protocolId The protocol ID.
*/
function removeProtocolState(uint32 protocolId) external virtual;
}{
"optimizer": {
"enabled": true,
"runs": 800
},
"viaIR": true,
"evmVersion": "paris",
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"metadata": {
"useLiteralContent": true
},
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_brevisProof","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"bytes32","name":"key","type":"bytes32"}],"name":"EnumerableMapNonexistentKey","type":"error"},{"inputs":[{"internalType":"uint64","name":"epoch","type":"uint64"}],"name":"IncorrectEpoch","type":"error"},{"inputs":[{"internalType":"bytes32","name":"expected","type":"bytes32"},{"internalType":"bytes32","name":"actual","type":"bytes32"}],"name":"InvalidAppCommitHash","type":"error"},{"inputs":[],"name":"InvalidInputLengths","type":"error"},{"inputs":[{"internalType":"enum RewardsSubmission.State","name":"state","type":"uint8"}],"name":"InvalidState","type":"error"},{"inputs":[{"internalType":"bytes32","name":"expected","type":"bytes32"},{"internalType":"bytes32","name":"actual","type":"bytes32"}],"name":"InvalidVkHash","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"epoch","type":"uint64"}],"name":"AllSettled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"epoch","type":"uint64"}],"name":"AllSubRootsGenerated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"prevBrevisProof","type":"address"},{"indexed":false,"internalType":"address","name":"newBrevisProof","type":"address"}],"name":"BrevisProofUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"int256","name":"adjustment","type":"int256"},{"indexed":false,"internalType":"uint256","name":"newCumulativeRewards","type":"uint256"}],"name":"CumulativeRewardsAdjusted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"cumulativeRewards","type":"uint256"}],"name":"CumulativeRewardsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"epoch","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"startTime","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"endTime","type":"uint64"},{"indexed":false,"internalType":"uint256[]","name":"bucketAmounts","type":"uint256[]"}],"name":"EpochInfoUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"epoch","type":"uint64"}],"name":"EpochInitialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"currEpoch","type":"uint64"},{"indexed":true,"internalType":"enum RewardsSubmission.State","name":"state","type":"uint8"}],"name":"GlobalStateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"numBuckets","type":"uint8"}],"name":"NumBucketsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"epoch","type":"uint64"},{"indexed":true,"internalType":"uint8","name":"bucket","type":"uint8"},{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"string","name":"protocolName","type":"string"},{"indexed":false,"internalType":"uint256","name":"addedPoints","type":"uint256"}],"name":"PointsAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"proofHandler","type":"address"}],"name":"ProofHandlerAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"proofHandler","type":"address"}],"name":"ProofHandlerRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"protocolId","type":"uint32"},{"indexed":false,"internalType":"string","name":"name","type":"string"}],"name":"ProtocolDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"protocolId","type":"uint32"},{"indexed":false,"internalType":"string","name":"name","type":"string"}],"name":"ProtocolEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"protocolId","type":"uint32"},{"indexed":false,"internalType":"string","name":"name","type":"string"}],"name":"ProtocolInfoRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"chainId","type":"uint64"},{"indexed":true,"internalType":"uint32","name":"protocolId","type":"uint32"},{"indexed":true,"internalType":"uint8","name":"bucket","type":"uint8"},{"indexed":false,"internalType":"string","name":"name","type":"string"},{"indexed":false,"internalType":"bytes32","name":"vkHash","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"batchSize","type":"uint256"},{"indexed":false,"internalType":"address","name":"resultHandler","type":"address"},{"indexed":false,"internalType":"bool","name":"enabled","type":"bool"},{"indexed":false,"internalType":"address","name":"taxCollector","type":"address"},{"indexed":false,"internalType":"uint256","name":"taxBps","type":"uint256"},{"indexed":false,"internalType":"bytes32[]","name":"extraData","type":"bytes32[]"}],"name":"ProtocolInfoUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"resultHandler","type":"address"}],"name":"ResultHandlerAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"resultHandler","type":"address"}],"name":"ResultHandlerRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"epoch","type":"uint64"}],"name":"RewardsAdjustmentComplete","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"epoch","type":"uint64"},{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint8","name":"bucket","type":"uint8"},{"indexed":false,"internalType":"uint256","name":"addedPoints","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"addedRewards","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newCumulativeRewards","type":"uint256"}],"name":"Settled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"epoch","type":"uint64"},{"indexed":true,"internalType":"uint256","name":"subRootIndex","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"subRoot","type":"bytes32"}],"name":"SubRootGenerated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"epoch","type":"uint64"},{"indexed":true,"internalType":"uint256","name":"subRootIndex","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"leafIndex","type":"uint256"},{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"cumulativeRewards","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"leafHash","type":"bytes32"}],"name":"SubRootLeafProcessed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"epoch","type":"uint64"}],"name":"SubmissionsComplete","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"submitter","type":"address"}],"name":"SubmitterAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"submitter","type":"address"}],"name":"SubmitterRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"epoch","type":"uint64"},{"indexed":false,"internalType":"bytes32","name":"topRoot","type":"bytes32"}],"name":"TopRootGenerated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"epoch","type":"uint64"},{"indexed":true,"internalType":"uint8","name":"bucket","type":"uint8"},{"indexed":false,"internalType":"uint256","name":"points","type":"uint256"}],"name":"TotalPointsByBucketAdded","type":"event"},{"inputs":[{"internalType":"uint8","name":"bucket","type":"uint8"},{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"addedPoints","type":"uint256"},{"components":[{"internalType":"uint64","name":"chainId","type":"uint64"},{"internalType":"uint8","name":"bucket","type":"uint8"},{"internalType":"string","name":"name","type":"string"},{"internalType":"bytes32","name":"vkHash","type":"bytes32"},{"internalType":"uint16","name":"batchSize","type":"uint16"},{"internalType":"address","name":"resultHandler","type":"address"},{"internalType":"bool","name":"enabled","type":"bool"},{"internalType":"address","name":"taxCollector","type":"address"},{"internalType":"uint256","name":"taxBps","type":"uint256"},{"internalType":"bytes32[]","name":"extraData","type":"bytes32[]"}],"internalType":"struct RewardsSubmission.ProtocolInfo","name":"protocol","type":"tuple"}],"name":"addPoints","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"proofHandler","type":"address"}],"name":"addProofHandler","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"resultHandler","type":"address"}],"name":"addResultHandler","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"submitter","type":"address"}],"name":"addSubmitter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"int256","name":"adjustment","type":"int256"}],"name":"adjustCumulativeRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32[]","name":"_protocolIds","type":"uint32[]"}],"name":"batchRemoveProtocolInfos","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"users","type":"address[]"},{"internalType":"uint256[]","name":"_cumulativeRewards","type":"uint256[]"}],"name":"batchSetCumulativeRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64[]","name":"chainIds","type":"uint64[]"},{"internalType":"uint32[]","name":"_protocolIds","type":"uint32[]"},{"internalType":"uint8[]","name":"buckets","type":"uint8[]"},{"internalType":"string[]","name":"names","type":"string[]"},{"internalType":"bytes32[]","name":"vkHashes","type":"bytes32[]"},{"internalType":"uint16[]","name":"batchSizes","type":"uint16[]"},{"internalType":"address[]","name":"_resultHandlers","type":"address[]"},{"internalType":"bool[]","name":"enableds","type":"bool[]"},{"internalType":"address[]","name":"taxCollectors","type":"address[]"},{"internalType":"uint256[]","name":"taxBpses","type":"uint256[]"},{"internalType":"bytes32[][]","name":"extraDatas","type":"bytes32[][]"}],"name":"batchSetProtocolInfos","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32[]","name":"_protocolIds","type":"uint32[]"},{"internalType":"bool[]","name":"enableds","type":"bool[]"}],"name":"batchSetProtocolsEnabled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32[]","name":"_protocolIds","type":"uint32[]"},{"internalType":"bytes[]","name":"proofs","type":"bytes[]"},{"internalType":"bytes[]","name":"circuitOutputs","type":"bytes[]"}],"name":"batchSubmitProofs","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"brevisProof","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currEpoch","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"","type":"uint64"}],"name":"epochInfos","outputs":[{"internalType":"uint64","name":"startTime","type":"uint64"},{"internalType":"uint64","name":"endTime","type":"uint64"},{"internalType":"uint128","name":"indexingBlockNumber","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"epoch","type":"uint64"},{"internalType":"uint256","name":"nLeaves","type":"uint256"}],"name":"genSubRoot","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"epoch","type":"uint64"}],"name":"genTopRoot","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getCumulativeRewards","outputs":[{"internalType":"uint64","name":"epoch","type":"uint64"},{"internalType":"uint256","name":"rewards","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"epoch","type":"uint64"},{"internalType":"address","name":"user","type":"address"}],"name":"getMerkleProof","outputs":[{"internalType":"uint256","name":"_cumulativeRewards","type":"uint256"},{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"protocolId","type":"uint32"}],"name":"getProtocolInfo","outputs":[{"components":[{"internalType":"uint64","name":"chainId","type":"uint64"},{"internalType":"uint8","name":"bucket","type":"uint8"},{"internalType":"string","name":"name","type":"string"},{"internalType":"bytes32","name":"vkHash","type":"bytes32"},{"internalType":"uint16","name":"batchSize","type":"uint16"},{"internalType":"address","name":"resultHandler","type":"address"},{"internalType":"bool","name":"enabled","type":"bool"},{"internalType":"address","name":"taxCollector","type":"address"},{"internalType":"uint256","name":"taxBps","type":"uint256"},{"internalType":"bytes32[]","name":"extraData","type":"bytes32[]"}],"internalType":"struct RewardsSubmission.ProtocolInfo","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"protocolId","type":"uint32"},{"components":[{"internalType":"uint64","name":"chainId","type":"uint64"},{"internalType":"uint8","name":"bucket","type":"uint8"},{"internalType":"string","name":"name","type":"string"},{"internalType":"bytes32","name":"vkHash","type":"bytes32"},{"internalType":"uint16","name":"batchSize","type":"uint16"},{"internalType":"address","name":"resultHandler","type":"address"},{"internalType":"bool","name":"enabled","type":"bool"},{"internalType":"address","name":"taxCollector","type":"address"},{"internalType":"uint256","name":"taxBps","type":"uint256"},{"internalType":"bytes32[]","name":"extraData","type":"bytes32[]"}],"internalType":"struct RewardsSubmission.ProtocolInfo","name":"protocol","type":"tuple"},{"internalType":"bytes","name":"circuitOutput","type":"bytes"}],"name":"handleProofResult","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"epoch","type":"uint64"}],"name":"markEpochInitialized","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"epoch","type":"uint64"}],"name":"markRewardsAdjustmentComplete","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"epoch","type":"uint64"}],"name":"markSubmissionsComplete","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"numBuckets","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"proofHandlers","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"","type":"uint32"}],"name":"protocols","outputs":[{"internalType":"uint64","name":"chainId","type":"uint64"},{"internalType":"uint8","name":"bucket","type":"uint8"},{"internalType":"string","name":"name","type":"string"},{"internalType":"bytes32","name":"vkHash","type":"bytes32"},{"internalType":"uint16","name":"batchSize","type":"uint16"},{"internalType":"address","name":"resultHandler","type":"address"},{"internalType":"bool","name":"enabled","type":"bool"},{"internalType":"address","name":"taxCollector","type":"address"},{"internalType":"uint256","name":"taxBps","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"proofHandler","type":"address"}],"name":"removeProofHandler","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"protocolId","type":"uint32"}],"name":"removeProtocolInfo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"resultHandler","type":"address"}],"name":"removeResultHandler","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"submitter","type":"address"}],"name":"removeSubmitter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"resultHandlers","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_brevisProof","type":"address"}],"name":"setBrevisProof","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"_cumulativeRewards","type":"uint256"}],"name":"setCumulativeRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"epoch","type":"uint64"},{"internalType":"uint64","name":"startTime","type":"uint64"},{"internalType":"uint64","name":"endTime","type":"uint64"},{"internalType":"uint256","name":"totalRewardAmount","type":"uint256"},{"internalType":"uint256[]","name":"bucketShares","type":"uint256[]"}],"name":"setEpochInfo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"_currEpoch","type":"uint64"},{"internalType":"enum RewardsSubmission.State","name":"_state","type":"uint8"}],"name":"setGlobalState","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"_numBuckets","type":"uint8"}],"name":"setNumBuckets","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"protocolId","type":"uint32"},{"internalType":"bool","name":"enabled","type":"bool"}],"name":"setProtocolEnabled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"chainId","type":"uint64"},{"internalType":"uint32","name":"protocolId","type":"uint32"},{"internalType":"uint8","name":"bucket","type":"uint8"},{"internalType":"string","name":"name","type":"string"},{"internalType":"bytes32","name":"vkHash","type":"bytes32"},{"internalType":"uint16","name":"batchSize","type":"uint16"},{"internalType":"address","name":"resultHandler","type":"address"},{"internalType":"bool","name":"enabled","type":"bool"},{"internalType":"address","name":"taxCollector","type":"address"},{"internalType":"uint256","name":"taxBps","type":"uint256"},{"internalType":"bytes32[]","name":"extraData","type":"bytes32[]"}],"name":"setProtocolInfo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"epoch","type":"uint64"},{"internalType":"uint256","name":"count","type":"uint256"}],"name":"settle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"state","outputs":[{"internalType":"enum RewardsSubmission.State","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"protocolId","type":"uint32"},{"internalType":"bytes","name":"proof","type":"bytes"},{"internalType":"bytes","name":"circuitOutput","type":"bytes"}],"name":"submitProof","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"submitters","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"topRoot","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"","type":"uint8"}],"name":"totalPointsByBucket","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
6080346100ed57601f61547738819003918201601f19168301916001600160401b038311848410176100f2578084926020946040528339810103126100ed57516001600160a01b038116908190036100ed5733156100d75760008054336001600160a01b0319821681178355604051939290916001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a380156100c657600480546001600160a01b03191691909117905561536e90816101098239f35b63d92e233d60e01b60005260046000fd5b631e4fbdf760e01b600052600060045260246000fd5b600080fd5b634e487b7160e01b600052604160045260246000fdfe61042080604052600436101561001457600080fd5b600061040052610400513560e01c908163065604351461433a575080630727917314613fcf578063072900f914613f575780630f6d1eb414613cb9578063116dcd7d14613c575780631b4fc38b14613c375780631e45e18514613baa5780631f26c48b14613a255780632ca8b601146139575780632cdbfb9314613914578063373db22914613809578063376c2bc81461377f5780633abbf2da146134a057806345a3533b1461337b5780634d0923d81461333857806350f0fa21146132935780636370f17d14612d2b578063669e4eb514612ad6578063715018a614612a7457806375ffab73146129c157806377586e04146127d65780638879315d146127aa5780638da5cb5b1461277f578063908225aa1461251b5780639682cbfa1461248e5780639d04209314611b05578063aa195f7b14611a7b578063ad9ebe32146119c4578063b94bd6bb1461187d578063baef9823146117e5578063bf73918e146115e4578063bfdcc9a2146115bc578063c19d93fb1461158b578063c36f41e214611516578063c772c87f1461147e578063c7f5aaa014611455578063ce13e7a81461141d578063d1ed17e014611198578063d5759c0914610fb3578063dc737a2014610ebc578063e18370ca14610d22578063e4524bb5146109a1578063ea0ce51814610691578063f2fde38b146105fb578063f3cb8577146104a95763fa2ec0301461022257600080fd5b3461045c57602036600319011261045c5761023b614404565b610243614b57565b60ff6008541690600682101561048f57816104715763ffffffff168061040051526001602052604061040051206001600160a01b036040519161028583614451565b60ff81546001600160401b038116855260401c1660208401526102aa600182016144a4565b92604081019384526002820154606082015261012061030b600660038501549461ffff8616608086015260ff60a0860196888160101c16885260b01c16151560c08601528660048201541660e0860152600581015461010086015201614951565b9101525116803b1561045c57604051906368d50a8360e01b825283600483015281602481610400519361040051905af1801561046357610441575b506103e27f6822e4450f695ee0b191df6a12d39bce9f3f87472939c31165d011ca0a272f3c9161037584615207565b5083610400515260016020526103cd600660406104005120610400518155600181016103a18154614417565b806103ec575b505061040051600282018190556003820181905560048201819055600582015501614a16565b51604051918291602083526020830190614548565b0390a26104005180f35b601f811160011461040657506104005190555b87806103a7565b610429908261040051526001601f60206104005120920160051c820191016147e6565b610400805182905251602081209181905590556103ff565b6104005161044e91614483565b6104005161045c5782610346565b6104005180fd5b6040513d61040051823e3d90fd5b5063683f44bb60e11b61040051526104005150600452602461040051fd5b634e487b7160e01b61040051526021600452602461040051fd5b3461045c57604036600319011261045c576104c2614379565b6024359033610400515260076020526104e460ff60406104005120541661479a565b60ff60085416600681101561048f57600381036105de57506001600160a01b03169061050f826152bb565b8091509061040051831360001461057e57508161054f7ff4793f27a2bf46ca8586a3150c23ad281663e90b7be224e1ee8a51c25019c08693604093614823565b846104005152600e602052808361040051205561056b85615091565b5082519182526020820152a26104005180f35b9050600160ff1b82146105c457816105bf6040927ff4793f27a2bf46ca8586a3150c23ad281663e90b7be224e1ee8a51c25019c086946104005103906148b3565b61054f565b634e487b7160e01b61040051526011600452602461040051fd5b63683f44bb60e11b61040051526104005150600452602461040051fd5b3461045c57602036600319011261045c576001600160a01b0361061c614379565b610624614b57565b168015610675576104005180546001600160a01b03198116831782556001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a36104005180f35b631e4fbdf760e01b610400515261040051600452602461040051fd5b3461045c57606036600319011261045c576004356001600160401b03811161045c576106c19036906004016143d4565b906024356001600160401b03811161045c576106e19036906004016143d4565b90926044356001600160401b03811161045c576107029036906004016143d4565b919092336104005152600760205261072360ff60406104005120541661479a565b81158015610997575b801561098d575b61097857610400515b82811061074a576104005180f35b61075d6107588285896147fd565b614abf565b61076882848a614b02565b61077384888a614b02565b939092336104005152600760205261079460ff60406104005120541661479a565b60ff60085416600681101561048f57600181036105de57506108ad9063ffffffff83166104005152600160205260606040610400512091604051956107d887614451565b60ff84546001600160401b038116895260401c1660208801526107fd600185016144a4565b60408801526108656006600286015495858a0196875260ff600382015461ffff811660808d01526001600160a01b038160101c1660a08d015260b01c16151560c08b01526001600160a01b0360048201541660e08b015260058101546101008b015201614951565b6101208801526001600160a01b0360045416906001600160401b038851166040519687948593849363e044095360e01b85526004850152604060248501526044840191614a8d565b039161040051905af1908115610463576104005192839261093b575b50518082036109205750506108df3686866146a1565b60208151910120908181036109055750509160019493916108ff93614df7565b0161073c565b6340f748cd60e01b6104005152600452602452604461040051fd5b6335bce51360e11b6104005152600452602452604461040051fd5b925090506060823d8211610970575b8161095760609383614483565b8101031261045c5760406020830151920151908e6108c9565b3d915061094a565b63637643ab60e11b6104005152600461040051fd5b5082811415610733565b508082141561072c565b3461045c57604036600319011261045c576109ba6143be565b6024356008549160ff8316600681101561048f57600281036105de57506001600160401b038091169260081c168203610d0957816104005152600960205260406104005120906040519160808301928084106001600160401b03851117610cef57610a6660609260019560405280546001600160401b03811684526001600160401b038160401c16602085015260801c6040840152610a5f6040518097819301614879565b0385614483565b0191825260ff600f541660105492610400515061040051935b8315610ce65760ff831693846104005152600a6020526040610400512094855415610cb1575090610ac091610baa610b4187865160ff8916968780926148f2565b518c7f9efdcd7e00e57e4d2c7c12f1e0408a812a8d940da0afada9938d88be5d4710a660606002610af18b88614861565b90549060031b1c96019580610400515286602052610b4b6001600160a01b0360406104005120549216988996886104005152600b6020526040610400512054906104005150610400515084614f04565b6104005190614823565b610b5f81610b58886152bb565b9050614823565b90866104005152600e602052816040610400512055610b7d87615091565b5060405192835260208301526040820152a4816104005152602052610400516040610400512055876150e6565b5060001901945460001981019081116105c4578103610c9e5782515160001981019081116105c4578214610c0557506104005152600b602052610400516040610400512055610bfc6104005192614aae565b935b9391610a7f565b93505050915060015b15610c86575060ff90610400515061040051506003821960085416176008558119600f5416600f5561040051601055166104005152600b6020526104005160406104005120557f64e4fe2e975e34557ba3458484d9064e3eae16332ae974185f17dda74fc292c26104005161040051a25b6104005180f35b915060ff1660ff19600f541617600f55601055610c7f565b610cab91509492946149bb565b91610bfe565b83515191955091939160001982019182116105c45714610cda57610cd490614aae565b93610bfe565b93505090506001610c0e565b92505091610c0e565b634e487b7160e01b61040051526041600452602461040051fd5b506320eeef9d60e01b6104005152600452602461040051fd5b3461045c57610d303661474a565b919290923361040051526007602052610d5260ff60406104005120541661479a565b80158015610eb2575b61097857610400515b838110610d72576104005180f35b610d85610d808284866147fd565b614b19565b90610d918186886147fd565b353361040051526007602052610db060ff60406104005120541661479a565b60085460ff8116600681101561048f57806105de575060081c6001600160401b03168015908115610e81575b5015610e3c577fa1a86ec5bc9cb16543e635cdd7c4b82bda0b15213dbd82348f879042b3e9780860206001600160a01b036001951692836104005152600e8252806040610400512055610e2e84615091565b50604051908152a201610d64565b60405162461bcd60e51b815260206004820152600f60248201527f77616974206e65787420626c6f636b00000000000000000000000000000000006044820152606490fd5b6001600160401b039150610e949061499c565b1661040051526009602052604061040051205460801c431188610ddc565b5082811415610d5b565b3461045c57604036600319011261045c57610ed5614379565b602435903361040051526007602052610ef760ff60406104005120541661479a565b60085460ff8116600681101561048f57806105de575060081c6001600160401b03168015908115610f82575b5015610e3c5760206001600160a01b037fa1a86ec5bc9cb16543e635cdd7c4b82bda0b15213dbd82348f879042b3e97808921692836104005152600e8252806040610400512055610f7384615091565b50604051908152a26104005180f35b6001600160401b039150610f959061499c565b1661040051526009602052604061040051205460801c431183610f23565b3461045c57610fc13661474a565b610fcc939193614b57565b808303610978576104005160ff60085416916006831093831515925b868110610ff6576104005180f35b6110046107588289856147fd565b61101761101283868c6147fd565b614b2d565b90611020614b57565b871561048f578561117e579063ffffffff6001939216908161040051528360205260406104005120906040519161105683614451565b60ff81546001600160401b038116855260401c16602084015261107a8682016144a4565b9260408101938452600282015460608201526101206110e9600660038501549461ffff861660808601526001600160a01b038660101c1660a086015260ff60c086019660b01c16151586526001600160a01b0360048201541660e0860152600581015461010086015201614951565b910152811515905260001461113c576111327faaf817e27cb709c532bd8a556c41800cc79948f41be602afcf86269a162eb4bd9151604051918291602083526020830190614548565b0390a25b01610fe8565b6111767fcd6dd2bfbc2095d9f6cf85d22bfb83173551ba7a122305b908fc5524c0714c669151604051918291602083526020830190614548565b0390a2611136565b610400805163683f44bb60e11b9052516004889052602490fd5b3461045c57608036600319011261045c576111b16145bd565b6111b9614394565b60443591606435906001600160401b03821161045c578160040190610140600319843603011261045c57336104005152600660205260ff604061040051205416156113d85760ff1692836104005152600a60205260406104005120946001600160a01b0382169561122a87826152f2565b6104005190949150610104870135806112da575b50926112886112c1937fff4b09174e75080e8d34b61d08ea82e7d1100c558cb6ba7571bcacf69899c21c979361128261127b6112d09998866148b3565b8098614823565b91614edf565b50876104005152600b6020526112a660406104005120918254614823565b905560446001600160401b0360085460081c16960190614ad0565b92909160405193849384614b3a565b0390a46104005180f35b848197939496959250029581870414811517156105c457611288856112c19461128261127b6113b4878e6112d09c8f7fff4b09174e75080e8d34b61d08ea82e7d1100c558cb6ba7571bcacf69899c21c9f7fff4b09174e75080e8d34b61d08ea82e7d1100c558cb6ba7571bcacf69899c21c916113c56127106001600160a01b03930497889761139160e485019761137c876113758b614b19565b16826152f2565b90506112828c61138b8c614b19565b92614823565b5060446113ac6001600160401b0360085460081c1698614b19565b940190614ad0565b604098919851948594169884614b3a565b0390a4959899505050939750935061123e565b60405162461bcd60e51b815260206004820152601c60248201527f6f6e6c7920726573756c742068616e646c65727320616c6c6f776564000000006044820152606490fd5b3461045c57602036600319011261045c5760ff6114386145bd565b166104005152600b60205260206040610400512054604051908152f35b3461045c576104005136600319011261045c5760206001600160a01b0360045416604051908152f35b3461045c57602036600319011261045c576001600160a01b0361149f614379565b6114a7614b57565b1680156115015760407fddb7d4b45d521a6718ed9ccac62f1faa18b869772bca7e77ab6f392912a4ec189160045490806001600160a01b03198316176004556001600160a01b038351921682526020820152a16104005180f35b63d92e233d60e01b6104005152600461040051fd5b3461045c57602036600319011261045c576001600160a01b03611537614379565b61153f614b57565b1680610400515260076020526040610400512060ff1981541690557ff84a004e1673d2f349a7c93c72b3794b8eba6d2f9338044d8c8cd260e51a57a16104005161040051a26104005180f35b3461045c576104005136600319011261045c5760ff600854166040516104005150600682101561048f576020918152f35b3461045c576104005136600319011261045c57602060ff610400515460a01c16604051908152f35b3461045c57606036600319011261045c576115fd614404565b6024356001600160401b03811161045c57610140600319823603011261045c576040519061162a82614451565b60048101356001600160401b038116810361045c578252602481013560ff8116810361045c57602083015260448101356001600160401b03811161045c5781013660238201121561045c576116899036906024600482013591016146a1565b604083015260648101356060830152608481013561ffff8116810361045c5760808301526116b960a482016143aa565b60a083015260c4810135801515810361045c5760c08301526116dd60e482016143aa565b60e0830152610104810135610100830152610124810135906001600160401b03821161045c57013660238201121561045c576117239036906024600482013591016146fe565b6101208201526044356001600160401b03811161045c576117489036906004016145cd565b91336104005152600560205260ff604061040051205416156117a05760ff6008541693600685101561048f576001850361178657610c7f9450614df7565b610400805163683f44bb60e11b9052516004869052602490fd5b60405162461bcd60e51b815260206004820152601b60248201527f6f6e6c792070726f6f662068616e646c65727320616c6c6f77656400000000006044820152606490fd5b3461045c57602036600319011261045c576117fe6143be565b336104005152600760205261181c60ff60406104005120541661479a565b60ff6008541690600682101561048f576003820361047157610400516008805460ff191660041790556001600160401b0391909116907fdd84b0a0fa79088c80855ac82217e24a5ae3ba87f19cef1d17696429b444c6dc9080a26104005180f35b3461045c57602036600319011261045c5763ffffffff61189b614404565b60606101206040516118ac81614451565b61040051815261040051602082015282604082015261040051838201526104005160808201526104005160a08201526104005160c08201526104005160e082015261040051610100820152015216610400515260016020526119c0604061040051206119a660066040519261192084614451565b60ff81546001600160401b038116865260401c166020850152611945600182016144a4565b60408501526002810154606085015260ff600382015461ffff811660808701526001600160a01b038160101c1660a087015260b01c16151560c08501526001600160a01b0360048201541660e0850152600581015461010085015201614951565b6101208201526040519182916020835260208301906145fa565b0390f35b3461045c57602036600319011261045c576119dd614379565b6008549060ff8216600681101561048f57806105de5750611a32611a2a6001600160a01b036001600160401b0360409560081c169384158015611a48575b611a24906149ca565b166152bb565b92905061499c565b906001600160401b038351921682526020820152f35b506001600160401b03611a5a8661499c565b1661040051526009602052611a248661040051205460801c43119050611a1b565b3461045c57602036600319011261045c57611a94614379565b611a9c614b57565b60ff6008541690600682101561048f5781610471576001600160a01b031680610400515260066020526040610400512060ff1981541690557f1602c5bcc673d1d5f0c782ac7faa22c4e47e10222017072c7c0a1aef8e1e16156104005161040051a26104005180f35b3461045c5761016036600319011261045c576004356001600160401b03811161045c57611b369036906004016143d4565b60c05260a0526024356001600160401b03811161045c57611b5b9036906004016143d4565b60e052610320526044356001600160401b03811161045c57611b819036906004016143d4565b61034052610100526064356001600160401b03811161045c57611ba89036906004016143d4565b610120526102e0526084356001600160401b03811161045c57611bcf9036906004016143d4565b610360526102205260a4356001600160401b03811161045c57611bf69036906004016143d4565b610300526101405260c4356001600160401b03811161045c57611c1d9036906004016143d4565b610160526102405260e4356001600160401b03811161045c57611c449036906004016143d4565b6101805261026052610104356001600160401b03811161045c57611c6c9036906004016143d4565b6101a0526102a052610124356001600160401b03811161045c57611c949036906004016143d4565b6101c0526102c0526001600160401b03610144351161045c57611cbd36610144356004016143d4565b610280526101e052611ccd614b57565b60c051158015612480575b8015612471575b8015612461575b8015612451575b8015612441575b8015612431575b8015612421575b8015612411575b8015612401575b80156123f1575b6109785761040051610200525b610360516102005110611d38576104005180f35b611d4a6102005160c05160a0516147fd565b356001600160401b038116810361045c57611d716107586102005160e051610320516147fd565b90611d866102005161034051610100516147fd565b3560ff8116810361045c57611da561020051610120516102e051614b02565b9091611dbb6102005161036051610220516147fd565b3592611dd16102005161030051610140516147fd565b3561ffff8116810361045c57611df4610d806102005161016051610240516147fd565b611e0b6110126102005161018051610260516147fd565b90611e23610d80610200516101a0516102a0516147fd565b92611e38610200516101c0516102c0516147fd565b3594610280516102005110156123d757601e196101e0513603016102005160051b6101e0510135121561045c576102005160051b6101e05101356101e05101976001600160401b0389351161045c57883560051b360360208a011361045c57611e9f614b57565b60ff60085416600681101561048f57806105de57506001600160a01b0384166104005152600660205260ff604061040051205416156123925760ff610400515460a01c1660ff8916101561234d57611efc63ffffffff8d1661503c565b506001600160a01b0384163b1561045c5760405163052db9cf60e31b815263ffffffff8d1660048201526104005181602481836001600160a01b038a165af1801561046357612332575b50604051611f5381614451565b6001600160401b038c16815260ff89166020820152611f733683856146a1565b60408201528a606082015261ffff841660808201526001600160a01b03851660a082015285151560c08201526001600160a01b03871660e082015287610100820152611fc4368b3560208d016146fe565b61012082015263ffffffff8d166104005152600160205260406104005120906001600160401b0380825116166001600160401b0319835416178255602081015168ff000000000000000083549160401b169068ff0000000000000000191617825560408101518051906001600160401b038211610cef576120486001850154614417565b601f81116122ee575b506020906001601f84111461227757918061208a926101209594610400519261226c575b50508160011b916000199060031b1c19161790565b60018401555b606081015160028401556003830161ffff60808301511681549075ffffffffffffffffffffffffffffffffffffffff000060a085015160101b169076ffffffffffffffffffffffffffffffffffffffffffffff1960ff60b01b60c0870151151560b01b16931617171790556001600160a01b0360e0820151166001600160a01b036004850191166001600160a01b031982541617905561010081015160058401550151908151916001600160401b038311610cef57602060069161215685848601614a4a565b019101610400515260206104005120610400515b83811061225857505050506001600160a01b0395949391926121a5879461ffff93604051608052610100608051526101006080510191614a8d565b9a602060805101521660406080510152166060608051015215156080805101521660a0608051015260c06080510152608051830360e06080510152813583526001600160fb1b0382351161045c57816001600160401b0363ffffffff60ff6020947f22cc39fb9f698334c07d92b6c2cc1a233f0da11fed8b1d8b320e7af2ed32a5f2963560051b868601878a0137169716951693608051913560051b010301608051a46001610200510161020052611d24565b60019060208451940193818401550161216a565b015190503880612075565b90601f1983169160018601610400515281610400512092610400515b8181106122d65750916001939185610120979694106122bd575b505050811b016001840155612090565b015160001960f88460031b161c191690553880806122ad565b92936020600181928786015181550195019301612293565b6123229060018601610400515260206104005120601f850160051c81019160208610612328575b601f0160051c01906147e6565b38612051565b9091508190612315565b6104005161233f91614483565b6104005161045c578c611f46565b60405162461bcd60e51b815260206004820152600e60248201527f696e76616c6964206275636b65740000000000000000000000000000000000006044820152606490fd5b60405162461bcd60e51b815260206004820152601b60248201527f756e617574686f72697a656420726573756c742068616e646c657200000000006044820152606490fd5b634e487b7160e01b61040051526032600452602461040051fd5b50610280516101c0511415611d17565b506101c0516101a0511415611d10565b506101a051610180511415611d09565b5061018051610160511415611d02565b5061016051610300511415611cfb565b5061030051610360511415611cf4565b5061036051610120511415611ced565b5061012051610340511415611ce6565b506103405160e0511415611cdf565b5060e05160c0511415611cd8565b3461045c57602036600319011261045c576124a7614379565b6124af614b57565b60ff6008541690600682101561048f5781610471576001600160a01b0316806104005152600660205260406104005120600160ff198254161790557f502e775abb2383950531644d7bf2d4c666e9596157bf6f4c7d9b51ce0336314e6104005161040051a26104005180f35b3461045c57602036600319011261045c576004356001600160401b03811161045c5761254b9036906004016143d4565b90612554614b57565b610400515b828110612567576104005180f35b6125756107588285856147fd565b61257d614b57565b60ff60085416600681101561048f57806105de575063ffffffff1690816104005152600160205260406104005120916001600160a01b03604051936125c185614451565b60ff81546001600160401b038116875260401c1660208601526125e6600182016144a4565b946040810195865260028201546060820152610120612647600660038501549461ffff8616608086015260ff60a0860196888160101c16885260b01c16151560c08601528660048201541660e0860152600581015461010086015201614951565b9101525116803b1561045c57604051906368d50a8360e01b825282600483015281602481610400519361040051905af1801561046357612764575b507f6822e4450f695ee0b191df6a12d39bce9f3f87472939c31165d011ca0a272f3c6127086001946126b384615207565b50836104005152856020526103cd6006604061040051206104005181558881016126dd8154614417565b8061271157505061040051600282018190556003820181905560048201819055600582015501614a16565b0390a201612559565b601f81118b1461272a57506104005190555b8b806103a7565b61274c908261040051528b601f60206104005120920160051c820191016147e6565b61040080518290525160208120918190559055612723565b6104005161277191614483565b6104005161045c5785612682565b3461045c576104005136600319011261045c5760206001600160a01b03610400515416604051908152f35b3461045c576104005136600319011261045c5760206001600160401b0360085460081c16604051908152f35b3461045c57602036600319011261045c576127ef6143be565b336104005152600760205261280d60ff60406104005120541661479a565b6008549060ff8216600681101561048f57600181036105de57506001600160401b038091169160081c1681036129a957610400515b6002548110156128f5576002548110156123d7576002610400515263ffffffff8160206104005120016104005150546104005160031b1c1680610400515260016020526001600160a01b03600360406104005120015460101c16803b1561045c576040519163052db9cf60e31b8352600483015281602481610400519361040051905af18015610463576128da575b50600101612842565b610400516128e791614483565b6104005161045c57826128d1565b50610400515b816104005152600960205260016040610400512001549060ff81169182101561296a5781612965926104005152600b602052837fc09ad501f56c8a0caedcbad2ec1dab802b1ceef6c666a24040ffc4477958a59260206040610400512054604051908152a3614aae565b6128fb565b827f3711923da2f2c9c943ad1776a84dfe8778252657c474f9f306485453dc82ba236104005161040051a2610400516008805460ff1916600217905580f35b6320eeef9d60e01b6104005152600452602461040051fd5b3461045c57602036600319011261045c576129da6145bd565b6129e2614b57565b60ff60085416600681101561048f57806105de577f5f7601cd31de990d2b7fe9278b29c356d6b7a1e8557d82d7f19197d714b5088560208361040051547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff74ff00000000000000000000000000000000000000008360a01b16911617610400515560ff60405191168152a16104005180f35b3461045c576104005136600319011261045c57612a8f614b57565b6104005180546001600160a01b0319811682556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a36104005180f35b3461045c57606036600319011261045c57612aef614404565b6024356001600160401b03811161045c57612b0e9036906004016145cd565b90916044356001600160401b03811161045c57612b2f9036906004016145cd565b9290913361040051526007602052612b5060ff60406104005120541661479a565b60ff6008541694600686101561048f5760018603612d1157612c6a955063ffffffff8216610400515260016020526060604061040051209160405194612b9586614451565b60ff84546001600160401b038116885260401c166020870152612bba600185016144a4565b6040870152612c22600660028601549585890196875260ff600382015461ffff811660808c01526001600160a01b038160101c1660a08c015260b01c16151560c08a01526001600160a01b0360048201541660e08a015260058101546101008a015201614951565b6101208701526001600160a01b0360045416906001600160401b038751166040519a8b948593849363e044095360e01b85526004850152604060248501526044840191614a8d565b039161040051905af19081156104635761040051968792612cd3575b5051808203610920575050612c9c3685856146a1565b6020815191012094858103612cb65750610c7f9450614df7565b85906340f748cd60e01b6104005152600452602452604461040051fd5b965090506060863d606011612d09575b81612cf060609383614483565b8101031261045c57604060208701519601519087612c86565b3d9150612ce3565b610400805163683f44bb60e11b9052516004879052602490fd5b3461045c5761016036600319011261045c57612d456143be565b6103c0526024356103e081905263ffffffff8116900361045c5760443560ff8116810361045c576064356001600160401b03811161045c57612d8b9036906004016145cd565b60a4356103a08190529092919061ffff8116900361045c5760c435906001600160a01b038216820361045c5760e435801515810361045c5761010435906001600160a01b038216820361045c57610144356001600160401b03811161045c57612df89036906004016143d4565b906103805292612e06614b57565b60ff60085416600681101561048f57806105de57506001600160a01b0385166104005152600660205260ff604061040051205416156123925760ff610400515460a01c1660ff8716101561234d57612e6663ffffffff6103e0511661503c565b506001600160a01b0385163b1561045c5760405163052db9cf60e31b81526103e05163ffffffff1660048201526104005181602481836001600160a01b038b165af1801561046357613280575b50604051612ec081614451565b6001600160401b036103c051168152602081019060ff88168252612ee5368a856146a1565b60408201908152606082016084358152608083019061ffff6103a05116825260a08401906001600160a01b038b16825260c0850190881515825260e08601946001600160a01b038b16865261012435610100880152612f48368d610380516146fe565b61012088015263ffffffff6103e051166104005152600160205260406104005120976001600160401b0380895116166001600160401b03198a54161789555168ff000000000000000089549160401b169068ff00000000000000001916178855518051906001600160401b038211610cef57612fc760018a0154614417565b601f8111613247575b506020906001601f8411146131c357826001600160a01b039795936101209a9997959361301593610400519261226c5750508160011b916000199060031b1c19161790565b60018a01555b51600289015561ffff6003890193511676ffffffffffffffffffffffffffffffffffffffffffffff1960ff60b01b75ffffffffffffffffffffffffffffffffffffffff00008654955160101b169351151560b01b169316171717905551166001600160a01b036004850191166001600160a01b031982541617905561010081015160058401550151908151916001600160401b038311610cef5760206006916130c685848601614a4a565b019101610400515260206104005120610400515b8381106131af5750505050906001600160a01b03613108819493604051996101008b526101008b0191614a8d565b9560843560208a015261ffff6103a0511660408a0152166060880152151560808701521660a08501526101243560c085015283820360e08501528082526001600160fb1b03811161045c5760ff7f22cc39fb9f698334c07d92b6c2cc1a233f0da11fed8b1d8b320e7af2ed32a5f29160051b9384610380516020860137169360208163ffffffff6103e05116956001600160401b036103c051169501030190a46104005180f35b6001906020845194019381840155016130da565b90601f1983169160018b01610400515281610400512092610400515b81811061322f57509260019285926001600160a01b039a98966101209d9c9a989610613216575b505050811b0160018a015561301b565b015160001960f88460031b161c19169055388080613206565b929360206001819287860151815501950193016131df565b61327a9060018b01610400515260206104005120601f850160051c8101916020861061232857601f0160051c01906147e6565b38612fd0565b6104005161328d91614483565b87612eb3565b3461045c57604036600319011261045c576132ac6143be565b60243590600682101561045c576132c1614b57565b6008805460ff9390931668ffffffffffffffffff1990931691811b68ffffffffffffffff001691909117821790819055600682101561048f576001600160401b039060081c167fc0b26fd2c11b8c0762b3ddd78c4beaf1923e7ef6307ad2b5ceafb992ccdc1b916104005161040051a36104005180f35b3461045c57602036600319011261045c576001600160a01b03613359614379565b1661040051526006602052602060ff6040610400512054166040519015158152f35b3461045c57602036600319011261045c576133946143be565b33610400515260076020526133b260ff60406104005120541661479a565b6008549060ff8216600681101561048f57806105de57506001600160401b038082169260081c168203610d09578115801561346e575b6133f291506149ca565b601154610400515b81811061344057827ffa7123a93f584cf4d9fb3271d15b3f117fb9603f50b1d22b689b509b420225286104005161040051a2610400516008805460ff1916600117905580f35b601154156123d757600190601161040051526134676020610400512061040051505461513d565b50016133fa565b506134806001600160401b039161499c565b16610400515260096020526133f2604061040051205460801c43116133e8565b3461045c57604036600319011261045c576134b96143be565b6134c1614394565b60085460ff8116600681101561048f57806105de57506001600160401b036134ee81809360081c1661499c565b169216918203610d09576001600160a01b0316806104005152600e602052604061040051205490811580613765575b61374d576104005152600d602052604061040051205460001981019081116105c4576104005160115460001981019081119391929190845b6105c457838186951080613734575b1561357857613572906149bb565b93613555565b9190826137125761040051945b600c5461359287826148b3565b916105c4576135a89285106136e8575b506148c0565b91610400515b835181101561362657806136126136046135d26135cd6001958b614823565b614b80565b60409391935192839160208301958690916034926bffffffffffffffffffffffff199060601b16825260148201520190565b03601f198101835282614483565b51902061361f82876148f2565b52016135ae565b5061364c61363e8461363888886148b3565b90614ca4565b91613647614906565b614ca4565b9061366261365d8251845190614823565b6148c0565b92610400515b8251811015613690578061367e600192856148f2565b5161368982886148f2565b5201613668565b5091610400515b81518110156136c957806136ad600192846148f2565b516136c26136bc838751614823565b886148f2565b5201613697565b5050506119c06040519283928352604060208401526040830190614589565b9061370661370c926136f987614846565b90549060031b1c906148b3565b906148b3565b866135a2565b60001983018381116105c45761372790614846565b90549060031b1c94613585565b5061373e81614846565b90549060031b1c841015613564565b63015ab34360e11b6104005152600452602461040051fd5b506104008051829052600d6020525160409020541561351d565b3461045c57602036600319011261045c57613798614379565b6137a0614b57565b60ff6008541690600682101561048f5781610471576001600160a01b031680610400515260056020526040610400512060ff1981541690557fbe5dcd1f0b2a0fbeeeb1bb03d6eaa4dc9ed20124839302d2dd653b8c01d793ae6104005161040051a26104005180f35b3461045c57602036600319011261045c576138226143be565b6008549060ff8216600681101561048f57600581036105de57506001600160401b038091169160081c1681036129a95761386261385d614906565b614bb0565b60145580610400515260096020526040610400512080546fffffffffffffffffffffffffffffffff80194360801b1691161790556008546001600160401b038160081c166001600160401b0381146105c45768ffffffffffffffffff19909116600191909101600890811b68ffffffffffffffff00169190911790556014546040519081527f149bb8e98c16d440ac1f1a03a4d3c2d93d9011a48aba5ab0e47386c72c6cd4f890602090a26104005180f35b3461045c57602036600319011261045c576001600160a01b03613935614379565b1661040051526005602052602060ff6040610400512054166040519015158152f35b3461045c57602036600319011261045c5763ffffffff613975614404565b166104005152600160205260ff60406104005120805490613998600182016144a4565b6002820154918460038201546139e960056001600160a01b036004860154169401549460405198886001600160401b038b9a168a5260401c1660208901526101206040890152610120880190614548565b94606087015261ffff811660808701526001600160a01b038160101c1660a087015260b01c16151560c085015260e08401526101008301520390f35b3461045c57604036600319011261045c57613a3e614404565b602435908115159081830361045c57613a55614b57565b60ff60085416600681101561048f57806105de575063ffffffff16918261040051526001602052604061040051209160405192613a9184614451565b60ff81546001600160401b038116865260401c166020850152613ab6600182016144a4565b936040810194855260028201546060820152610120613b25600660038501549461ffff861660808601526001600160a01b038660101c1660a086015260ff60c086019660b01c16151586526001600160a01b0360048201541660e0860152600581015461010086015201614951565b9101525215613b68576103e27faaf817e27cb709c532bd8a556c41800cc79948f41be602afcf86269a162eb4bd9151604051918291602083526020830190614548565b613ba27fcd6dd2bfbc2095d9f6cf85d22bfb83173551ba7a122305b908fc5524c0714c669151604051918291602083526020830190614548565b0390a2610c7f565b3461045c57602036600319011261045c57613bc3614379565b613bcb614b57565b60ff6008541690600682101561048f5781610471576001600160a01b0316806104005152600560205260406104005120600160ff198254161790557f1a6f0b2e0a49f9872fcf562d696d893dc6c4094bdcd27cba1c6e14311a56c8376104005161040051a26104005180f35b3461045c576104005136600319011261045c576020601454604051908152f35b3461045c57602036600319011261045c576001600160401b03613c786143be565b166104005152600960205260606040610400512054604051906001600160401b03811682526001600160401b038160401c16602083015260801c6040820152f35b3461045c57604036600319011261045c57613cd26143be565b6024356008549160ff8316600681101561048f57600481036105de57506001600160401b038091169260081c168203610d09576401000000008111613f1257601154610400519080613eee57610400516013805491905580613ecd575b505b613d3d82600c546148b3565b90818411613ec4575b84613d50856148c0565b610400515b868110613e2857506020613d897fa798d21d4735fa640961e41c1c64c71ac1a880bed56cc8f53dd2e4fa0cd51f4d92614bb0565b613d9281614fe1565b50604051908152a38203613dde575050610400516008805460ff191660051790557fb95c96f28d7bc16885c1b6299dcc3816b715899206a2e0939cce4c4c9bb2d5679080a26104005180f35b613de89250614823565b601354600160401b811015610cef57613e0a816001613e219301601355614846565b819391549060031b91821b91600019901b19161790565b9055610c7f565b8084600193947f43fa36b7b583cad3d050ef0cb611495f9f3bd6ccfcc858eeb0b677dc65c71cce6060613e5e6135cd868d614823565b604051606083901b6bffffffffffffffffffffffff1916602082019081526034820183905290613e918160548101613604565b5190209081613ea0898d6148f2565b526001600160a01b036040519316835260208301526040820152a401908691613d55565b92508092613d46565b613ee8906013610400515260206104005120908101906147e6565b84613d2f565b905060001981018181116105c457613f0590614846565b90549060031b1c90613d31565b60405162461bcd60e51b815260206004820152600f60248201527f746f6f206d616e79206c656176657300000000000000000000000000000000006044820152606490fd5b3461045c57602036600319011261045c576001600160a01b03613f78614379565b613f80614b57565b16806104005152600760205260406104005120600160ff198254161790557fb079bc2cbde1f186e0b351d4a87c4597e3ed098f571548617449e73506428d8b6104005161040051a26104005180f35b3461045c5760a036600319011261045c57613fe86143be565b6024356001600160401b0381169081900361045c576044356001600160401b0381169081810361045c57606435906084356001600160401b03811161045c576140359036906004016143d4565b929091336104005152600760205261405660ff60406104005120541661479a565b6008549660ff8816600681101561048f57806105de57506001600160401b038091169760081c1687036143215760ff610400515460a01c1684036142dc57866104005152600960205260406104005120866001600160401b0319825416179055866104005152600960205260406104005120906fffffffffffffffff000000000000000082549160401b16906fffffffffffffffff00000000000000001916179055614101836146e7565b61410e6040519182614483565b83815261411a846146e7565b602082019190601f19013683378761040051526009602052600160406104005120019051916001600160401b038311610cef57600160401b8311610cef5781548383558084106142ba575b5090610400515260206104005120610400515b8381106142a6575050610400519491508490505b8181106142485750505050612710036141f7577f7b158b44bae8b68ba7efc6ab9f46fe56309a2870128c67c38c041ba45fe1535d9183610400515260096020526103e26001604061040051200160405193849384526020840152606060408401526060830190614879565b60405162461bcd60e51b815260206004820152602360248201527f6275636b657420736861726573206e6f7420616464696e6720757020746f203160448201526230302560e81b6064820152608490fd5b61426b61271061426461425c8486896147fd565b358098614823565b9685614f04565b610400518101919082106105c4578160019250896104005152600960205261429e613e0a83856040610400512001614861565b90550161418c565b600190602084519401938184015501614178565b6142d690836104005152846020610400512091820191016147e6565b89614165565b60405162461bcd60e51b815260206004820152601c60248201527f696e76616c6964206275636b657420736861726573206c656e677468000000006044820152606490fd5b866320eeef9d60e01b6104005152600452602461040051fd5b3461045c57602036600319011261045c576020906001600160a01b0361435e614379565b1661040051526007825260ff60406104005120541615158152f35b600435906001600160a01b038216820361438f57565b600080fd5b602435906001600160a01b038216820361438f57565b35906001600160a01b038216820361438f57565b600435906001600160401b038216820361438f57565b9181601f8401121561438f578235916001600160401b03831161438f576020808501948460051b01011161438f57565b6004359063ffffffff8216820361438f57565b90600182811c92168015614447575b602083101461443157565b634e487b7160e01b600052602260045260246000fd5b91607f1691614426565b61014081019081106001600160401b0382111761446d57604052565b634e487b7160e01b600052604160045260246000fd5b90601f801991011681019081106001600160401b0382111761446d57604052565b90604051918260008254926144b884614417565b808452936001811690811561452657506001146144df575b506144dd92500383614483565b565b90506000929192526020600020906000915b81831061450a5750509060206144dd92820101386144d0565b60209193508060019154838589010152019101909184926144f1565b9050602092506144dd94915060ff191682840152151560051b820101386144d0565b919082519283825260005b848110614574575050826000602080949584010152601f8019910116010190565b80602080928401015182828601015201614553565b906020808351928381520192019060005b8181106145a75750505090565b825184526020938401939092019160010161459a565b6004359060ff8216820361438f57565b9181601f8401121561438f578235916001600160401b03831161438f576020838186019501011161438f57565b61469e916001600160401b03825116815260ff602083015116602082015261012061463660408401516101406040850152610140840190614548565b926060810151606084015261ffff60808201511660808401526001600160a01b0360a08201511660a084015260c0810151151560c08401526001600160a01b0360e08201511660e0840152610100810151610100840152015190610120818403910152614589565b90565b9291926001600160401b03821161446d57604051916146ca601f8201601f191660200184614483565b82948184528183011161438f578281602093846000960137010152565b6001600160401b03811161446d5760051b60200190565b92919061470a816146e7565b936147186040519586614483565b602085838152019160051b810192831161438f57905b82821061473a57505050565b813581526020918201910161472e565b604060031982011261438f576004356001600160401b03811161438f5781614774916004016143d4565b92909291602435906001600160401b03821161438f57614796916004016143d4565b9091565b156147a157565b60405162461bcd60e51b815260206004820152601760248201527f6f6e6c79207375626d69747465727320616c6c6f7765640000000000000000006044820152606490fd5b8181106147f1575050565b600081556001016147e6565b919081101561480d5760051b0190565b634e487b7160e01b600052603260045260246000fd5b9190820180921161483057565b634e487b7160e01b600052601160045260246000fd5b60135481101561480d57601360005260206000200190600090565b805482101561480d5760005260206000200190600090565b906020825491828152019160005260206000209060005b81811061489d5750505090565b8254845260209093019260019283019201614890565b9190820391821161483057565b906148ca826146e7565b6148d76040519182614483565b82815280926148e8601f19916146e7565b0190602036910137565b805182101561480d5760209160051b010190565b604051906011548083528260208101601160005260206000209260005b8181106149385750506144dd92500383614483565b8454835260019485019487945060209093019201614923565b906040519182815491828252602082019060005260206000209260005b8181106149835750506144dd92500383614483565b845483526001948501948794506020909301920161496e565b6001600160401b03600019911601906001600160401b03821161483057565b60001981146148305760010190565b156149d157565b60405162461bcd60e51b815260206004820152601560248201527f65706f6368206e6f7420696e64657865642079657400000000000000000000006044820152606490fd5b8054906000815581614a26575050565b6000526020600020908101905b818110614a3e575050565b60008155600101614a33565b90600160401b811161446d57815491818155828210614a6857505050565b600052602060002091820191015b818110614a81575050565b60008155600101614a76565b908060209392818452848401376000828201840152601f01601f1916010190565b60ff1660ff81146148305760010190565b3563ffffffff8116810361438f5790565b903590601e198136030182121561438f57018035906001600160401b03821161438f5760200191813603831361438f57565b9082101561480d576147969160051b810190614ad0565b356001600160a01b038116810361438f5790565b35801515810361438f5790565b939291602091614b5291604087526040870191614a8d565b930152565b6001600160a01b03600054163303614b6b57565b63118cdaa760e01b6000523360045260246000fd5b614b8b90600c614861565b90549060031b1c9081600052600e6020526001600160a01b0360406000205492169190565b90815115614c9e575b81516001811115614c8e576001810180911161483057614bdb9060011c6148c0565b9060005b8351600019810190811161483057811015614c4f57614bfe81856148f2565b51600182019081831161483057614c18614c1f92876148f2565b5190614fbc565b614c2c8260011c856148f2565b526002810180911115614bdf57634e487b7160e01b600052601160045260246000fd5b909280516000198101908111614830578214614c6e575b505090614bb9565b614c7b82614c86926148f2565b519160011c836148f2565b523880614c66565b509080511561480d576020015190565b60009150565b9161042060405190614cb68183614483565b6020825250610400366020830137806000935b85516001811115614dec57600116158015614dd6575b614dad575b60011c9085516001810180911161483057614d019060011c6148c0565b9460005b8751600019810190811161483057811015614d6e57614d2481896148f2565b51600182019081831161483057614c18614d3e928b6148f2565b614d4b8260011c896148f2565b526002810180911115614d0557634e487b7160e01b600052601160045260246000fd5b909396959194929580516000198101908111614830578214614d98575b5050949193929092614cc9565b614c7b82614da5926148f2565b523880614d8b565b93614dd090614dbf60018718886148f2565b51614dca82856148f2565b526149bb565b93614ce4565b5085516000198101908111614830578110614cdf565b505090935091909152565b60c082015160009492939015614e9a576001600160a01b0360a08501511692833b15614e965785614e5a9593614e6c82969463ffffffff94604051998a988997889663ad5aa16d60e01b88521660048701526060602487015260648601906145fa565b84810360031901604486015291614a8d565b03925af18015614e8b57614e7e575050565b81614e8891614483565b50565b6040513d84823e3d90fd5b8580fd5b60405162461bcd60e51b815260206004820152601160248201527f70726f746f636f6c2064697361626c65640000000000000000000000000000006044820152606490fd5b6001600160a01b0361469e9392169182600052600282016020526040600020556150e6565b918183029160001981850993838086109503948086039514614f985784831115614f7f5790829109816000038216809204600281600302188082026002030280820260020302808202600203028082026002030280820260020302809102600203029360018380600003040190848311900302920304170290565b82634e487b71600052156003026011186020526024601cfd5b505091508115614fa6570490565b634e487b7160e01b600052601260045260246000fd5b81811015614fd257600052602052604060002090565b90600052602052604060002090565b8060005260126020526040600020541560001461503657601154600160401b81101561446d5761501d613e0a8260018594016011556011614861565b9055601154906000526012602052604060002055600190565b50600090565b8060005260036020526040600020541560001461503657600254600160401b81101561446d57615078613e0a8260018594016002556002614861565b9055600254906000526003602052604060002055600190565b80600052600d6020526040600020541560001461503657600c54600160401b81101561446d576150cd613e0a826001859401600c55600c614861565b9055600c5490600052600d602052604060002055600190565b600082815260018201602052604090205461513657805490600160401b82101561446d578261511f613e0a846001809601855584614861565b905580549260005201602052604060002055600190565b5050600090565b600081815260126020526040902054801561513657600019810181811161483057601154600019810191908211614830578181036151cd575b50505060115480156151b75760001901615191816011614861565b8154906000199060031b1b19169055601155600052601260205260006040812055600190565b634e487b7160e01b600052603160045260246000fd5b6151ef6151de613e0a936011614861565b90549060031b1c9283926011614861565b90556000526012602052604060002055388080615176565b60008181526003602052604090205480156151365760001981018181116148305760025460001981019190821161483057818103615281575b50505060025480156151b7576000190161525b816002614861565b8154906000199060031b1b19169055600255600052600360205260006040812055600190565b6152a3615292613e0a936002614861565b90549060031b1c9283926002614861565b90556000526003602052604060002055388080615240565b80600052600e60205260406000205480156000146152ea5750600052600d602052604060002054151590600090565b600192909150565b919080600052600283016020526040600020549283156000146153305761532a92935060019160005201602052604060002054151590565b90600090565b50506001919056fea26469706673582212208127f912c4df0ed32c9110a01f8ec23269ead0ac883d7df0b264619e26f24b9864736f6c634300081c0033000000000000000000000000c0d97651d3237b9be228bd40faabd2a5790cece6
Deployed Bytecode
0x61042080604052600436101561001457600080fd5b600061040052610400513560e01c908163065604351461433a575080630727917314613fcf578063072900f914613f575780630f6d1eb414613cb9578063116dcd7d14613c575780631b4fc38b14613c375780631e45e18514613baa5780631f26c48b14613a255780632ca8b601146139575780632cdbfb9314613914578063373db22914613809578063376c2bc81461377f5780633abbf2da146134a057806345a3533b1461337b5780634d0923d81461333857806350f0fa21146132935780636370f17d14612d2b578063669e4eb514612ad6578063715018a614612a7457806375ffab73146129c157806377586e04146127d65780638879315d146127aa5780638da5cb5b1461277f578063908225aa1461251b5780639682cbfa1461248e5780639d04209314611b05578063aa195f7b14611a7b578063ad9ebe32146119c4578063b94bd6bb1461187d578063baef9823146117e5578063bf73918e146115e4578063bfdcc9a2146115bc578063c19d93fb1461158b578063c36f41e214611516578063c772c87f1461147e578063c7f5aaa014611455578063ce13e7a81461141d578063d1ed17e014611198578063d5759c0914610fb3578063dc737a2014610ebc578063e18370ca14610d22578063e4524bb5146109a1578063ea0ce51814610691578063f2fde38b146105fb578063f3cb8577146104a95763fa2ec0301461022257600080fd5b3461045c57602036600319011261045c5761023b614404565b610243614b57565b60ff6008541690600682101561048f57816104715763ffffffff168061040051526001602052604061040051206001600160a01b036040519161028583614451565b60ff81546001600160401b038116855260401c1660208401526102aa600182016144a4565b92604081019384526002820154606082015261012061030b600660038501549461ffff8616608086015260ff60a0860196888160101c16885260b01c16151560c08601528660048201541660e0860152600581015461010086015201614951565b9101525116803b1561045c57604051906368d50a8360e01b825283600483015281602481610400519361040051905af1801561046357610441575b506103e27f6822e4450f695ee0b191df6a12d39bce9f3f87472939c31165d011ca0a272f3c9161037584615207565b5083610400515260016020526103cd600660406104005120610400518155600181016103a18154614417565b806103ec575b505061040051600282018190556003820181905560048201819055600582015501614a16565b51604051918291602083526020830190614548565b0390a26104005180f35b601f811160011461040657506104005190555b87806103a7565b610429908261040051526001601f60206104005120920160051c820191016147e6565b610400805182905251602081209181905590556103ff565b6104005161044e91614483565b6104005161045c5782610346565b6104005180fd5b6040513d61040051823e3d90fd5b5063683f44bb60e11b61040051526104005150600452602461040051fd5b634e487b7160e01b61040051526021600452602461040051fd5b3461045c57604036600319011261045c576104c2614379565b6024359033610400515260076020526104e460ff60406104005120541661479a565b60ff60085416600681101561048f57600381036105de57506001600160a01b03169061050f826152bb565b8091509061040051831360001461057e57508161054f7ff4793f27a2bf46ca8586a3150c23ad281663e90b7be224e1ee8a51c25019c08693604093614823565b846104005152600e602052808361040051205561056b85615091565b5082519182526020820152a26104005180f35b9050600160ff1b82146105c457816105bf6040927ff4793f27a2bf46ca8586a3150c23ad281663e90b7be224e1ee8a51c25019c086946104005103906148b3565b61054f565b634e487b7160e01b61040051526011600452602461040051fd5b63683f44bb60e11b61040051526104005150600452602461040051fd5b3461045c57602036600319011261045c576001600160a01b0361061c614379565b610624614b57565b168015610675576104005180546001600160a01b03198116831782556001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a36104005180f35b631e4fbdf760e01b610400515261040051600452602461040051fd5b3461045c57606036600319011261045c576004356001600160401b03811161045c576106c19036906004016143d4565b906024356001600160401b03811161045c576106e19036906004016143d4565b90926044356001600160401b03811161045c576107029036906004016143d4565b919092336104005152600760205261072360ff60406104005120541661479a565b81158015610997575b801561098d575b61097857610400515b82811061074a576104005180f35b61075d6107588285896147fd565b614abf565b61076882848a614b02565b61077384888a614b02565b939092336104005152600760205261079460ff60406104005120541661479a565b60ff60085416600681101561048f57600181036105de57506108ad9063ffffffff83166104005152600160205260606040610400512091604051956107d887614451565b60ff84546001600160401b038116895260401c1660208801526107fd600185016144a4565b60408801526108656006600286015495858a0196875260ff600382015461ffff811660808d01526001600160a01b038160101c1660a08d015260b01c16151560c08b01526001600160a01b0360048201541660e08b015260058101546101008b015201614951565b6101208801526001600160a01b0360045416906001600160401b038851166040519687948593849363e044095360e01b85526004850152604060248501526044840191614a8d565b039161040051905af1908115610463576104005192839261093b575b50518082036109205750506108df3686866146a1565b60208151910120908181036109055750509160019493916108ff93614df7565b0161073c565b6340f748cd60e01b6104005152600452602452604461040051fd5b6335bce51360e11b6104005152600452602452604461040051fd5b925090506060823d8211610970575b8161095760609383614483565b8101031261045c5760406020830151920151908e6108c9565b3d915061094a565b63637643ab60e11b6104005152600461040051fd5b5082811415610733565b508082141561072c565b3461045c57604036600319011261045c576109ba6143be565b6024356008549160ff8316600681101561048f57600281036105de57506001600160401b038091169260081c168203610d0957816104005152600960205260406104005120906040519160808301928084106001600160401b03851117610cef57610a6660609260019560405280546001600160401b03811684526001600160401b038160401c16602085015260801c6040840152610a5f6040518097819301614879565b0385614483565b0191825260ff600f541660105492610400515061040051935b8315610ce65760ff831693846104005152600a6020526040610400512094855415610cb1575090610ac091610baa610b4187865160ff8916968780926148f2565b518c7f9efdcd7e00e57e4d2c7c12f1e0408a812a8d940da0afada9938d88be5d4710a660606002610af18b88614861565b90549060031b1c96019580610400515286602052610b4b6001600160a01b0360406104005120549216988996886104005152600b6020526040610400512054906104005150610400515084614f04565b6104005190614823565b610b5f81610b58886152bb565b9050614823565b90866104005152600e602052816040610400512055610b7d87615091565b5060405192835260208301526040820152a4816104005152602052610400516040610400512055876150e6565b5060001901945460001981019081116105c4578103610c9e5782515160001981019081116105c4578214610c0557506104005152600b602052610400516040610400512055610bfc6104005192614aae565b935b9391610a7f565b93505050915060015b15610c86575060ff90610400515061040051506003821960085416176008558119600f5416600f5561040051601055166104005152600b6020526104005160406104005120557f64e4fe2e975e34557ba3458484d9064e3eae16332ae974185f17dda74fc292c26104005161040051a25b6104005180f35b915060ff1660ff19600f541617600f55601055610c7f565b610cab91509492946149bb565b91610bfe565b83515191955091939160001982019182116105c45714610cda57610cd490614aae565b93610bfe565b93505090506001610c0e565b92505091610c0e565b634e487b7160e01b61040051526041600452602461040051fd5b506320eeef9d60e01b6104005152600452602461040051fd5b3461045c57610d303661474a565b919290923361040051526007602052610d5260ff60406104005120541661479a565b80158015610eb2575b61097857610400515b838110610d72576104005180f35b610d85610d808284866147fd565b614b19565b90610d918186886147fd565b353361040051526007602052610db060ff60406104005120541661479a565b60085460ff8116600681101561048f57806105de575060081c6001600160401b03168015908115610e81575b5015610e3c577fa1a86ec5bc9cb16543e635cdd7c4b82bda0b15213dbd82348f879042b3e9780860206001600160a01b036001951692836104005152600e8252806040610400512055610e2e84615091565b50604051908152a201610d64565b60405162461bcd60e51b815260206004820152600f60248201527f77616974206e65787420626c6f636b00000000000000000000000000000000006044820152606490fd5b6001600160401b039150610e949061499c565b1661040051526009602052604061040051205460801c431188610ddc565b5082811415610d5b565b3461045c57604036600319011261045c57610ed5614379565b602435903361040051526007602052610ef760ff60406104005120541661479a565b60085460ff8116600681101561048f57806105de575060081c6001600160401b03168015908115610f82575b5015610e3c5760206001600160a01b037fa1a86ec5bc9cb16543e635cdd7c4b82bda0b15213dbd82348f879042b3e97808921692836104005152600e8252806040610400512055610f7384615091565b50604051908152a26104005180f35b6001600160401b039150610f959061499c565b1661040051526009602052604061040051205460801c431183610f23565b3461045c57610fc13661474a565b610fcc939193614b57565b808303610978576104005160ff60085416916006831093831515925b868110610ff6576104005180f35b6110046107588289856147fd565b61101761101283868c6147fd565b614b2d565b90611020614b57565b871561048f578561117e579063ffffffff6001939216908161040051528360205260406104005120906040519161105683614451565b60ff81546001600160401b038116855260401c16602084015261107a8682016144a4565b9260408101938452600282015460608201526101206110e9600660038501549461ffff861660808601526001600160a01b038660101c1660a086015260ff60c086019660b01c16151586526001600160a01b0360048201541660e0860152600581015461010086015201614951565b910152811515905260001461113c576111327faaf817e27cb709c532bd8a556c41800cc79948f41be602afcf86269a162eb4bd9151604051918291602083526020830190614548565b0390a25b01610fe8565b6111767fcd6dd2bfbc2095d9f6cf85d22bfb83173551ba7a122305b908fc5524c0714c669151604051918291602083526020830190614548565b0390a2611136565b610400805163683f44bb60e11b9052516004889052602490fd5b3461045c57608036600319011261045c576111b16145bd565b6111b9614394565b60443591606435906001600160401b03821161045c578160040190610140600319843603011261045c57336104005152600660205260ff604061040051205416156113d85760ff1692836104005152600a60205260406104005120946001600160a01b0382169561122a87826152f2565b6104005190949150610104870135806112da575b50926112886112c1937fff4b09174e75080e8d34b61d08ea82e7d1100c558cb6ba7571bcacf69899c21c979361128261127b6112d09998866148b3565b8098614823565b91614edf565b50876104005152600b6020526112a660406104005120918254614823565b905560446001600160401b0360085460081c16960190614ad0565b92909160405193849384614b3a565b0390a46104005180f35b848197939496959250029581870414811517156105c457611288856112c19461128261127b6113b4878e6112d09c8f7fff4b09174e75080e8d34b61d08ea82e7d1100c558cb6ba7571bcacf69899c21c9f7fff4b09174e75080e8d34b61d08ea82e7d1100c558cb6ba7571bcacf69899c21c916113c56127106001600160a01b03930497889761139160e485019761137c876113758b614b19565b16826152f2565b90506112828c61138b8c614b19565b92614823565b5060446113ac6001600160401b0360085460081c1698614b19565b940190614ad0565b604098919851948594169884614b3a565b0390a4959899505050939750935061123e565b60405162461bcd60e51b815260206004820152601c60248201527f6f6e6c7920726573756c742068616e646c65727320616c6c6f776564000000006044820152606490fd5b3461045c57602036600319011261045c5760ff6114386145bd565b166104005152600b60205260206040610400512054604051908152f35b3461045c576104005136600319011261045c5760206001600160a01b0360045416604051908152f35b3461045c57602036600319011261045c576001600160a01b0361149f614379565b6114a7614b57565b1680156115015760407fddb7d4b45d521a6718ed9ccac62f1faa18b869772bca7e77ab6f392912a4ec189160045490806001600160a01b03198316176004556001600160a01b038351921682526020820152a16104005180f35b63d92e233d60e01b6104005152600461040051fd5b3461045c57602036600319011261045c576001600160a01b03611537614379565b61153f614b57565b1680610400515260076020526040610400512060ff1981541690557ff84a004e1673d2f349a7c93c72b3794b8eba6d2f9338044d8c8cd260e51a57a16104005161040051a26104005180f35b3461045c576104005136600319011261045c5760ff600854166040516104005150600682101561048f576020918152f35b3461045c576104005136600319011261045c57602060ff610400515460a01c16604051908152f35b3461045c57606036600319011261045c576115fd614404565b6024356001600160401b03811161045c57610140600319823603011261045c576040519061162a82614451565b60048101356001600160401b038116810361045c578252602481013560ff8116810361045c57602083015260448101356001600160401b03811161045c5781013660238201121561045c576116899036906024600482013591016146a1565b604083015260648101356060830152608481013561ffff8116810361045c5760808301526116b960a482016143aa565b60a083015260c4810135801515810361045c5760c08301526116dd60e482016143aa565b60e0830152610104810135610100830152610124810135906001600160401b03821161045c57013660238201121561045c576117239036906024600482013591016146fe565b6101208201526044356001600160401b03811161045c576117489036906004016145cd565b91336104005152600560205260ff604061040051205416156117a05760ff6008541693600685101561048f576001850361178657610c7f9450614df7565b610400805163683f44bb60e11b9052516004869052602490fd5b60405162461bcd60e51b815260206004820152601b60248201527f6f6e6c792070726f6f662068616e646c65727320616c6c6f77656400000000006044820152606490fd5b3461045c57602036600319011261045c576117fe6143be565b336104005152600760205261181c60ff60406104005120541661479a565b60ff6008541690600682101561048f576003820361047157610400516008805460ff191660041790556001600160401b0391909116907fdd84b0a0fa79088c80855ac82217e24a5ae3ba87f19cef1d17696429b444c6dc9080a26104005180f35b3461045c57602036600319011261045c5763ffffffff61189b614404565b60606101206040516118ac81614451565b61040051815261040051602082015282604082015261040051838201526104005160808201526104005160a08201526104005160c08201526104005160e082015261040051610100820152015216610400515260016020526119c0604061040051206119a660066040519261192084614451565b60ff81546001600160401b038116865260401c166020850152611945600182016144a4565b60408501526002810154606085015260ff600382015461ffff811660808701526001600160a01b038160101c1660a087015260b01c16151560c08501526001600160a01b0360048201541660e0850152600581015461010085015201614951565b6101208201526040519182916020835260208301906145fa565b0390f35b3461045c57602036600319011261045c576119dd614379565b6008549060ff8216600681101561048f57806105de5750611a32611a2a6001600160a01b036001600160401b0360409560081c169384158015611a48575b611a24906149ca565b166152bb565b92905061499c565b906001600160401b038351921682526020820152f35b506001600160401b03611a5a8661499c565b1661040051526009602052611a248661040051205460801c43119050611a1b565b3461045c57602036600319011261045c57611a94614379565b611a9c614b57565b60ff6008541690600682101561048f5781610471576001600160a01b031680610400515260066020526040610400512060ff1981541690557f1602c5bcc673d1d5f0c782ac7faa22c4e47e10222017072c7c0a1aef8e1e16156104005161040051a26104005180f35b3461045c5761016036600319011261045c576004356001600160401b03811161045c57611b369036906004016143d4565b60c05260a0526024356001600160401b03811161045c57611b5b9036906004016143d4565b60e052610320526044356001600160401b03811161045c57611b819036906004016143d4565b61034052610100526064356001600160401b03811161045c57611ba89036906004016143d4565b610120526102e0526084356001600160401b03811161045c57611bcf9036906004016143d4565b610360526102205260a4356001600160401b03811161045c57611bf69036906004016143d4565b610300526101405260c4356001600160401b03811161045c57611c1d9036906004016143d4565b610160526102405260e4356001600160401b03811161045c57611c449036906004016143d4565b6101805261026052610104356001600160401b03811161045c57611c6c9036906004016143d4565b6101a0526102a052610124356001600160401b03811161045c57611c949036906004016143d4565b6101c0526102c0526001600160401b03610144351161045c57611cbd36610144356004016143d4565b610280526101e052611ccd614b57565b60c051158015612480575b8015612471575b8015612461575b8015612451575b8015612441575b8015612431575b8015612421575b8015612411575b8015612401575b80156123f1575b6109785761040051610200525b610360516102005110611d38576104005180f35b611d4a6102005160c05160a0516147fd565b356001600160401b038116810361045c57611d716107586102005160e051610320516147fd565b90611d866102005161034051610100516147fd565b3560ff8116810361045c57611da561020051610120516102e051614b02565b9091611dbb6102005161036051610220516147fd565b3592611dd16102005161030051610140516147fd565b3561ffff8116810361045c57611df4610d806102005161016051610240516147fd565b611e0b6110126102005161018051610260516147fd565b90611e23610d80610200516101a0516102a0516147fd565b92611e38610200516101c0516102c0516147fd565b3594610280516102005110156123d757601e196101e0513603016102005160051b6101e0510135121561045c576102005160051b6101e05101356101e05101976001600160401b0389351161045c57883560051b360360208a011361045c57611e9f614b57565b60ff60085416600681101561048f57806105de57506001600160a01b0384166104005152600660205260ff604061040051205416156123925760ff610400515460a01c1660ff8916101561234d57611efc63ffffffff8d1661503c565b506001600160a01b0384163b1561045c5760405163052db9cf60e31b815263ffffffff8d1660048201526104005181602481836001600160a01b038a165af1801561046357612332575b50604051611f5381614451565b6001600160401b038c16815260ff89166020820152611f733683856146a1565b60408201528a606082015261ffff841660808201526001600160a01b03851660a082015285151560c08201526001600160a01b03871660e082015287610100820152611fc4368b3560208d016146fe565b61012082015263ffffffff8d166104005152600160205260406104005120906001600160401b0380825116166001600160401b0319835416178255602081015168ff000000000000000083549160401b169068ff0000000000000000191617825560408101518051906001600160401b038211610cef576120486001850154614417565b601f81116122ee575b506020906001601f84111461227757918061208a926101209594610400519261226c575b50508160011b916000199060031b1c19161790565b60018401555b606081015160028401556003830161ffff60808301511681549075ffffffffffffffffffffffffffffffffffffffff000060a085015160101b169076ffffffffffffffffffffffffffffffffffffffffffffff1960ff60b01b60c0870151151560b01b16931617171790556001600160a01b0360e0820151166001600160a01b036004850191166001600160a01b031982541617905561010081015160058401550151908151916001600160401b038311610cef57602060069161215685848601614a4a565b019101610400515260206104005120610400515b83811061225857505050506001600160a01b0395949391926121a5879461ffff93604051608052610100608051526101006080510191614a8d565b9a602060805101521660406080510152166060608051015215156080805101521660a0608051015260c06080510152608051830360e06080510152813583526001600160fb1b0382351161045c57816001600160401b0363ffffffff60ff6020947f22cc39fb9f698334c07d92b6c2cc1a233f0da11fed8b1d8b320e7af2ed32a5f2963560051b868601878a0137169716951693608051913560051b010301608051a46001610200510161020052611d24565b60019060208451940193818401550161216a565b015190503880612075565b90601f1983169160018601610400515281610400512092610400515b8181106122d65750916001939185610120979694106122bd575b505050811b016001840155612090565b015160001960f88460031b161c191690553880806122ad565b92936020600181928786015181550195019301612293565b6123229060018601610400515260206104005120601f850160051c81019160208610612328575b601f0160051c01906147e6565b38612051565b9091508190612315565b6104005161233f91614483565b6104005161045c578c611f46565b60405162461bcd60e51b815260206004820152600e60248201527f696e76616c6964206275636b65740000000000000000000000000000000000006044820152606490fd5b60405162461bcd60e51b815260206004820152601b60248201527f756e617574686f72697a656420726573756c742068616e646c657200000000006044820152606490fd5b634e487b7160e01b61040051526032600452602461040051fd5b50610280516101c0511415611d17565b506101c0516101a0511415611d10565b506101a051610180511415611d09565b5061018051610160511415611d02565b5061016051610300511415611cfb565b5061030051610360511415611cf4565b5061036051610120511415611ced565b5061012051610340511415611ce6565b506103405160e0511415611cdf565b5060e05160c0511415611cd8565b3461045c57602036600319011261045c576124a7614379565b6124af614b57565b60ff6008541690600682101561048f5781610471576001600160a01b0316806104005152600660205260406104005120600160ff198254161790557f502e775abb2383950531644d7bf2d4c666e9596157bf6f4c7d9b51ce0336314e6104005161040051a26104005180f35b3461045c57602036600319011261045c576004356001600160401b03811161045c5761254b9036906004016143d4565b90612554614b57565b610400515b828110612567576104005180f35b6125756107588285856147fd565b61257d614b57565b60ff60085416600681101561048f57806105de575063ffffffff1690816104005152600160205260406104005120916001600160a01b03604051936125c185614451565b60ff81546001600160401b038116875260401c1660208601526125e6600182016144a4565b946040810195865260028201546060820152610120612647600660038501549461ffff8616608086015260ff60a0860196888160101c16885260b01c16151560c08601528660048201541660e0860152600581015461010086015201614951565b9101525116803b1561045c57604051906368d50a8360e01b825282600483015281602481610400519361040051905af1801561046357612764575b507f6822e4450f695ee0b191df6a12d39bce9f3f87472939c31165d011ca0a272f3c6127086001946126b384615207565b50836104005152856020526103cd6006604061040051206104005181558881016126dd8154614417565b8061271157505061040051600282018190556003820181905560048201819055600582015501614a16565b0390a201612559565b601f81118b1461272a57506104005190555b8b806103a7565b61274c908261040051528b601f60206104005120920160051c820191016147e6565b61040080518290525160208120918190559055612723565b6104005161277191614483565b6104005161045c5785612682565b3461045c576104005136600319011261045c5760206001600160a01b03610400515416604051908152f35b3461045c576104005136600319011261045c5760206001600160401b0360085460081c16604051908152f35b3461045c57602036600319011261045c576127ef6143be565b336104005152600760205261280d60ff60406104005120541661479a565b6008549060ff8216600681101561048f57600181036105de57506001600160401b038091169160081c1681036129a957610400515b6002548110156128f5576002548110156123d7576002610400515263ffffffff8160206104005120016104005150546104005160031b1c1680610400515260016020526001600160a01b03600360406104005120015460101c16803b1561045c576040519163052db9cf60e31b8352600483015281602481610400519361040051905af18015610463576128da575b50600101612842565b610400516128e791614483565b6104005161045c57826128d1565b50610400515b816104005152600960205260016040610400512001549060ff81169182101561296a5781612965926104005152600b602052837fc09ad501f56c8a0caedcbad2ec1dab802b1ceef6c666a24040ffc4477958a59260206040610400512054604051908152a3614aae565b6128fb565b827f3711923da2f2c9c943ad1776a84dfe8778252657c474f9f306485453dc82ba236104005161040051a2610400516008805460ff1916600217905580f35b6320eeef9d60e01b6104005152600452602461040051fd5b3461045c57602036600319011261045c576129da6145bd565b6129e2614b57565b60ff60085416600681101561048f57806105de577f5f7601cd31de990d2b7fe9278b29c356d6b7a1e8557d82d7f19197d714b5088560208361040051547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff74ff00000000000000000000000000000000000000008360a01b16911617610400515560ff60405191168152a16104005180f35b3461045c576104005136600319011261045c57612a8f614b57565b6104005180546001600160a01b0319811682556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a36104005180f35b3461045c57606036600319011261045c57612aef614404565b6024356001600160401b03811161045c57612b0e9036906004016145cd565b90916044356001600160401b03811161045c57612b2f9036906004016145cd565b9290913361040051526007602052612b5060ff60406104005120541661479a565b60ff6008541694600686101561048f5760018603612d1157612c6a955063ffffffff8216610400515260016020526060604061040051209160405194612b9586614451565b60ff84546001600160401b038116885260401c166020870152612bba600185016144a4565b6040870152612c22600660028601549585890196875260ff600382015461ffff811660808c01526001600160a01b038160101c1660a08c015260b01c16151560c08a01526001600160a01b0360048201541660e08a015260058101546101008a015201614951565b6101208701526001600160a01b0360045416906001600160401b038751166040519a8b948593849363e044095360e01b85526004850152604060248501526044840191614a8d565b039161040051905af19081156104635761040051968792612cd3575b5051808203610920575050612c9c3685856146a1565b6020815191012094858103612cb65750610c7f9450614df7565b85906340f748cd60e01b6104005152600452602452604461040051fd5b965090506060863d606011612d09575b81612cf060609383614483565b8101031261045c57604060208701519601519087612c86565b3d9150612ce3565b610400805163683f44bb60e11b9052516004879052602490fd5b3461045c5761016036600319011261045c57612d456143be565b6103c0526024356103e081905263ffffffff8116900361045c5760443560ff8116810361045c576064356001600160401b03811161045c57612d8b9036906004016145cd565b60a4356103a08190529092919061ffff8116900361045c5760c435906001600160a01b038216820361045c5760e435801515810361045c5761010435906001600160a01b038216820361045c57610144356001600160401b03811161045c57612df89036906004016143d4565b906103805292612e06614b57565b60ff60085416600681101561048f57806105de57506001600160a01b0385166104005152600660205260ff604061040051205416156123925760ff610400515460a01c1660ff8716101561234d57612e6663ffffffff6103e0511661503c565b506001600160a01b0385163b1561045c5760405163052db9cf60e31b81526103e05163ffffffff1660048201526104005181602481836001600160a01b038b165af1801561046357613280575b50604051612ec081614451565b6001600160401b036103c051168152602081019060ff88168252612ee5368a856146a1565b60408201908152606082016084358152608083019061ffff6103a05116825260a08401906001600160a01b038b16825260c0850190881515825260e08601946001600160a01b038b16865261012435610100880152612f48368d610380516146fe565b61012088015263ffffffff6103e051166104005152600160205260406104005120976001600160401b0380895116166001600160401b03198a54161789555168ff000000000000000089549160401b169068ff00000000000000001916178855518051906001600160401b038211610cef57612fc760018a0154614417565b601f8111613247575b506020906001601f8411146131c357826001600160a01b039795936101209a9997959361301593610400519261226c5750508160011b916000199060031b1c19161790565b60018a01555b51600289015561ffff6003890193511676ffffffffffffffffffffffffffffffffffffffffffffff1960ff60b01b75ffffffffffffffffffffffffffffffffffffffff00008654955160101b169351151560b01b169316171717905551166001600160a01b036004850191166001600160a01b031982541617905561010081015160058401550151908151916001600160401b038311610cef5760206006916130c685848601614a4a565b019101610400515260206104005120610400515b8381106131af5750505050906001600160a01b03613108819493604051996101008b526101008b0191614a8d565b9560843560208a015261ffff6103a0511660408a0152166060880152151560808701521660a08501526101243560c085015283820360e08501528082526001600160fb1b03811161045c5760ff7f22cc39fb9f698334c07d92b6c2cc1a233f0da11fed8b1d8b320e7af2ed32a5f29160051b9384610380516020860137169360208163ffffffff6103e05116956001600160401b036103c051169501030190a46104005180f35b6001906020845194019381840155016130da565b90601f1983169160018b01610400515281610400512092610400515b81811061322f57509260019285926001600160a01b039a98966101209d9c9a989610613216575b505050811b0160018a015561301b565b015160001960f88460031b161c19169055388080613206565b929360206001819287860151815501950193016131df565b61327a9060018b01610400515260206104005120601f850160051c8101916020861061232857601f0160051c01906147e6565b38612fd0565b6104005161328d91614483565b87612eb3565b3461045c57604036600319011261045c576132ac6143be565b60243590600682101561045c576132c1614b57565b6008805460ff9390931668ffffffffffffffffff1990931691811b68ffffffffffffffff001691909117821790819055600682101561048f576001600160401b039060081c167fc0b26fd2c11b8c0762b3ddd78c4beaf1923e7ef6307ad2b5ceafb992ccdc1b916104005161040051a36104005180f35b3461045c57602036600319011261045c576001600160a01b03613359614379565b1661040051526006602052602060ff6040610400512054166040519015158152f35b3461045c57602036600319011261045c576133946143be565b33610400515260076020526133b260ff60406104005120541661479a565b6008549060ff8216600681101561048f57806105de57506001600160401b038082169260081c168203610d09578115801561346e575b6133f291506149ca565b601154610400515b81811061344057827ffa7123a93f584cf4d9fb3271d15b3f117fb9603f50b1d22b689b509b420225286104005161040051a2610400516008805460ff1916600117905580f35b601154156123d757600190601161040051526134676020610400512061040051505461513d565b50016133fa565b506134806001600160401b039161499c565b16610400515260096020526133f2604061040051205460801c43116133e8565b3461045c57604036600319011261045c576134b96143be565b6134c1614394565b60085460ff8116600681101561048f57806105de57506001600160401b036134ee81809360081c1661499c565b169216918203610d09576001600160a01b0316806104005152600e602052604061040051205490811580613765575b61374d576104005152600d602052604061040051205460001981019081116105c4576104005160115460001981019081119391929190845b6105c457838186951080613734575b1561357857613572906149bb565b93613555565b9190826137125761040051945b600c5461359287826148b3565b916105c4576135a89285106136e8575b506148c0565b91610400515b835181101561362657806136126136046135d26135cd6001958b614823565b614b80565b60409391935192839160208301958690916034926bffffffffffffffffffffffff199060601b16825260148201520190565b03601f198101835282614483565b51902061361f82876148f2565b52016135ae565b5061364c61363e8461363888886148b3565b90614ca4565b91613647614906565b614ca4565b9061366261365d8251845190614823565b6148c0565b92610400515b8251811015613690578061367e600192856148f2565b5161368982886148f2565b5201613668565b5091610400515b81518110156136c957806136ad600192846148f2565b516136c26136bc838751614823565b886148f2565b5201613697565b5050506119c06040519283928352604060208401526040830190614589565b9061370661370c926136f987614846565b90549060031b1c906148b3565b906148b3565b866135a2565b60001983018381116105c45761372790614846565b90549060031b1c94613585565b5061373e81614846565b90549060031b1c841015613564565b63015ab34360e11b6104005152600452602461040051fd5b506104008051829052600d6020525160409020541561351d565b3461045c57602036600319011261045c57613798614379565b6137a0614b57565b60ff6008541690600682101561048f5781610471576001600160a01b031680610400515260056020526040610400512060ff1981541690557fbe5dcd1f0b2a0fbeeeb1bb03d6eaa4dc9ed20124839302d2dd653b8c01d793ae6104005161040051a26104005180f35b3461045c57602036600319011261045c576138226143be565b6008549060ff8216600681101561048f57600581036105de57506001600160401b038091169160081c1681036129a95761386261385d614906565b614bb0565b60145580610400515260096020526040610400512080546fffffffffffffffffffffffffffffffff80194360801b1691161790556008546001600160401b038160081c166001600160401b0381146105c45768ffffffffffffffffff19909116600191909101600890811b68ffffffffffffffff00169190911790556014546040519081527f149bb8e98c16d440ac1f1a03a4d3c2d93d9011a48aba5ab0e47386c72c6cd4f890602090a26104005180f35b3461045c57602036600319011261045c576001600160a01b03613935614379565b1661040051526005602052602060ff6040610400512054166040519015158152f35b3461045c57602036600319011261045c5763ffffffff613975614404565b166104005152600160205260ff60406104005120805490613998600182016144a4565b6002820154918460038201546139e960056001600160a01b036004860154169401549460405198886001600160401b038b9a168a5260401c1660208901526101206040890152610120880190614548565b94606087015261ffff811660808701526001600160a01b038160101c1660a087015260b01c16151560c085015260e08401526101008301520390f35b3461045c57604036600319011261045c57613a3e614404565b602435908115159081830361045c57613a55614b57565b60ff60085416600681101561048f57806105de575063ffffffff16918261040051526001602052604061040051209160405192613a9184614451565b60ff81546001600160401b038116865260401c166020850152613ab6600182016144a4565b936040810194855260028201546060820152610120613b25600660038501549461ffff861660808601526001600160a01b038660101c1660a086015260ff60c086019660b01c16151586526001600160a01b0360048201541660e0860152600581015461010086015201614951565b9101525215613b68576103e27faaf817e27cb709c532bd8a556c41800cc79948f41be602afcf86269a162eb4bd9151604051918291602083526020830190614548565b613ba27fcd6dd2bfbc2095d9f6cf85d22bfb83173551ba7a122305b908fc5524c0714c669151604051918291602083526020830190614548565b0390a2610c7f565b3461045c57602036600319011261045c57613bc3614379565b613bcb614b57565b60ff6008541690600682101561048f5781610471576001600160a01b0316806104005152600560205260406104005120600160ff198254161790557f1a6f0b2e0a49f9872fcf562d696d893dc6c4094bdcd27cba1c6e14311a56c8376104005161040051a26104005180f35b3461045c576104005136600319011261045c576020601454604051908152f35b3461045c57602036600319011261045c576001600160401b03613c786143be565b166104005152600960205260606040610400512054604051906001600160401b03811682526001600160401b038160401c16602083015260801c6040820152f35b3461045c57604036600319011261045c57613cd26143be565b6024356008549160ff8316600681101561048f57600481036105de57506001600160401b038091169260081c168203610d09576401000000008111613f1257601154610400519080613eee57610400516013805491905580613ecd575b505b613d3d82600c546148b3565b90818411613ec4575b84613d50856148c0565b610400515b868110613e2857506020613d897fa798d21d4735fa640961e41c1c64c71ac1a880bed56cc8f53dd2e4fa0cd51f4d92614bb0565b613d9281614fe1565b50604051908152a38203613dde575050610400516008805460ff191660051790557fb95c96f28d7bc16885c1b6299dcc3816b715899206a2e0939cce4c4c9bb2d5679080a26104005180f35b613de89250614823565b601354600160401b811015610cef57613e0a816001613e219301601355614846565b819391549060031b91821b91600019901b19161790565b9055610c7f565b8084600193947f43fa36b7b583cad3d050ef0cb611495f9f3bd6ccfcc858eeb0b677dc65c71cce6060613e5e6135cd868d614823565b604051606083901b6bffffffffffffffffffffffff1916602082019081526034820183905290613e918160548101613604565b5190209081613ea0898d6148f2565b526001600160a01b036040519316835260208301526040820152a401908691613d55565b92508092613d46565b613ee8906013610400515260206104005120908101906147e6565b84613d2f565b905060001981018181116105c457613f0590614846565b90549060031b1c90613d31565b60405162461bcd60e51b815260206004820152600f60248201527f746f6f206d616e79206c656176657300000000000000000000000000000000006044820152606490fd5b3461045c57602036600319011261045c576001600160a01b03613f78614379565b613f80614b57565b16806104005152600760205260406104005120600160ff198254161790557fb079bc2cbde1f186e0b351d4a87c4597e3ed098f571548617449e73506428d8b6104005161040051a26104005180f35b3461045c5760a036600319011261045c57613fe86143be565b6024356001600160401b0381169081900361045c576044356001600160401b0381169081810361045c57606435906084356001600160401b03811161045c576140359036906004016143d4565b929091336104005152600760205261405660ff60406104005120541661479a565b6008549660ff8816600681101561048f57806105de57506001600160401b038091169760081c1687036143215760ff610400515460a01c1684036142dc57866104005152600960205260406104005120866001600160401b0319825416179055866104005152600960205260406104005120906fffffffffffffffff000000000000000082549160401b16906fffffffffffffffff00000000000000001916179055614101836146e7565b61410e6040519182614483565b83815261411a846146e7565b602082019190601f19013683378761040051526009602052600160406104005120019051916001600160401b038311610cef57600160401b8311610cef5781548383558084106142ba575b5090610400515260206104005120610400515b8381106142a6575050610400519491508490505b8181106142485750505050612710036141f7577f7b158b44bae8b68ba7efc6ab9f46fe56309a2870128c67c38c041ba45fe1535d9183610400515260096020526103e26001604061040051200160405193849384526020840152606060408401526060830190614879565b60405162461bcd60e51b815260206004820152602360248201527f6275636b657420736861726573206e6f7420616464696e6720757020746f203160448201526230302560e81b6064820152608490fd5b61426b61271061426461425c8486896147fd565b358098614823565b9685614f04565b610400518101919082106105c4578160019250896104005152600960205261429e613e0a83856040610400512001614861565b90550161418c565b600190602084519401938184015501614178565b6142d690836104005152846020610400512091820191016147e6565b89614165565b60405162461bcd60e51b815260206004820152601c60248201527f696e76616c6964206275636b657420736861726573206c656e677468000000006044820152606490fd5b866320eeef9d60e01b6104005152600452602461040051fd5b3461045c57602036600319011261045c576020906001600160a01b0361435e614379565b1661040051526007825260ff60406104005120541615158152f35b600435906001600160a01b038216820361438f57565b600080fd5b602435906001600160a01b038216820361438f57565b35906001600160a01b038216820361438f57565b600435906001600160401b038216820361438f57565b9181601f8401121561438f578235916001600160401b03831161438f576020808501948460051b01011161438f57565b6004359063ffffffff8216820361438f57565b90600182811c92168015614447575b602083101461443157565b634e487b7160e01b600052602260045260246000fd5b91607f1691614426565b61014081019081106001600160401b0382111761446d57604052565b634e487b7160e01b600052604160045260246000fd5b90601f801991011681019081106001600160401b0382111761446d57604052565b90604051918260008254926144b884614417565b808452936001811690811561452657506001146144df575b506144dd92500383614483565b565b90506000929192526020600020906000915b81831061450a5750509060206144dd92820101386144d0565b60209193508060019154838589010152019101909184926144f1565b9050602092506144dd94915060ff191682840152151560051b820101386144d0565b919082519283825260005b848110614574575050826000602080949584010152601f8019910116010190565b80602080928401015182828601015201614553565b906020808351928381520192019060005b8181106145a75750505090565b825184526020938401939092019160010161459a565b6004359060ff8216820361438f57565b9181601f8401121561438f578235916001600160401b03831161438f576020838186019501011161438f57565b61469e916001600160401b03825116815260ff602083015116602082015261012061463660408401516101406040850152610140840190614548565b926060810151606084015261ffff60808201511660808401526001600160a01b0360a08201511660a084015260c0810151151560c08401526001600160a01b0360e08201511660e0840152610100810151610100840152015190610120818403910152614589565b90565b9291926001600160401b03821161446d57604051916146ca601f8201601f191660200184614483565b82948184528183011161438f578281602093846000960137010152565b6001600160401b03811161446d5760051b60200190565b92919061470a816146e7565b936147186040519586614483565b602085838152019160051b810192831161438f57905b82821061473a57505050565b813581526020918201910161472e565b604060031982011261438f576004356001600160401b03811161438f5781614774916004016143d4565b92909291602435906001600160401b03821161438f57614796916004016143d4565b9091565b156147a157565b60405162461bcd60e51b815260206004820152601760248201527f6f6e6c79207375626d69747465727320616c6c6f7765640000000000000000006044820152606490fd5b8181106147f1575050565b600081556001016147e6565b919081101561480d5760051b0190565b634e487b7160e01b600052603260045260246000fd5b9190820180921161483057565b634e487b7160e01b600052601160045260246000fd5b60135481101561480d57601360005260206000200190600090565b805482101561480d5760005260206000200190600090565b906020825491828152019160005260206000209060005b81811061489d5750505090565b8254845260209093019260019283019201614890565b9190820391821161483057565b906148ca826146e7565b6148d76040519182614483565b82815280926148e8601f19916146e7565b0190602036910137565b805182101561480d5760209160051b010190565b604051906011548083528260208101601160005260206000209260005b8181106149385750506144dd92500383614483565b8454835260019485019487945060209093019201614923565b906040519182815491828252602082019060005260206000209260005b8181106149835750506144dd92500383614483565b845483526001948501948794506020909301920161496e565b6001600160401b03600019911601906001600160401b03821161483057565b60001981146148305760010190565b156149d157565b60405162461bcd60e51b815260206004820152601560248201527f65706f6368206e6f7420696e64657865642079657400000000000000000000006044820152606490fd5b8054906000815581614a26575050565b6000526020600020908101905b818110614a3e575050565b60008155600101614a33565b90600160401b811161446d57815491818155828210614a6857505050565b600052602060002091820191015b818110614a81575050565b60008155600101614a76565b908060209392818452848401376000828201840152601f01601f1916010190565b60ff1660ff81146148305760010190565b3563ffffffff8116810361438f5790565b903590601e198136030182121561438f57018035906001600160401b03821161438f5760200191813603831361438f57565b9082101561480d576147969160051b810190614ad0565b356001600160a01b038116810361438f5790565b35801515810361438f5790565b939291602091614b5291604087526040870191614a8d565b930152565b6001600160a01b03600054163303614b6b57565b63118cdaa760e01b6000523360045260246000fd5b614b8b90600c614861565b90549060031b1c9081600052600e6020526001600160a01b0360406000205492169190565b90815115614c9e575b81516001811115614c8e576001810180911161483057614bdb9060011c6148c0565b9060005b8351600019810190811161483057811015614c4f57614bfe81856148f2565b51600182019081831161483057614c18614c1f92876148f2565b5190614fbc565b614c2c8260011c856148f2565b526002810180911115614bdf57634e487b7160e01b600052601160045260246000fd5b909280516000198101908111614830578214614c6e575b505090614bb9565b614c7b82614c86926148f2565b519160011c836148f2565b523880614c66565b509080511561480d576020015190565b60009150565b9161042060405190614cb68183614483565b6020825250610400366020830137806000935b85516001811115614dec57600116158015614dd6575b614dad575b60011c9085516001810180911161483057614d019060011c6148c0565b9460005b8751600019810190811161483057811015614d6e57614d2481896148f2565b51600182019081831161483057614c18614d3e928b6148f2565b614d4b8260011c896148f2565b526002810180911115614d0557634e487b7160e01b600052601160045260246000fd5b909396959194929580516000198101908111614830578214614d98575b5050949193929092614cc9565b614c7b82614da5926148f2565b523880614d8b565b93614dd090614dbf60018718886148f2565b51614dca82856148f2565b526149bb565b93614ce4565b5085516000198101908111614830578110614cdf565b505090935091909152565b60c082015160009492939015614e9a576001600160a01b0360a08501511692833b15614e965785614e5a9593614e6c82969463ffffffff94604051998a988997889663ad5aa16d60e01b88521660048701526060602487015260648601906145fa565b84810360031901604486015291614a8d565b03925af18015614e8b57614e7e575050565b81614e8891614483565b50565b6040513d84823e3d90fd5b8580fd5b60405162461bcd60e51b815260206004820152601160248201527f70726f746f636f6c2064697361626c65640000000000000000000000000000006044820152606490fd5b6001600160a01b0361469e9392169182600052600282016020526040600020556150e6565b918183029160001981850993838086109503948086039514614f985784831115614f7f5790829109816000038216809204600281600302188082026002030280820260020302808202600203028082026002030280820260020302809102600203029360018380600003040190848311900302920304170290565b82634e487b71600052156003026011186020526024601cfd5b505091508115614fa6570490565b634e487b7160e01b600052601260045260246000fd5b81811015614fd257600052602052604060002090565b90600052602052604060002090565b8060005260126020526040600020541560001461503657601154600160401b81101561446d5761501d613e0a8260018594016011556011614861565b9055601154906000526012602052604060002055600190565b50600090565b8060005260036020526040600020541560001461503657600254600160401b81101561446d57615078613e0a8260018594016002556002614861565b9055600254906000526003602052604060002055600190565b80600052600d6020526040600020541560001461503657600c54600160401b81101561446d576150cd613e0a826001859401600c55600c614861565b9055600c5490600052600d602052604060002055600190565b600082815260018201602052604090205461513657805490600160401b82101561446d578261511f613e0a846001809601855584614861565b905580549260005201602052604060002055600190565b5050600090565b600081815260126020526040902054801561513657600019810181811161483057601154600019810191908211614830578181036151cd575b50505060115480156151b75760001901615191816011614861565b8154906000199060031b1b19169055601155600052601260205260006040812055600190565b634e487b7160e01b600052603160045260246000fd5b6151ef6151de613e0a936011614861565b90549060031b1c9283926011614861565b90556000526012602052604060002055388080615176565b60008181526003602052604090205480156151365760001981018181116148305760025460001981019190821161483057818103615281575b50505060025480156151b7576000190161525b816002614861565b8154906000199060031b1b19169055600255600052600360205260006040812055600190565b6152a3615292613e0a936002614861565b90549060031b1c9283926002614861565b90556000526003602052604060002055388080615240565b80600052600e60205260406000205480156000146152ea5750600052600d602052604060002054151590600090565b600192909150565b919080600052600283016020526040600020549283156000146153305761532a92935060019160005201602052604060002054151590565b90600090565b50506001919056fea26469706673582212208127f912c4df0ed32c9110a01f8ec23269ead0ac883d7df0b264619e26f24b9864736f6c634300081c0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000c0d97651d3237b9be228bd40faabd2a5790cece6
-----Decoded View---------------
Arg [0] : _brevisProof (address): 0xC0D97651d3237B9be228BD40FaabD2A5790CEce6
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000c0d97651d3237b9be228bd40faabd2a5790cece6
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
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.