Overview
ETH Balance
0 ETH
Eth Value
$0.00Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
TiebreakerSubCommittee
Compiler Version
v0.8.26+commit.8a97fa7a
Optimization Enabled:
Yes with 200 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-FileCopyrightText: 2024 Lido <[email protected]> // SPDX-License-Identifier: MIT pragma solidity 0.8.26; import {Address} from "@openzeppelin/contracts/utils/Address.sol"; import {Durations} from "../types/Duration.sol"; import {Timestamp} from "../types/Timestamp.sol"; import {ITiebreakerCoreCommittee} from "../interfaces/ITiebreakerCoreCommittee.sol"; import {HashConsensus} from "./HashConsensus.sol"; import {ProposalsList} from "./ProposalsList.sol"; enum ProposalType { ScheduleProposal, ResumeSealable } /// @title Tiebreaker SubCommittee Contract /// @notice This contract allows a subcommittee to vote on and execute proposals for scheduling and resuming sealable addresses /// @dev Inherits from HashConsensus for voting mechanisms and ProposalsList for proposal management contract TiebreakerSubCommittee is HashConsensus, ProposalsList { address public immutable TIEBREAKER_CORE_COMMITTEE; constructor( address owner, address[] memory committeeMembers, uint256 executionQuorum, address tiebreakerCoreCommittee ) HashConsensus(owner, Durations.ZERO) { TIEBREAKER_CORE_COMMITTEE = tiebreakerCoreCommittee; _addMembers(committeeMembers, executionQuorum); } // --- // Schedule proposal // --- /// @notice Votes on a proposal to schedule /// @dev Allows committee members to vote on scheduling a proposal /// @param proposalId The ID of the proposal to schedule function scheduleProposal(uint256 proposalId) external { _checkCallerIsMember(); ITiebreakerCoreCommittee(TIEBREAKER_CORE_COMMITTEE).checkProposalExists(proposalId); (bytes memory proposalData, bytes32 key) = _encodeApproveProposal(proposalId); _vote(key, true); _pushProposal(key, uint256(ProposalType.ScheduleProposal), proposalData); } /// @notice Gets the current state of a schedule proposal /// @dev Retrieves the state of the schedule proposal for a given proposal ID /// @param proposalId The ID of the proposal /// @return support The number of votes in support of the proposal /// @return executionQuorum The required number of votes for execution /// @return quorumAt The number of votes required to reach quorum /// @return isExecuted Whether the proposal has been executed function getScheduleProposalState(uint256 proposalId) external view returns (uint256 support, uint256 executionQuorum, Timestamp quorumAt, bool isExecuted) { (, bytes32 key) = _encodeApproveProposal(proposalId); return _getHashState(key); } /// @notice Executes an approved schedule proposal /// @dev Executes the schedule proposal by calling the scheduleProposal function on the Tiebreaker Core contract /// @param proposalId The ID of the proposal to schedule function executeScheduleProposal(uint256 proposalId) external { (, bytes32 key) = _encodeApproveProposal(proposalId); _markUsed(key); Address.functionCall( TIEBREAKER_CORE_COMMITTEE, abi.encodeWithSelector(ITiebreakerCoreCommittee.scheduleProposal.selector, proposalId) ); } /// @notice Encodes a schedule proposal /// @dev Internal function to encode the proposal data and generate the proposal key /// @param proposalId The ID of the proposal to schedule /// @return data The encoded proposal data /// @return key The generated proposal key function _encodeApproveProposal(uint256 proposalId) internal pure returns (bytes memory data, bytes32 key) { data = abi.encode(ProposalType.ScheduleProposal, proposalId); key = keccak256(data); } // --- // Sealable resume // --- /// @notice Votes on a proposal to resume a sealable address /// @dev Allows committee members to vote on resuming a sealable address /// reverts if the sealable address is the zero address or if the sealable address is not paused /// @param sealable The address to resume function sealableResume(address sealable) external { _checkCallerIsMember(); ITiebreakerCoreCommittee(TIEBREAKER_CORE_COMMITTEE).checkSealableIsPaused(sealable); (bytes memory proposalData, bytes32 key,) = _encodeSealableResume(sealable); _vote(key, true); _pushProposal(key, uint256(ProposalType.ResumeSealable), proposalData); } /// @notice Gets the current state of a resume sealable proposal /// @dev Retrieves the state of the resume sealable proposal for a given address /// @param sealable The address to resume /// @return support The number of votes in support of the proposal /// @return executionQuorum The required number of votes for execution /// @return quorumAt The timestamp when the quorum was reached /// @return isExecuted Whether the proposal has been executed function getSealableResumeState(address sealable) external view returns (uint256 support, uint256 executionQuorum, Timestamp quorumAt, bool isExecuted) { (, bytes32 key,) = _encodeSealableResume(sealable); return _getHashState(key); } /// @notice Executes an approved resume sealable proposal /// @dev Executes the resume sealable proposal by calling the sealableResume function on the Tiebreaker Core contract /// @param sealable The address to resume function executeSealableResume(address sealable) external { (, bytes32 key, uint256 nonce) = _encodeSealableResume(sealable); _markUsed(key); Address.functionCall( TIEBREAKER_CORE_COMMITTEE, abi.encodeWithSelector(ITiebreakerCoreCommittee.sealableResume.selector, sealable, nonce) ); } /// @notice Encodes a resume sealable proposal /// @dev Internal function to encode the proposal data and generate the proposal key /// @param sealable The address to resume /// @return data The encoded proposal data /// @return key The generated proposal key /// @return nonce The current resume nonce for the sealable address function _encodeSealableResume(address sealable) internal view returns (bytes memory data, bytes32 key, uint256 nonce) { nonce = ITiebreakerCoreCommittee(TIEBREAKER_CORE_COMMITTEE).getSealableResumeNonce(sealable); data = abi.encode(ProposalType.ResumeSealable, sealable, nonce); key = keccak256(data); } }
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)
pragma solidity ^0.8.20;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/
error AddressInsufficientBalance(address account);
/**
* @dev There's no code at `target` (it is not a contract).
*/
error AddressEmptyCode(address target);
/**
* @dev A call to an address target failed. The target may have reverted.
*/
error FailedInnerCall();
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert AddressInsufficientBalance(address(this));
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert FailedInnerCall();
}
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason or custom error, it is bubbled
* up by this function (like regular Solidity function calls). However, if
* the call reverted with no returned reason, this function reverts with a
* {FailedInnerCall} error.
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert AddressInsufficientBalance(address(this));
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
* was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
* unsuccessful call.
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
// only check if target is a contract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
/**
* @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
* revert reason or with a default {FailedInnerCall} error.
*/
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
/**
* @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
*/
function _revert(bytes memory returndata) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert FailedInnerCall();
}
}
}// SPDX-FileCopyrightText: 2024 Lido <[email protected]> // SPDX-License-Identifier: MIT pragma solidity 0.8.26; import {Timestamp, Timestamps} from "./Timestamp.sol"; // --- // Type Definition // --- type Duration is uint32; // --- // Assign Global Operations // --- using {lt as <, lte as <=, eq as ==, neq as !=, gte as >=, gt as >} for Duration global; using {addTo, plusSeconds, minusSeconds, multipliedBy, dividedBy, toSeconds} for Duration global; using {plus as +, minus as -} for Duration global; // --- // Errors // --- error DivisionByZero(); error DurationOverflow(); error DurationUnderflow(); // --- // Constants // --- /// @dev The maximum possible duration is approximately 136 years (assuming 365 days per year). uint32 constant MAX_DURATION_VALUE = type(uint32).max; // --- // Comparison Operations // --- function lt(Duration d1, Duration d2) pure returns (bool) { return Duration.unwrap(d1) < Duration.unwrap(d2); } function lte(Duration d1, Duration d2) pure returns (bool) { return Duration.unwrap(d1) <= Duration.unwrap(d2); } function eq(Duration d1, Duration d2) pure returns (bool) { return Duration.unwrap(d1) == Duration.unwrap(d2); } function neq(Duration d1, Duration d2) pure returns (bool) { return Duration.unwrap(d1) != Duration.unwrap(d2); } function gte(Duration d1, Duration d2) pure returns (bool) { return Duration.unwrap(d1) >= Duration.unwrap(d2); } function gt(Duration d1, Duration d2) pure returns (bool) { return Duration.unwrap(d1) > Duration.unwrap(d2); } // --- // Conversion Operations // --- function toSeconds(Duration d) pure returns (uint256) { return Duration.unwrap(d); } // --- // Arithmetic Operations // --- function plus(Duration d1, Duration d2) pure returns (Duration) { unchecked { /// @dev Both `d1.toSeconds()` and `d2.toSeconds()` are <= type(uint32).max. Therefore, their /// sum is <= type(uint256).max. return Durations.from(d1.toSeconds() + d2.toSeconds()); } } function minus(Duration d1, Duration d2) pure returns (Duration) { uint256 d1Seconds = d1.toSeconds(); uint256 d2Seconds = d2.toSeconds(); if (d1Seconds < d2Seconds) { revert DurationUnderflow(); } unchecked { /// @dev Subtraction is safe because `d1Seconds` >= `d2Seconds`. /// Both `d1Seconds` and `d2Seconds` <= `type(uint32).max`, so the difference fits within `uint32`. return Duration.wrap(uint32(d1Seconds - d2Seconds)); } } // --- // Custom Operations // --- function plusSeconds(Duration d, uint256 secondsToAdd) pure returns (Duration) { return Durations.from(d.toSeconds() + secondsToAdd); } function minusSeconds(Duration d, uint256 secondsToSubtract) pure returns (Duration) { uint256 durationSeconds = d.toSeconds(); if (durationSeconds < secondsToSubtract) { revert DurationUnderflow(); } unchecked { /// @dev Subtraction is safe because `durationSeconds` >= `secondsToSubtract`. /// Both `durationSeconds` and `secondsToSubtract` <= `type(uint32).max`, /// so the difference fits within `uint32`. return Duration.wrap(uint32(durationSeconds - secondsToSubtract)); } } function dividedBy(Duration d, uint256 divisor) pure returns (Duration) { if (divisor == 0) { revert DivisionByZero(); } return Duration.wrap(uint32(d.toSeconds() / divisor)); } function multipliedBy(Duration d, uint256 multiplicand) pure returns (Duration) { return Durations.from(multiplicand * d.toSeconds()); } function addTo(Duration d, Timestamp t) pure returns (Timestamp) { unchecked { /// @dev Both `t.toSeconds()` <= `type(uint40).max` and `d.toSeconds()` <= `type(uint32).max`, so their /// sum fits within `uint256`. return Timestamps.from(t.toSeconds() + d.toSeconds()); } } // --- // Namespaced Helper Methods // --- library Durations { Duration internal constant ZERO = Duration.wrap(0); function from(uint256 durationInSeconds) internal pure returns (Duration res) { if (durationInSeconds > MAX_DURATION_VALUE) { revert DurationOverflow(); } /// @dev Casting `durationInSeconds` to `uint32` is safe as the check ensures it is less than or equal /// to `MAX_DURATION_VALUE`, which fits within the `uint32`. res = Duration.wrap(uint32(durationInSeconds)); } }
// SPDX-FileCopyrightText: 2024 Lido <[email protected]> // SPDX-License-Identifier: MIT pragma solidity 0.8.26; // --- // Type Definition // --- type Timestamp is uint40; // --- // Assign Global Operations // --- using {lt as <, lte as <=, eq as ==, neq as !=, gte as >=, gt as >} for Timestamp global; using {isZero, isNotZero, toSeconds} for Timestamp global; // --- // Errors // --- error TimestampOverflow(); // --- // Constants // --- /// @dev The maximum value for a `Timestamp`, corresponding to approximately the year 36812. uint40 constant MAX_TIMESTAMP_VALUE = type(uint40).max; // --- // Comparison Operations // --- function lt(Timestamp t1, Timestamp t2) pure returns (bool) { return Timestamp.unwrap(t1) < Timestamp.unwrap(t2); } function lte(Timestamp t1, Timestamp t2) pure returns (bool) { return Timestamp.unwrap(t1) <= Timestamp.unwrap(t2); } function eq(Timestamp t1, Timestamp t2) pure returns (bool) { return Timestamp.unwrap(t1) == Timestamp.unwrap(t2); } function neq(Timestamp t1, Timestamp t2) pure returns (bool) { return Timestamp.unwrap(t1) != Timestamp.unwrap(t2); } function gte(Timestamp t1, Timestamp t2) pure returns (bool) { return Timestamp.unwrap(t1) >= Timestamp.unwrap(t2); } function gt(Timestamp t1, Timestamp t2) pure returns (bool) { return Timestamp.unwrap(t1) > Timestamp.unwrap(t2); } // --- // Conversion Operations // --- function toSeconds(Timestamp t) pure returns (uint256) { return Timestamp.unwrap(t); } // --- // Custom Operations // --- function isZero(Timestamp t) pure returns (bool) { return Timestamp.unwrap(t) == 0; } function isNotZero(Timestamp t) pure returns (bool) { return Timestamp.unwrap(t) > 0; } // --- // Namespaced Helper Methods // --- library Timestamps { Timestamp internal constant ZERO = Timestamp.wrap(0); function from(uint256 timestampInSeconds) internal pure returns (Timestamp res) { if (timestampInSeconds > MAX_TIMESTAMP_VALUE) { revert TimestampOverflow(); } /// @dev Casting `timestampInSeconds` to `uint40` is safe as the check ensures it is less than or equal /// to `MAX_TIMESTAMP_VALUE`, which fits within the `uint40`. return Timestamp.wrap(uint40(timestampInSeconds)); } function now() internal view returns (Timestamp res) { /// @dev Skipping the check that `block.timestamp` <= `MAX_TIMESTAMP_VALUE` for gas efficiency. /// Overflow is possible only after approximately 34,000 years from the Unix epoch. res = Timestamp.wrap(uint40(block.timestamp)); } function max(Timestamp t1, Timestamp t2) internal pure returns (Timestamp) { return t1 > t2 ? t1 : t2; } }
// SPDX-FileCopyrightText: 2024 Lido <[email protected]> // SPDX-License-Identifier: MIT pragma solidity 0.8.26; interface ITiebreakerCoreCommittee { function getSealableResumeNonce(address sealable) external view returns (uint256 nonce); function scheduleProposal(uint256 proposalId) external; function sealableResume(address sealable, uint256 nonce) external; function checkProposalExists(uint256 proposalId) external view; function checkSealableIsPaused(address sealable) external view; }
// SPDX-FileCopyrightText: 2024 Lido <[email protected]> // SPDX-License-Identifier: MIT pragma solidity 0.8.26; import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; import {Duration} from "../types/Duration.sol"; import {Timestamp, Timestamps} from "../types/Timestamp.sol"; /// @title HashConsensus Contract /// @notice This contract provides a consensus mechanism based on hash voting among members /// @dev Inherits from Ownable for access control and uses EnumerableSet for member management abstract contract HashConsensus is Ownable { using EnumerableSet for EnumerableSet.AddressSet; event MemberAdded(address indexed member); event MemberRemoved(address indexed member); event QuorumSet(uint256 quorum); event HashUsed(bytes32 hash); event HashScheduled(bytes32 hash); event Voted(address indexed signer, bytes32 hash, bool support); event TimelockDurationSet(Duration timelockDuration); error DuplicatedMember(address account); error InvalidMemberAccount(address account); error AccountIsNotMember(address account); error CallerIsNotMember(address caller); error HashAlreadyUsed(bytes32 hash); error HashIsNotScheduled(bytes32 hash); error HashAlreadyScheduled(bytes32 hash); error QuorumIsNotReached(); error InvalidQuorum(); error InvalidTimelockDuration(Duration timelock); error TimelockNotPassed(); /// @notice Represents current and historical state of a hash /// @param scheduledAt The timestamp when the hash was scheduled /// @param usedAt The timestamp when the hash was used /// @param supportWhenScheduled The number of votes in support when the hash was scheduled /// @param quorumWhenScheduled The required number of votes for execution when the hash was scheduled struct HashState { Timestamp scheduledAt; Timestamp usedAt; uint256 supportWhenScheduled; uint256 quorumWhenScheduled; } uint256 private _quorum; Duration private _timelockDuration; mapping(bytes32 hash => HashState state) private _hashStates; EnumerableSet.AddressSet private _members; mapping(address signer => mapping(bytes32 hash => bool approve)) public approves; constructor(address owner, Duration timelock) Ownable(owner) { _timelockDuration = timelock; emit TimelockDurationSet(timelock); } /// @notice Gets the list of committee members /// @dev Public function to return the list of members /// @return An array of addresses representing the committee members function getMembers() external view returns (address[] memory) { return _members.values(); } /// @notice Adds new members to the contract and sets the execution quorum. /// @dev This function allows the contract owner to add multiple new members and set the execution quorum. /// The function reverts if the caller is not the owner, if the execution quorum is set to zero, /// or if it exceeds the total number of members. /// @param newMembers The array of addresses to be added as new members /// @param executionQuorum The minimum number of members required for executing certain operations function addMembers(address[] memory newMembers, uint256 executionQuorum) external { _checkOwner(); _addMembers(newMembers, executionQuorum); } /// @notice Removes specified members from the contract and updates the execution quorum. /// @dev This function can only be called by the contract owner. It removes multiple members from /// the contract. If any of the specified members are not found in the members list, the /// function will revert. The quorum is also updated and must not be zero or greater than /// the new total number of members. /// @param membersToRemove The array of addresses to be removed from the members list. /// @param executionQuorum The updated minimum number of members required for executing certain operations. function removeMembers(address[] memory membersToRemove, uint256 executionQuorum) external { _checkOwner(); _removeMembers(membersToRemove, executionQuorum); } /// @notice Checks if an address is a member of the committee /// @dev Public function to check membership status /// @param member The address to check /// @return A boolean indicating whether the address is a member function isMember(address member) external view returns (bool) { return _members.contains(member); } /// @notice Gets the timelock duration value function getTimelockDuration() external view returns (Duration) { return _timelockDuration; } /// @notice Sets the timelock duration /// @dev Only callable by the owner /// @param newTimelock The new timelock duration in seconds function setTimelockDuration(Duration newTimelock) external { _checkOwner(); if (newTimelock == _timelockDuration) { revert InvalidTimelockDuration(newTimelock); } _timelockDuration = newTimelock; emit TimelockDurationSet(newTimelock); } /// @notice Gets the quorum value function getQuorum() external view returns (uint256) { return _quorum; } /// @notice Sets the quorum value /// @dev Only callable by the owner /// @param newQuorum The new quorum value function setQuorum(uint256 newQuorum) external { _checkOwner(); if (newQuorum == _quorum) { revert InvalidQuorum(); } _setQuorum(newQuorum); } /// @notice Schedules a proposal for execution if quorum is reached and it has not been scheduled yet. /// @dev This function schedules a proposal for execution if the quorum is reached and /// the proposal has not been scheduled yet. Could happen when execution quorum was set to the same value as /// current support of the proposal. /// @param hash The hash of the proposal to be scheduled function schedule(bytes32 hash) external { HashState storage state = _hashStates[hash]; if (state.scheduledAt.isNotZero()) { revert HashAlreadyScheduled(hash); } uint256 currentQuorum = _quorum; if (currentQuorum == 0) { revert InvalidQuorum(); } uint256 currentSupport = _getSupport(hash); if (currentSupport < currentQuorum) { revert QuorumIsNotReached(); } state.scheduledAt = Timestamps.now(); state.supportWhenScheduled = currentSupport; state.quorumWhenScheduled = currentQuorum; emit HashScheduled(hash); } /// @notice Casts a vote on a given hash if hash has not been used /// @dev Only callable by members /// @param hash The hash to vote on /// @param support Indicates whether the member supports the hash function _vote(bytes32 hash, bool support) internal { HashState storage state = _hashStates[hash]; if (state.scheduledAt.isNotZero()) { revert HashAlreadyScheduled(hash); } approves[msg.sender][hash] = support; emit Voted(msg.sender, hash, support); uint256 currentSupport = _getSupport(hash); uint256 currentQuorum = _quorum; if (currentSupport >= currentQuorum) { state.scheduledAt = Timestamps.now(); state.supportWhenScheduled = currentSupport; state.quorumWhenScheduled = currentQuorum; emit HashScheduled(hash); } } /// @notice Marks a hash as used if quorum is reached and timelock has passed /// @dev Internal function that handles marking a hash as used /// @param hash The hash to mark as used function _markUsed(bytes32 hash) internal { if (_hashStates[hash].scheduledAt.isZero()) { revert HashIsNotScheduled(hash); } if (_hashStates[hash].usedAt.isNotZero()) { revert HashAlreadyUsed(hash); } if (_timelockDuration.addTo(_hashStates[hash].scheduledAt) > Timestamps.now()) { revert TimelockNotPassed(); } _hashStates[hash].usedAt = Timestamps.now(); emit HashUsed(hash); } /// @notice Gets the state of a given hash /// @dev Internal function to retrieve the state of a hash /// @param hash The hash to get the state for /// @return support The number of votes in support of the hash /// @return executionQuorum The required number of votes for execution /// @return scheduledAt The timestamp when the quorum was reached or scheduleProposal was called /// @return isUsed Whether the hash has been used function _getHashState(bytes32 hash) internal view returns (uint256 support, uint256 executionQuorum, Timestamp scheduledAt, bool isUsed) { HashState storage hashState = _hashStates[hash]; scheduledAt = hashState.scheduledAt; isUsed = hashState.usedAt.isNotZero(); if (scheduledAt.isZero()) { support = _getSupport(hash); executionQuorum = _quorum; } else { support = hashState.supportWhenScheduled; executionQuorum = hashState.quorumWhenScheduled; } } /// @notice Sets the execution quorum required for certain operations. /// @dev The quorum value must be greater than zero and not exceed the current number of members. /// @param executionQuorum The new quorum value to be set. function _setQuorum(uint256 executionQuorum) internal { if (executionQuorum == 0 || executionQuorum > _members.length()) { revert InvalidQuorum(); } if (executionQuorum != _quorum) { _quorum = executionQuorum; emit QuorumSet(executionQuorum); } } /// @notice Adds new members to the contract and sets the execution quorum. /// @dev This internal function adds multiple new members and sets the execution quorum. /// The function reverts if the execution quorum is set to zero or exceeds the total number of members. /// @param newMembers The array of addresses to be added as new members. /// @param executionQuorum The minimum number of members required for executing certain operations. function _addMembers(address[] memory newMembers, uint256 executionQuorum) internal { uint256 membersCount = newMembers.length; for (uint256 i = 0; i < membersCount; ++i) { if (newMembers[i] == address(0)) { revert InvalidMemberAccount(newMembers[i]); } if (!_members.add(newMembers[i])) { revert DuplicatedMember(newMembers[i]); } emit MemberAdded(newMembers[i]); } _setQuorum(executionQuorum); } /// @notice Removes specified members from the contract and updates the execution quorum. /// @dev This internal function removes multiple members from the contract. If any of the specified members are not /// found in the members list, the function will revert. The quorum is also updated and must not be zero or /// greater than the new total number of members. /// @param membersToRemove The array of addresses to be removed from the members list. /// @param executionQuorum The updated minimum number of members required for executing certain operations. function _removeMembers(address[] memory membersToRemove, uint256 executionQuorum) internal { uint256 membersCount = membersToRemove.length; for (uint256 i = 0; i < membersCount; ++i) { if (!_members.remove(membersToRemove[i])) { revert AccountIsNotMember(membersToRemove[i]); } emit MemberRemoved(membersToRemove[i]); } _setQuorum(executionQuorum); } /// @notice Gets the number of votes in support of a given hash /// @dev Internal function to count the votes in support of a hash /// @param hash The hash to check /// @return support The number of votes in support of the hash function _getSupport(bytes32 hash) internal view returns (uint256 support) { uint256 membersCount = _members.length(); for (uint256 i = 0; i < membersCount; ++i) { if (approves[_members.at(i)][hash]) { support++; } } } /// @notice Restricts access to only committee members /// @dev Reverts if the sender is not a member function _checkCallerIsMember() internal view { if (!_members.contains(msg.sender)) { revert CallerIsNotMember(msg.sender); } } }
// SPDX-FileCopyrightText: 2024 Lido <[email protected]> // SPDX-License-Identifier: MIT pragma solidity 0.8.26; import {EnumerableProposals, Proposal} from "../libraries/EnumerableProposals.sol"; /// @title Proposals List Contract /// @notice This contract manages a list of proposals using an enumerable map /// @dev Uses the EnumerableProposals library for managing proposals contract ProposalsList { using EnumerableProposals for EnumerableProposals.Bytes32ToProposalMap; EnumerableProposals.Bytes32ToProposalMap internal _proposals; /// @notice Retrieves a list of proposals with pagination /// @dev Fetches an ordered list of proposals based on the offset and limit /// @param offset The starting index for the list of proposals /// @param limit The maximum number of proposals to return /// @return proposals An array of Proposal structs function getProposals(uint256 offset, uint256 limit) external view returns (Proposal[] memory proposals) { bytes32[] memory keys = _proposals.getOrderedKeys(offset, limit); uint256 length = keys.length; proposals = new Proposal[](length); for (uint256 i = 0; i < length; ++i) { proposals[i] = _proposals.get(keys[i]); } } /// @notice Retrieves a proposal at a specific index /// @dev Fetches the proposal located at the specified index in the map /// @param index The index of the proposal to retrieve /// @return The Proposal struct at the given index function getProposalAt(uint256 index) external view returns (Proposal memory) { return _proposals.at(index); } /// @notice Retrieves a proposal by its key /// @dev Fetches the proposal associated with the given key /// @param key The key of the proposal to retrieve /// @return The Proposal struct associated with the given key function getProposal(bytes32 key) external view returns (Proposal memory) { return _proposals.get(key); } /// @notice Retrieves the total number of proposals /// @dev Fetches the length of the proposals map /// @return The total number of proposals function getProposalsLength() external view returns (uint256) { return _proposals.length(); } /// @notice Retrieves an ordered list of proposal keys with pagination /// @dev Fetches the keys of the proposals based on the offset and limit /// @param offset The starting index for the list of keys /// @param limit The maximum number of keys to return /// @return An array of proposal keys function getOrderedKeys(uint256 offset, uint256 limit) external view returns (bytes32[] memory) { return _proposals.getOrderedKeys(offset, limit); } /// @notice Adds a new proposal to the list /// @dev Internal function to push a new proposal into the map /// @param key The key of the proposal /// @param proposalType The type of the proposal /// @param data The data associated with the proposal function _pushProposal(bytes32 key, uint256 proposalType, bytes memory data) internal { _proposals.push(key, proposalType, data); } }
// 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.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;
/// @solidity memory-safe-assembly
assembly {
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;
/// @solidity memory-safe-assembly
assembly {
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;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
}// SPDX-FileCopyrightText: 2024 Lido <[email protected]> // SPDX-License-Identifier: MIT pragma solidity 0.8.26; import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; import {Timestamp, Timestamps} from "../types/Timestamp.sol"; /// @notice Data structure representing a proposal. /// @param submittedAt The timestamp when the proposal was submitted. /// @param proposalType The type identifier for the proposal. /// @param data The additional data associated with the proposal. struct Proposal { Timestamp submittedAt; uint256 proposalType; bytes data; } /// @title Enumerable Proposals Library /// @notice Library to manage a set of proposals with enumerable functionality. /// @dev Uses EnumerableSet for managing the proposal keys. library EnumerableProposals { using EnumerableSet for EnumerableSet.Bytes32Set; // --- // Errors // --- error ProposalDoesNotExist(bytes32 key); error OffsetOutOfBounds(); // --- // Data Types // --- /// @notice Data structure to manage the state of the library. /// @dev Uses `EnumerableSet.Bytes32Set` to manage unique keys efficiently. /// @param _orderedKeys Array of proposal keys in the order of insertion. /// @param _keys Set of unique proposal keys for existence checks. /// @param _proposals Mapping of proposal keys to Proposal data. struct Bytes32ToProposalMap { bytes32[] _orderedKeys; EnumerableSet.Bytes32Set _keys; mapping(bytes32 key => Proposal) _proposals; } // --- // Main Functionality // --- /// @notice Adds a new proposal to the map. /// @dev Adds the proposal if it does not already exist in the map. /// @param map The map to add the proposal to. /// @param key The key of the proposal. /// @param proposalType The type of the proposal. /// @param data The data associated with the proposal. /// @return success A boolean indicating if the proposal was added successfully. function push( Bytes32ToProposalMap storage map, bytes32 key, uint256 proposalType, bytes memory data ) internal returns (bool) { if (map._keys.add(key)) { Proposal memory proposal = Proposal(Timestamps.now(), proposalType, data); map._proposals[key] = proposal; map._orderedKeys.push(key); return true; } return false; } /// @notice Checks if a proposal with the specified key exists in the map. /// @param map The map to check. /// @param key The key of the proposal. /// @return exists A boolean indicating if the proposal exists. function contains(Bytes32ToProposalMap storage map, bytes32 key) internal view returns (bool) { return map._keys.contains(key); } /// @notice Retrieves the number of proposals in the map. /// @param map The map to check. /// @return length The number of proposals in the map. function length(Bytes32ToProposalMap storage map) internal view returns (uint256) { return map._orderedKeys.length; } /// @notice Retrieves a proposal at a specified index. /// @param map The map to check. /// @param index The index to retrieve. /// @return proposal The proposal at the specified index. function at(Bytes32ToProposalMap storage map, uint256 index) internal view returns (Proposal memory) { bytes32 key = map._orderedKeys[index]; return map._proposals[key]; } /// @notice Retrieves a proposal by its unique key. /// @param map The map to check. /// @param key The key of the proposal. /// @return value The proposal associated with the given key. function get(Bytes32ToProposalMap storage map, bytes32 key) internal view returns (Proposal memory value) { if (!contains(map, key)) { revert ProposalDoesNotExist(key); } value = map._proposals[key]; } /// @notice Retrieves all proposal keys in the order they were added. /// @param map The map to check. /// @return keys An array of ordered proposal keys. function getOrderedKeys(Bytes32ToProposalMap storage map) internal view returns (bytes32[] memory) { return map._orderedKeys; } /// @notice Retrieves a subset of proposal keys using pagination. /// @dev Returns a subset of keys based on the provided offset and limit for pagination. /// @param map The map to check. /// @param offset The starting index for the subset. /// @param limit The maximum number of keys to return. /// @return keys An array of ordered keys within the specified range. function getOrderedKeys( Bytes32ToProposalMap storage map, uint256 offset, uint256 limit ) internal view returns (bytes32[] memory keys) { if (offset >= map._orderedKeys.length) { revert OffsetOutOfBounds(); } uint256 keysLength = limit; if (keysLength > map._orderedKeys.length - offset) { keysLength = map._orderedKeys.length - offset; } keys = new bytes32[](keysLength); for (uint256 i = 0; i < keysLength; ++i) { keys[i] = map._orderedKeys[offset + i]; } } }
// 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;
}
}{
"remappings": [
"@openzeppelin/=lib/openzeppelin-contracts/",
"ds-test/=lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/src/",
"erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
"eth-gas-reporter/=node_modules/eth-gas-reporter/",
"forge-std/=lib/forge-std/src/",
"hardhat/=node_modules/hardhat/",
"kontrol-cheatcodes/=lib/kontrol-cheatcodes/src/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "cancun",
"viaIR": false,
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address[]","name":"committeeMembers","type":"address[]"},{"internalType":"uint256","name":"executionQuorum","type":"uint256"},{"internalType":"address","name":"tiebreakerCoreCommittee","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AccountIsNotMember","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"}],"name":"CallerIsNotMember","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"DuplicatedMember","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[{"internalType":"bytes32","name":"hash","type":"bytes32"}],"name":"HashAlreadyScheduled","type":"error"},{"inputs":[{"internalType":"bytes32","name":"hash","type":"bytes32"}],"name":"HashAlreadyUsed","type":"error"},{"inputs":[{"internalType":"bytes32","name":"hash","type":"bytes32"}],"name":"HashIsNotScheduled","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"InvalidMemberAccount","type":"error"},{"inputs":[],"name":"InvalidQuorum","type":"error"},{"inputs":[{"internalType":"Duration","name":"timelock","type":"uint32"}],"name":"InvalidTimelockDuration","type":"error"},{"inputs":[],"name":"OffsetOutOfBounds","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":[{"internalType":"bytes32","name":"key","type":"bytes32"}],"name":"ProposalDoesNotExist","type":"error"},{"inputs":[],"name":"QuorumIsNotReached","type":"error"},{"inputs":[],"name":"TimelockNotPassed","type":"error"},{"inputs":[],"name":"TimestampOverflow","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"hash","type":"bytes32"}],"name":"HashScheduled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"hash","type":"bytes32"}],"name":"HashUsed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"member","type":"address"}],"name":"MemberAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"member","type":"address"}],"name":"MemberRemoved","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":false,"internalType":"uint256","name":"quorum","type":"uint256"}],"name":"QuorumSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"Duration","name":"timelockDuration","type":"uint32"}],"name":"TimelockDurationSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"signer","type":"address"},{"indexed":false,"internalType":"bytes32","name":"hash","type":"bytes32"},{"indexed":false,"internalType":"bool","name":"support","type":"bool"}],"name":"Voted","type":"event"},{"inputs":[],"name":"TIEBREAKER_CORE_COMMITTEE","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"newMembers","type":"address[]"},{"internalType":"uint256","name":"executionQuorum","type":"uint256"}],"name":"addMembers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"signer","type":"address"},{"internalType":"bytes32","name":"hash","type":"bytes32"}],"name":"approves","outputs":[{"internalType":"bool","name":"approve","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"proposalId","type":"uint256"}],"name":"executeScheduleProposal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sealable","type":"address"}],"name":"executeSealableResume","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getMembers","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"offset","type":"uint256"},{"internalType":"uint256","name":"limit","type":"uint256"}],"name":"getOrderedKeys","outputs":[{"internalType":"bytes32[]","name":"","type":"bytes32[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"key","type":"bytes32"}],"name":"getProposal","outputs":[{"components":[{"internalType":"Timestamp","name":"submittedAt","type":"uint40"},{"internalType":"uint256","name":"proposalType","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct Proposal","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getProposalAt","outputs":[{"components":[{"internalType":"Timestamp","name":"submittedAt","type":"uint40"},{"internalType":"uint256","name":"proposalType","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct Proposal","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"offset","type":"uint256"},{"internalType":"uint256","name":"limit","type":"uint256"}],"name":"getProposals","outputs":[{"components":[{"internalType":"Timestamp","name":"submittedAt","type":"uint40"},{"internalType":"uint256","name":"proposalType","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct Proposal[]","name":"proposals","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getProposalsLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getQuorum","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"proposalId","type":"uint256"}],"name":"getScheduleProposalState","outputs":[{"internalType":"uint256","name":"support","type":"uint256"},{"internalType":"uint256","name":"executionQuorum","type":"uint256"},{"internalType":"Timestamp","name":"quorumAt","type":"uint40"},{"internalType":"bool","name":"isExecuted","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"sealable","type":"address"}],"name":"getSealableResumeState","outputs":[{"internalType":"uint256","name":"support","type":"uint256"},{"internalType":"uint256","name":"executionQuorum","type":"uint256"},{"internalType":"Timestamp","name":"quorumAt","type":"uint40"},{"internalType":"bool","name":"isExecuted","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTimelockDuration","outputs":[{"internalType":"Duration","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"member","type":"address"}],"name":"isMember","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"membersToRemove","type":"address[]"},{"internalType":"uint256","name":"executionQuorum","type":"uint256"}],"name":"removeMembers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"hash","type":"bytes32"}],"name":"schedule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"proposalId","type":"uint256"}],"name":"scheduleProposal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sealable","type":"address"}],"name":"sealableResume","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newQuorum","type":"uint256"}],"name":"setQuorum","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"Duration","name":"newTimelock","type":"uint32"}],"name":"setTimelockDuration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
60a060405234801561000f575f80fd5b5060405161231438038061231483398101604081905261002e91610399565b835f816001600160a01b03811661005f57604051631e4fbdf760e01b81525f60048201526024015b60405180910390fd5b610068816100d6565b506002805463ffffffff191663ffffffff83169081179091556040519081527f2607ecb03bc646643f6e6a7818db8d53cf9022e79f212f0275ab0e726ffb97de9060200160405180910390a150506001600160a01b0381166080526100cd8383610125565b505050506104a5565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b81515f5b81811015610271575f6001600160a01b031684828151811061014d5761014d610491565b60200260200101516001600160a01b0316036101a65783818151811061017557610175610491565b60200260200101516040516304d078d160e31b815260040161005691906001600160a01b0391909116815260200190565b6101d38482815181106101bb576101bb610491565b6020026020010151600461028060201b90919060201c565b61021a578381815181106101e9576101e9610491565b6020026020010151604051636c630b0960e11b815260040161005691906001600160a01b0391909116815260200190565b83818151811061022c5761022c610491565b60200260200101516001600160a01b03167fb251eb052afc73ffd02ffe85ad79990a8b3fed60d76dbc2fa2fdd7123dffd91460405160405180910390a2600101610129565b5061027b8261029d565b505050565b5f610294836001600160a01b038416610315565b90505b92915050565b8015806102b257506102af6004610361565b81115b156102d05760405163d173577960e01b815260040160405180910390fd5b60015481146103125760018190556040518181527f339b520f8e0a4be8c081fee9338c96ea4c139210fac8019decca1146a637a9b79060200160405180910390a15b50565b5f81815260018301602052604081205461035a57508154600181810184555f848152602080822090930184905584548482528286019093526040902091909155610297565b505f610297565b5f610297825490565b80516001600160a01b0381168114610380575f80fd5b919050565b634e487b7160e01b5f52604160045260245ffd5b5f805f80608085870312156103ac575f80fd5b6103b58561036a565b60208601519094506001600160401b038111156103d0575f80fd5b8501601f810187136103e0575f80fd5b80516001600160401b038111156103f9576103f9610385565b604051600582901b90603f8201601f191681016001600160401b038111828210171561042757610427610385565b60405291825260208184018101929081018a841115610444575f80fd5b6020850194505b8385101561046a5761045c8561036a565b81526020948501940161044b565b506040890151909650945061048692505060608701905061036a565b905092959194509250565b634e487b7160e01b5f52603260045260245ffd5b608051611e346104e05f395f81816102250152818161040a015281816104e4015281816108270152818161094d0152610cb10152611e345ff3fe608060405234801561000f575f80fd5b506004361061016c575f3560e01c80638da5cb5b116100d9578063c26c12eb11610093578063c9f2e0d91161006e578063c9f2e0d91461039e578063df5aa6b1146103b1578063f2fde38b146103c4578063fdf2f312146103d7575f80fd5b8063c26c12eb14610363578063c99d1fdc1461036b578063c9a0e6521461038b575f80fd5b80638da5cb5b146102ef5780639eab5253146102ff578063a230c52414610314578063a698a9bc14610327578063bc378a731461033a578063c1ba4e5914610350575f80fd5b8063575c60a31161012a578063575c60a3146102205780635e3b43651461025f5780636c2d18521461027f5780636dcc1b0314610292578063715018a6146102d45780638304fc25146102dc575f80fd5b80620ad3ea146101705780630ef16633146101855780631c334548146101c75780633cdcfe3d146101e7578063430694cf146101fa578063548eac041461020d575b5f80fd5b61018361017e3660046118d6565b6103ef565b005b6101b2610193366004611908565b600660209081525f928352604080842090915290825290205460ff1681565b60405190151581526020015b60405180910390f35b6101da6101d53660046118d6565b610480565b6040516101be9190611983565b6101836101f5366004611995565b6104ac565b6101da6102083660046118d6565b61051b565b61018361021b3660046118d6565b610541565b6102477f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016101be565b61027261026d3660046119ae565b61062d565b6040516101be91906119ce565b61018361028d366004611a45565b61070e565b6102a56102a03660046118d6565b610724565b6040516101be9493929190938452602084019290925264ffffffffff1660408301521515606082015260800190565b61018361074e565b6101836102ea366004611a45565b610761565b5f546001600160a01b0316610247565b610307610773565b6040516101be9190611b18565b6101b2610322366004611995565b610784565b6102a5610335366004611995565b610790565b6103426107ab565b6040519081526020016101be565b61018361035e3660046118d6565b6107b5565b600154610342565b61037e6103793660046119ae565b6107eb565b6040516101be9190611b63565b610183610399366004611995565b610800565b6101836103ac366004611b9a565b6108a5565b6101836103bf3660046118d6565b61092f565b6101836103d2366004611995565b6109cf565b60025460405163ffffffff90911681526020016101be565b5f6103f982610a09565b91505061040581610a3f565b61047b7f000000000000000000000000000000000000000000000000000000000000000063df5aa6b160e01b8460405160240161044491815260200190565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152610b70565b505050565b60408051606080820183525f8083526020830152918101919091526104a6600783610b7d565b92915050565b5f806104b783610c8b565b92509250506104c582610a3f565b6040516001600160a01b038416602482015260448101829052610515907f000000000000000000000000000000000000000000000000000000000000000090633bced09560e11b90606401610444565b50505050565b60408051606080820183525f8083526020830152918101919091526104a6600783610d56565b5f818152600360205260409020805464ffffffffff161561057d57604051630d56196760e11b8152600481018390526024015b60405180910390fd5b6001545f8190036105a15760405163d173577960e01b815260040160405180910390fd5b5f6105ab84610e6c565b9050818110156105ce57604051630911696960e11b815260040160405180910390fd5b42835464ffffffffff191664ffffffffff9190911617835560018301819055600283018290556040518481527fcce62829585799549ad5321854f31ef4ed85ce1f765d5d892993a86380e619a69060200160405180910390a150505050565b60605f61063c60078585610edd565b80519091508067ffffffffffffffff81111561065a5761065a611a31565b6040519080825280602002602001820160405280156106a657816020015b60408051606080820183525f8083526020830152918101919091528152602001906001900390816106785790505b5092505f5b81811015610705576106e08382815181106106c8576106c8611bbd565b60200260200101516007610d5690919063ffffffff16565b8482815181106106f2576106f2611bbd565b60209081029190910101526001016106ab565b50505092915050565b610716610fc8565b6107208282610ff4565b5050565b5f805f805f61073286610a09565b91505061073e816110d5565b9450945094509450509193509193565b610756610fc8565b61075f5f61112e565b565b610769610fc8565b610720828261117d565b606061077f60046112c9565b905090565b5f6104a66004836112d5565b5f805f805f61079e86610c8b565b5091505061073e816110d5565b5f61077f60075490565b6107bd610fc8565b60015481036107df5760405163d173577960e01b815260040160405180910390fd5b6107e8816112f6565b50565b60606107f960078484610edd565b9392505050565b610808611367565b604051633872079160e21b81526001600160a01b0382811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063e1c81e44906024015f6040518083038186803b158015610867575f80fd5b505afa158015610879573d5f803e3d5ffd5b505050505f8061088883610c8b565b5091509150610898816001611391565b61047b8160015b8461149d565b6108ad610fc8565b60025463ffffffff8083169116036108e05760405163652a8a8b60e01b815263ffffffff82166004820152602401610574565b6002805463ffffffff191663ffffffff83169081179091556040519081527f2607ecb03bc646643f6e6a7818db8d53cf9022e79f212f0275ab0e726ffb97de906020015b60405180910390a150565b610937611367565b60405163e922bf3760e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063e922bf37906024015f6040518083038186803b158015610995575f80fd5b505afa1580156109a7573d5f803e3d5ffd5b505050505f806109b683610a09565b915091506109c5816001611391565b61047b815f61089f565b6109d7610fc8565b6001600160a01b038116610a0057604051631e4fbdf760e01b81525f6004820152602401610574565b6107e88161112e565b60605f8083604051602001610a1f929190611bf1565b604051602081830303815290604052915081805190602001209050915091565b5f8181526003602052604090205464ffffffffff16610a745760405163058ef8db60e01b815260048101829052602401610574565b5f8181526003602052604090205465010000000000900464ffffffffff1615610ab35760405163f2f8f56b60e01b815260048101829052602401610574565b5f81815260036020526040902054600254610af291610ae39163ffffffff9081169164ffffffffff16906114aa16565b64ffffffffff42811691161190565b15610b10576040516320800e6f60e01b815260040160405180910390fd5b5f81815260036020908152604091829020805469ffffffffff000000000019166501000000000064ffffffffff42160217905590518281527f12039fcc6a1aa7efa7a2112522b43d9cf99d165e0fc6bb8813bd7d44871e16209101610924565b60606107f983835f6114c3565b60408051606080820183525f8083526020830152918101919091525f835f018381548110610bad57610bad611bbd565b5f9182526020808320909101548083526003870182526040928390208351606081018552815464ffffffffff1681526001820154938101939093526002810180549295509293909290840191610c0290611c0c565b80601f0160208091040260200160405190810160405280929190818152602001828054610c2e90611c0c565b8015610c795780601f10610c5057610100808354040283529160200191610c79565b820191905f5260205f20905b815481529060010190602001808311610c5c57829003601f168201915b50505050508152505091505092915050565b604051638abe1e5960e01b81526001600160a01b0382811660048301526060915f9182917f000000000000000000000000000000000000000000000000000000000000000090911690638abe1e5990602401602060405180830381865afa158015610cf8573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d1c9190611c44565b905060018482604051602001610d3493929190611c5b565b6040516020818303038152906040529250828051906020012091509193909250565b60408051606080820183525f808352602083015291810191909152610d7b838361155c565b610d9b5760405163018c7aa360e51b815260048101839052602401610574565b5f8281526003840160209081526040918290208251606081018452815464ffffffffff1681526001820154928101929092526002810180549293919291840191610de490611c0c565b80601f0160208091040260200160405190810160405280929190818152602001828054610e1090611c0c565b8015610e5b5780601f10610e3257610100808354040283529160200191610e5b565b820191905f5260205f20905b815481529060010190602001808311610e3e57829003601f168201915b505050505081525050905092915050565b5f80610e78600461156a565b90505f5b81811015610ed65760065f610e92600484611573565b6001600160a01b0316815260208082019290925260409081015f90812087825290925290205460ff1615610ece5782610eca81611c97565b9350505b600101610e7c565b5050919050565b82546060908310610f01576040516309605a0160e41b815260040160405180910390fd5b83548290610f10908590611caf565b811115610f27578454610f24908590611caf565b90505b8067ffffffffffffffff811115610f4057610f40611a31565b604051908082528060200260200182016040528015610f69578160200160208202803683370190505b5091505f5b81811015610fbf5785610f818287611cc2565b81548110610f9157610f91611bbd565b905f5260205f200154838281518110610fac57610fac611bbd565b6020908102919091010152600101610f6e565b50509392505050565b5f546001600160a01b0316331461075f5760405163118cdaa760e01b8152336004820152602401610574565b81515f5b818110156110cb5761102d84828151811061101557611015611bbd565b6020026020010151600461157e90919063ffffffff16565b6110745783818151811061104357611043611bbd565b6020026020010151604051632b29ea4960e01b815260040161057491906001600160a01b0391909116815260200190565b83818151811061108657611086611bbd565b60200260200101516001600160a01b03167f6e76fb4c77256006d9c38ec7d82b45a8c8f3c27b1d6766fffc42dfb8de68449260405160405180910390a2600101610ff8565b5061047b826112f6565b5f8181526003602052604081208054829164ffffffffff8083169265010000000000900416151590826111175761110b86610e6c565b94506001549350611126565b80600101549450806002015493505b509193509193565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b81515f5b818110156110cb575f6001600160a01b03168482815181106111a5576111a5611bbd565b60200260200101516001600160a01b0316036111fe578381815181106111cd576111cd611bbd565b60200260200101516040516304d078d160e31b815260040161057491906001600160a01b0391909116815260200190565b61122b84828151811061121357611213611bbd565b6020026020010151600461159290919063ffffffff16565b6112725783818151811061124157611241611bbd565b6020026020010151604051636c630b0960e11b815260040161057491906001600160a01b0391909116815260200190565b83818151811061128457611284611bbd565b60200260200101516001600160a01b03167fb251eb052afc73ffd02ffe85ad79990a8b3fed60d76dbc2fa2fdd7123dffd91460405160405180910390a2600101611181565b60605f6107f9836115a6565b6001600160a01b0381165f90815260018301602052604081205415156107f9565b80158061130b5750611308600461156a565b81115b156113295760405163d173577960e01b815260040160405180910390fd5b60015481146107e85760018190556040518181527f339b520f8e0a4be8c081fee9338c96ea4c139210fac8019decca1146a637a9b790602001610924565b6113726004336112d5565b61075f5760405163ec4aa47360e01b8152336004820152602401610574565b5f828152600360205260409020805464ffffffffff16156113c857604051630d56196760e11b815260048101849052602401610574565b335f818152600660209081526040808320878452825291829020805460ff19168615159081179091558251878152918201527fa448f14934e131ddc08d9e2eb30b168167cdd3ef91b829718c99b539153b5222910160405180910390a25f61142f84610e6c565b6001549091508082106114965742835464ffffffffff191664ffffffffff9190911617835560018301829055600283018190556040518581527fcce62829585799549ad5321854f31ef4ed85ce1f765d5d892993a86380e619a69060200160405180910390a15b5050505050565b61051560078484846115ff565b5f6107f963ffffffff841664ffffffffff8416016116af565b6060814710156114e85760405163cd78605960e01b8152306004820152602401610574565b5f80856001600160a01b031684866040516115039190611cd5565b5f6040518083038185875af1925050503d805f811461153d576040519150601f19603f3d011682016040523d82523d5f602084013e611542565b606091505b50915091506115528683836116da565b9695505050505050565b5f6107f96001840183611736565b5f6104a6825490565b5f6107f9838361174d565b5f6107f9836001600160a01b038416611773565b5f6107f9836001600160a01b038416611856565b6060815f018054806020026020016040519081016040528092919081815260200182805480156115f357602002820191905f5260205f20905b8154815260200190600101908083116115df575b50505050509050919050565b5f61160d60018601856118a2565b156116a4575f60405180606001604052806116254290565b64ffffffffff9081168252602080830188905260409283018790525f89815260038b0182528390208451815464ffffffffff19169316929092178255830151600182015590820151919250829160028201906116819082611d2f565b50508654600181810189555f8981526020902090910187905592506116a7915050565b505f5b949350505050565b5f64ffffffffff8211156116d65760405163549a019760e01b815260040160405180910390fd5b5090565b6060826116ef576116ea826118ad565b6107f9565b815115801561170657506001600160a01b0384163b155b1561172f57604051639996b31560e01b81526001600160a01b0385166004820152602401610574565b50806107f9565b5f81815260018301602052604081205415156107f9565b5f825f01828154811061176257611762611bbd565b905f5260205f200154905092915050565b5f818152600183016020526040812054801561184d575f611795600183611caf565b85549091505f906117a890600190611caf565b9050808214611807575f865f0182815481106117c6576117c6611bbd565b905f5260205f200154905080875f0184815481106117e6576117e6611bbd565b5f918252602080832090910192909255918252600188019052604090208390555b855486908061181857611818611dea565b600190038181905f5260205f20015f90559055856001015f8681526020019081526020015f205f9055600193505050506104a6565b5f9150506104a6565b5f81815260018301602052604081205461189b57508154600181810184555f8481526020808220909301849055845484825282860190935260409020919091556104a6565b505f6104a6565b5f6107f98383611856565b8051156118bd5780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b5f602082840312156118e6575f80fd5b5035919050565b80356001600160a01b0381168114611903575f80fd5b919050565b5f8060408385031215611919575f80fd5b611922836118ed565b946020939093013593505050565b64ffffffffff8151168252602081015160208301525f60408201516060604085015280518060608601528060208301608087015e5f608082870101526080601f19601f8301168601019250505092915050565b602081525f6107f96020830184611930565b5f602082840312156119a5575f80fd5b6107f9826118ed565b5f80604083850312156119bf575f80fd5b50508035926020909101359150565b5f602082016020835280845180835260408501915060408160051b8601019250602086015f5b82811015611a2557603f19878603018452611a10858351611930565b945060209384019391909101906001016119f4565b50929695505050505050565b634e487b7160e01b5f52604160045260245ffd5b5f8060408385031215611a56575f80fd5b823567ffffffffffffffff811115611a6c575f80fd5b8301601f81018513611a7c575f80fd5b803567ffffffffffffffff811115611a9657611a96611a31565b8060051b604051601f19603f830116810181811067ffffffffffffffff82111715611ac357611ac3611a31565b604052918252602081840181019290810188841115611ae0575f80fd5b6020850194505b83851015611b0657611af8856118ed565b815260209485019401611ae7565b50976020969096013596505050505050565b602080825282518282018190525f918401906040840190835b81811015611b585783516001600160a01b0316835260209384019390920191600101611b31565b509095945050505050565b602080825282518282018190525f918401906040840190835b81811015611b58578351835260209384019390920191600101611b7c565b5f60208284031215611baa575f80fd5b813563ffffffff811681146107f9575f80fd5b634e487b7160e01b5f52603260045260245ffd5b60028110611bed57634e487b7160e01b5f52602160045260245ffd5b9052565b60408101611bff8285611bd1565b8260208301529392505050565b600181811c90821680611c2057607f821691505b602082108103611c3e57634e487b7160e01b5f52602260045260245ffd5b50919050565b5f60208284031215611c54575f80fd5b5051919050565b60608101611c698286611bd1565b6001600160a01b0393909316602082015260400152919050565b634e487b7160e01b5f52601160045260245ffd5b5f60018201611ca857611ca8611c83565b5060010190565b818103818111156104a6576104a6611c83565b808201808211156104a6576104a6611c83565b5f82518060208501845e5f920191825250919050565b601f82111561047b57805f5260205f20601f840160051c81016020851015611d105750805b601f840160051c820191505b81811015611496575f8155600101611d1c565b815167ffffffffffffffff811115611d4957611d49611a31565b611d5d81611d578454611c0c565b84611ceb565b6020601f821160018114611d8f575f8315611d785750848201515b5f19600385901b1c1916600184901b178455611496565b5f84815260208120601f198516915b82811015611dbe5787850151825560209485019460019092019101611d9e565b5084821015611ddb57868401515f19600387901b60f8161c191681555b50505050600190811b01905550565b634e487b7160e01b5f52603160045260245ffdfea264697066735822122055d3bbb7e6cc1c7a6208ab52b31d6ba65fece06a9d3fc73de676e6c08cbcfd0b64736f6c634300081a003300000000000000000000000023e0b465633ff5178808f4a75186e2f2f953702100000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000003000000000000000000000000175742c3ddd88b0192df3ecf98f180a79cb259d0000000000000000000000000000000000000000000000000000000000000000500000000000000000000000080b2d9fa613c35ec52b0da5d84e6a819bcc5e369000000000000000000000000ec7abf73f339361ecca951e1746c90a3e6205bfc000000000000000000000000b04b6fb471e766d7f21a6aa0e4e25b2aea0a75ab00000000000000000000000060bda95a40d5536303bfcf84d679ca461a23398d0000000000000000000000005d60f5d653cc318d1f0abacd83ed4feeaa6e5804
Deployed Bytecode
0x608060405234801561000f575f80fd5b506004361061016c575f3560e01c80638da5cb5b116100d9578063c26c12eb11610093578063c9f2e0d91161006e578063c9f2e0d91461039e578063df5aa6b1146103b1578063f2fde38b146103c4578063fdf2f312146103d7575f80fd5b8063c26c12eb14610363578063c99d1fdc1461036b578063c9a0e6521461038b575f80fd5b80638da5cb5b146102ef5780639eab5253146102ff578063a230c52414610314578063a698a9bc14610327578063bc378a731461033a578063c1ba4e5914610350575f80fd5b8063575c60a31161012a578063575c60a3146102205780635e3b43651461025f5780636c2d18521461027f5780636dcc1b0314610292578063715018a6146102d45780638304fc25146102dc575f80fd5b80620ad3ea146101705780630ef16633146101855780631c334548146101c75780633cdcfe3d146101e7578063430694cf146101fa578063548eac041461020d575b5f80fd5b61018361017e3660046118d6565b6103ef565b005b6101b2610193366004611908565b600660209081525f928352604080842090915290825290205460ff1681565b60405190151581526020015b60405180910390f35b6101da6101d53660046118d6565b610480565b6040516101be9190611983565b6101836101f5366004611995565b6104ac565b6101da6102083660046118d6565b61051b565b61018361021b3660046118d6565b610541565b6102477f000000000000000000000000175742c3ddd88b0192df3ecf98f180a79cb259d081565b6040516001600160a01b0390911681526020016101be565b61027261026d3660046119ae565b61062d565b6040516101be91906119ce565b61018361028d366004611a45565b61070e565b6102a56102a03660046118d6565b610724565b6040516101be9493929190938452602084019290925264ffffffffff1660408301521515606082015260800190565b61018361074e565b6101836102ea366004611a45565b610761565b5f546001600160a01b0316610247565b610307610773565b6040516101be9190611b18565b6101b2610322366004611995565b610784565b6102a5610335366004611995565b610790565b6103426107ab565b6040519081526020016101be565b61018361035e3660046118d6565b6107b5565b600154610342565b61037e6103793660046119ae565b6107eb565b6040516101be9190611b63565b610183610399366004611995565b610800565b6101836103ac366004611b9a565b6108a5565b6101836103bf3660046118d6565b61092f565b6101836103d2366004611995565b6109cf565b60025460405163ffffffff90911681526020016101be565b5f6103f982610a09565b91505061040581610a3f565b61047b7f000000000000000000000000175742c3ddd88b0192df3ecf98f180a79cb259d063df5aa6b160e01b8460405160240161044491815260200190565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152610b70565b505050565b60408051606080820183525f8083526020830152918101919091526104a6600783610b7d565b92915050565b5f806104b783610c8b565b92509250506104c582610a3f565b6040516001600160a01b038416602482015260448101829052610515907f000000000000000000000000175742c3ddd88b0192df3ecf98f180a79cb259d090633bced09560e11b90606401610444565b50505050565b60408051606080820183525f8083526020830152918101919091526104a6600783610d56565b5f818152600360205260409020805464ffffffffff161561057d57604051630d56196760e11b8152600481018390526024015b60405180910390fd5b6001545f8190036105a15760405163d173577960e01b815260040160405180910390fd5b5f6105ab84610e6c565b9050818110156105ce57604051630911696960e11b815260040160405180910390fd5b42835464ffffffffff191664ffffffffff9190911617835560018301819055600283018290556040518481527fcce62829585799549ad5321854f31ef4ed85ce1f765d5d892993a86380e619a69060200160405180910390a150505050565b60605f61063c60078585610edd565b80519091508067ffffffffffffffff81111561065a5761065a611a31565b6040519080825280602002602001820160405280156106a657816020015b60408051606080820183525f8083526020830152918101919091528152602001906001900390816106785790505b5092505f5b81811015610705576106e08382815181106106c8576106c8611bbd565b60200260200101516007610d5690919063ffffffff16565b8482815181106106f2576106f2611bbd565b60209081029190910101526001016106ab565b50505092915050565b610716610fc8565b6107208282610ff4565b5050565b5f805f805f61073286610a09565b91505061073e816110d5565b9450945094509450509193509193565b610756610fc8565b61075f5f61112e565b565b610769610fc8565b610720828261117d565b606061077f60046112c9565b905090565b5f6104a66004836112d5565b5f805f805f61079e86610c8b565b5091505061073e816110d5565b5f61077f60075490565b6107bd610fc8565b60015481036107df5760405163d173577960e01b815260040160405180910390fd5b6107e8816112f6565b50565b60606107f960078484610edd565b9392505050565b610808611367565b604051633872079160e21b81526001600160a01b0382811660048301527f000000000000000000000000175742c3ddd88b0192df3ecf98f180a79cb259d0169063e1c81e44906024015f6040518083038186803b158015610867575f80fd5b505afa158015610879573d5f803e3d5ffd5b505050505f8061088883610c8b565b5091509150610898816001611391565b61047b8160015b8461149d565b6108ad610fc8565b60025463ffffffff8083169116036108e05760405163652a8a8b60e01b815263ffffffff82166004820152602401610574565b6002805463ffffffff191663ffffffff83169081179091556040519081527f2607ecb03bc646643f6e6a7818db8d53cf9022e79f212f0275ab0e726ffb97de906020015b60405180910390a150565b610937611367565b60405163e922bf3760e01b8152600481018290527f000000000000000000000000175742c3ddd88b0192df3ecf98f180a79cb259d06001600160a01b03169063e922bf37906024015f6040518083038186803b158015610995575f80fd5b505afa1580156109a7573d5f803e3d5ffd5b505050505f806109b683610a09565b915091506109c5816001611391565b61047b815f61089f565b6109d7610fc8565b6001600160a01b038116610a0057604051631e4fbdf760e01b81525f6004820152602401610574565b6107e88161112e565b60605f8083604051602001610a1f929190611bf1565b604051602081830303815290604052915081805190602001209050915091565b5f8181526003602052604090205464ffffffffff16610a745760405163058ef8db60e01b815260048101829052602401610574565b5f8181526003602052604090205465010000000000900464ffffffffff1615610ab35760405163f2f8f56b60e01b815260048101829052602401610574565b5f81815260036020526040902054600254610af291610ae39163ffffffff9081169164ffffffffff16906114aa16565b64ffffffffff42811691161190565b15610b10576040516320800e6f60e01b815260040160405180910390fd5b5f81815260036020908152604091829020805469ffffffffff000000000019166501000000000064ffffffffff42160217905590518281527f12039fcc6a1aa7efa7a2112522b43d9cf99d165e0fc6bb8813bd7d44871e16209101610924565b60606107f983835f6114c3565b60408051606080820183525f8083526020830152918101919091525f835f018381548110610bad57610bad611bbd565b5f9182526020808320909101548083526003870182526040928390208351606081018552815464ffffffffff1681526001820154938101939093526002810180549295509293909290840191610c0290611c0c565b80601f0160208091040260200160405190810160405280929190818152602001828054610c2e90611c0c565b8015610c795780601f10610c5057610100808354040283529160200191610c79565b820191905f5260205f20905b815481529060010190602001808311610c5c57829003601f168201915b50505050508152505091505092915050565b604051638abe1e5960e01b81526001600160a01b0382811660048301526060915f9182917f000000000000000000000000175742c3ddd88b0192df3ecf98f180a79cb259d090911690638abe1e5990602401602060405180830381865afa158015610cf8573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d1c9190611c44565b905060018482604051602001610d3493929190611c5b565b6040516020818303038152906040529250828051906020012091509193909250565b60408051606080820183525f808352602083015291810191909152610d7b838361155c565b610d9b5760405163018c7aa360e51b815260048101839052602401610574565b5f8281526003840160209081526040918290208251606081018452815464ffffffffff1681526001820154928101929092526002810180549293919291840191610de490611c0c565b80601f0160208091040260200160405190810160405280929190818152602001828054610e1090611c0c565b8015610e5b5780601f10610e3257610100808354040283529160200191610e5b565b820191905f5260205f20905b815481529060010190602001808311610e3e57829003601f168201915b505050505081525050905092915050565b5f80610e78600461156a565b90505f5b81811015610ed65760065f610e92600484611573565b6001600160a01b0316815260208082019290925260409081015f90812087825290925290205460ff1615610ece5782610eca81611c97565b9350505b600101610e7c565b5050919050565b82546060908310610f01576040516309605a0160e41b815260040160405180910390fd5b83548290610f10908590611caf565b811115610f27578454610f24908590611caf565b90505b8067ffffffffffffffff811115610f4057610f40611a31565b604051908082528060200260200182016040528015610f69578160200160208202803683370190505b5091505f5b81811015610fbf5785610f818287611cc2565b81548110610f9157610f91611bbd565b905f5260205f200154838281518110610fac57610fac611bbd565b6020908102919091010152600101610f6e565b50509392505050565b5f546001600160a01b0316331461075f5760405163118cdaa760e01b8152336004820152602401610574565b81515f5b818110156110cb5761102d84828151811061101557611015611bbd565b6020026020010151600461157e90919063ffffffff16565b6110745783818151811061104357611043611bbd565b6020026020010151604051632b29ea4960e01b815260040161057491906001600160a01b0391909116815260200190565b83818151811061108657611086611bbd565b60200260200101516001600160a01b03167f6e76fb4c77256006d9c38ec7d82b45a8c8f3c27b1d6766fffc42dfb8de68449260405160405180910390a2600101610ff8565b5061047b826112f6565b5f8181526003602052604081208054829164ffffffffff8083169265010000000000900416151590826111175761110b86610e6c565b94506001549350611126565b80600101549450806002015493505b509193509193565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b81515f5b818110156110cb575f6001600160a01b03168482815181106111a5576111a5611bbd565b60200260200101516001600160a01b0316036111fe578381815181106111cd576111cd611bbd565b60200260200101516040516304d078d160e31b815260040161057491906001600160a01b0391909116815260200190565b61122b84828151811061121357611213611bbd565b6020026020010151600461159290919063ffffffff16565b6112725783818151811061124157611241611bbd565b6020026020010151604051636c630b0960e11b815260040161057491906001600160a01b0391909116815260200190565b83818151811061128457611284611bbd565b60200260200101516001600160a01b03167fb251eb052afc73ffd02ffe85ad79990a8b3fed60d76dbc2fa2fdd7123dffd91460405160405180910390a2600101611181565b60605f6107f9836115a6565b6001600160a01b0381165f90815260018301602052604081205415156107f9565b80158061130b5750611308600461156a565b81115b156113295760405163d173577960e01b815260040160405180910390fd5b60015481146107e85760018190556040518181527f339b520f8e0a4be8c081fee9338c96ea4c139210fac8019decca1146a637a9b790602001610924565b6113726004336112d5565b61075f5760405163ec4aa47360e01b8152336004820152602401610574565b5f828152600360205260409020805464ffffffffff16156113c857604051630d56196760e11b815260048101849052602401610574565b335f818152600660209081526040808320878452825291829020805460ff19168615159081179091558251878152918201527fa448f14934e131ddc08d9e2eb30b168167cdd3ef91b829718c99b539153b5222910160405180910390a25f61142f84610e6c565b6001549091508082106114965742835464ffffffffff191664ffffffffff9190911617835560018301829055600283018190556040518581527fcce62829585799549ad5321854f31ef4ed85ce1f765d5d892993a86380e619a69060200160405180910390a15b5050505050565b61051560078484846115ff565b5f6107f963ffffffff841664ffffffffff8416016116af565b6060814710156114e85760405163cd78605960e01b8152306004820152602401610574565b5f80856001600160a01b031684866040516115039190611cd5565b5f6040518083038185875af1925050503d805f811461153d576040519150601f19603f3d011682016040523d82523d5f602084013e611542565b606091505b50915091506115528683836116da565b9695505050505050565b5f6107f96001840183611736565b5f6104a6825490565b5f6107f9838361174d565b5f6107f9836001600160a01b038416611773565b5f6107f9836001600160a01b038416611856565b6060815f018054806020026020016040519081016040528092919081815260200182805480156115f357602002820191905f5260205f20905b8154815260200190600101908083116115df575b50505050509050919050565b5f61160d60018601856118a2565b156116a4575f60405180606001604052806116254290565b64ffffffffff9081168252602080830188905260409283018790525f89815260038b0182528390208451815464ffffffffff19169316929092178255830151600182015590820151919250829160028201906116819082611d2f565b50508654600181810189555f8981526020902090910187905592506116a7915050565b505f5b949350505050565b5f64ffffffffff8211156116d65760405163549a019760e01b815260040160405180910390fd5b5090565b6060826116ef576116ea826118ad565b6107f9565b815115801561170657506001600160a01b0384163b155b1561172f57604051639996b31560e01b81526001600160a01b0385166004820152602401610574565b50806107f9565b5f81815260018301602052604081205415156107f9565b5f825f01828154811061176257611762611bbd565b905f5260205f200154905092915050565b5f818152600183016020526040812054801561184d575f611795600183611caf565b85549091505f906117a890600190611caf565b9050808214611807575f865f0182815481106117c6576117c6611bbd565b905f5260205f200154905080875f0184815481106117e6576117e6611bbd565b5f918252602080832090910192909255918252600188019052604090208390555b855486908061181857611818611dea565b600190038181905f5260205f20015f90559055856001015f8681526020019081526020015f205f9055600193505050506104a6565b5f9150506104a6565b5f81815260018301602052604081205461189b57508154600181810184555f8481526020808220909301849055845484825282860190935260409020919091556104a6565b505f6104a6565b5f6107f98383611856565b8051156118bd5780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b5f602082840312156118e6575f80fd5b5035919050565b80356001600160a01b0381168114611903575f80fd5b919050565b5f8060408385031215611919575f80fd5b611922836118ed565b946020939093013593505050565b64ffffffffff8151168252602081015160208301525f60408201516060604085015280518060608601528060208301608087015e5f608082870101526080601f19601f8301168601019250505092915050565b602081525f6107f96020830184611930565b5f602082840312156119a5575f80fd5b6107f9826118ed565b5f80604083850312156119bf575f80fd5b50508035926020909101359150565b5f602082016020835280845180835260408501915060408160051b8601019250602086015f5b82811015611a2557603f19878603018452611a10858351611930565b945060209384019391909101906001016119f4565b50929695505050505050565b634e487b7160e01b5f52604160045260245ffd5b5f8060408385031215611a56575f80fd5b823567ffffffffffffffff811115611a6c575f80fd5b8301601f81018513611a7c575f80fd5b803567ffffffffffffffff811115611a9657611a96611a31565b8060051b604051601f19603f830116810181811067ffffffffffffffff82111715611ac357611ac3611a31565b604052918252602081840181019290810188841115611ae0575f80fd5b6020850194505b83851015611b0657611af8856118ed565b815260209485019401611ae7565b50976020969096013596505050505050565b602080825282518282018190525f918401906040840190835b81811015611b585783516001600160a01b0316835260209384019390920191600101611b31565b509095945050505050565b602080825282518282018190525f918401906040840190835b81811015611b58578351835260209384019390920191600101611b7c565b5f60208284031215611baa575f80fd5b813563ffffffff811681146107f9575f80fd5b634e487b7160e01b5f52603260045260245ffd5b60028110611bed57634e487b7160e01b5f52602160045260245ffd5b9052565b60408101611bff8285611bd1565b8260208301529392505050565b600181811c90821680611c2057607f821691505b602082108103611c3e57634e487b7160e01b5f52602260045260245ffd5b50919050565b5f60208284031215611c54575f80fd5b5051919050565b60608101611c698286611bd1565b6001600160a01b0393909316602082015260400152919050565b634e487b7160e01b5f52601160045260245ffd5b5f60018201611ca857611ca8611c83565b5060010190565b818103818111156104a6576104a6611c83565b808201808211156104a6576104a6611c83565b5f82518060208501845e5f920191825250919050565b601f82111561047b57805f5260205f20601f840160051c81016020851015611d105750805b601f840160051c820191505b81811015611496575f8155600101611d1c565b815167ffffffffffffffff811115611d4957611d49611a31565b611d5d81611d578454611c0c565b84611ceb565b6020601f821160018114611d8f575f8315611d785750848201515b5f19600385901b1c1916600184901b178455611496565b5f84815260208120601f198516915b82811015611dbe5787850151825560209485019460019092019101611d9e565b5084821015611ddb57868401515f19600387901b60f8161c191681555b50505050600190811b01905550565b634e487b7160e01b5f52603160045260245ffdfea264697066735822122055d3bbb7e6cc1c7a6208ab52b31d6ba65fece06a9d3fc73de676e6c08cbcfd0b64736f6c634300081a0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000023e0b465633ff5178808f4a75186e2f2f953702100000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000003000000000000000000000000175742c3ddd88b0192df3ecf98f180a79cb259d0000000000000000000000000000000000000000000000000000000000000000500000000000000000000000080b2d9fa613c35ec52b0da5d84e6a819bcc5e369000000000000000000000000ec7abf73f339361ecca951e1746c90a3e6205bfc000000000000000000000000b04b6fb471e766d7f21a6aa0e4e25b2aea0a75ab00000000000000000000000060bda95a40d5536303bfcf84d679ca461a23398d0000000000000000000000005d60f5d653cc318d1f0abacd83ed4feeaa6e5804
-----Decoded View---------------
Arg [0] : owner (address): 0x23E0B465633FF5178808F4A75186E2F2F9537021
Arg [1] : committeeMembers (address[]): 0x80B2D9FA613c35Ec52B0dA5D84e6A819bcc5e369,0xEC7ABf73f339361ecCA951E1746C90a3e6205BFC,0xb04b6fB471E766D7F21A6AA0E4E25B2AEA0a75AB,0x60BDa95a40d5536303BFcf84D679ca461A23398d,0x5d60F5d653Cc318d1f0ABacd83eD4feeAa6e5804
Arg [2] : executionQuorum (uint256): 3
Arg [3] : tiebreakerCoreCommittee (address): 0x175742c3DDD88B0192df3EcF98f180A79cb259D0
-----Encoded View---------------
10 Constructor Arguments found :
Arg [0] : 00000000000000000000000023e0b465633ff5178808f4a75186e2f2f9537021
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000080
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000003
Arg [3] : 000000000000000000000000175742c3ddd88b0192df3ecf98f180a79cb259d0
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000005
Arg [5] : 00000000000000000000000080b2d9fa613c35ec52b0da5d84e6a819bcc5e369
Arg [6] : 000000000000000000000000ec7abf73f339361ecca951e1746c90a3e6205bfc
Arg [7] : 000000000000000000000000b04b6fb471e766d7f21a6aa0e4e25b2aea0a75ab
Arg [8] : 00000000000000000000000060bda95a40d5536303bfcf84d679ca461a23398d
Arg [9] : 0000000000000000000000005d60f5d653cc318d1f0abacd83ed4feeaa6e5804
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
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.