Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Similar Match Source Code This contract matches the deployed Bytecode of the Source Code for Contract 0xB19fe55e...30cF66DCD The constructor portion of the code might be different and could alter the actual behaviour of the contract
Contract Name:
SnapshotVotePowerModule
Compiler Version
v0.8.17+commit.8df45f5f
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
//SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {OwnableStorage} from "@synthetixio/core-contracts/contracts/ownership/OwnableStorage.sol"; import {SafeCastU256} from "@synthetixio/core-contracts/contracts/utils/SafeCast.sol"; import {ISnapshotVotePowerModule} from "../../interfaces/ISnapshotVotePowerModule.sol"; import {ISnapshotRecord} from "../../interfaces/external/ISnapshotRecord.sol"; import {Council} from "../../storage/Council.sol"; import {Epoch} from "../../storage/Epoch.sol"; import {Ballot} from "../../storage/Ballot.sol"; import {SnapshotVotePower} from "../../storage/SnapshotVotePower.sol"; import {SnapshotVotePowerEpoch} from "../../storage/SnapshotVotePowerEpoch.sol"; contract SnapshotVotePowerModule is ISnapshotVotePowerModule { using SafeCastU256 for uint256; event ScaleSet(address indexed snapshotContract, uint256 scale); event SnapshotContractSet( address indexed snapshotContract, bool indexed enabled, SnapshotVotePower.WeightType weight ); ///@notice Sets a snapshot contract to be used for voting power calculations function setSnapshotContract( address snapshotContract, SnapshotVotePower.WeightType weight, bool enabled ) external override { OwnableStorage.onlyOwner(); Council.onlyInPeriods(Epoch.ElectionPeriod.Administration, Epoch.ElectionPeriod.Nomination); SnapshotVotePower.Data storage snapshotVotePower = SnapshotVotePower.load(snapshotContract); snapshotVotePower.enabled = enabled; snapshotVotePower.weight = weight; emit SnapshotContractSet(snapshotContract, enabled, weight); } function setScale(address snapshotContract, uint256 scale) external { OwnableStorage.onlyOwner(); Council.onlyInPeriod(Epoch.ElectionPeriod.Administration); SnapshotVotePower.Data storage snapshotVotePower = SnapshotVotePower.load(snapshotContract); if (snapshotVotePower.weight != SnapshotVotePower.WeightType.Scaled) revert SnapshotVotePower.InvalidWeightType(); snapshotVotePower.scale = scale; emit ScaleSet(snapshotContract, scale); } function takeVotePowerSnapshot( address snapshotContract ) external override returns (uint128 snapshotId) { Council.onlyInPeriods(Epoch.ElectionPeriod.Nomination, Epoch.ElectionPeriod.Vote); SnapshotVotePower.Data storage snapshotVotePower = SnapshotVotePower.load(snapshotContract); uint128 electionId = Council.load().currentElectionId.to128(); if (!snapshotVotePower.enabled) { revert InvalidSnapshotContract(); } SnapshotVotePowerEpoch.Data storage snapshotVotePowerEpoch = snapshotVotePower.epochs[ electionId ]; if (snapshotVotePowerEpoch.snapshotId > 0) { revert SnapshotAlreadyTaken(snapshotVotePowerEpoch.snapshotId); } snapshotId = ISnapshotRecord(snapshotContract).currentPeriodId(); ISnapshotRecord(snapshotContract).takeSnapshot(block.timestamp.to128()); snapshotVotePowerEpoch.snapshotId = snapshotId; } function getVotePowerSnapshotId( address snapshotContract, uint128 electionId ) external view returns (uint128) { return SnapshotVotePower.load(snapshotContract).epochs[electionId].snapshotId; } /// @dev WARNING: this function is for the frontend to get the voting power of a voter, not for the contract to use function getVotingPowerForUser( address snapshotContract, address voter, uint256 periodId ) external view override returns (uint256) { uint256 snapshotAmount = ISnapshotRecord(snapshotContract).balanceOfOnPeriod( voter, periodId ); SnapshotVotePower.Data storage snapshotVotePower = SnapshotVotePower.load(snapshotContract); return SnapshotVotePower.calculateVotingPower(snapshotVotePower, snapshotAmount); } function prepareBallotWithSnapshot( address snapshotContract, address voter ) external override returns (uint256 votingPower) { Council.onlyInPeriod(Epoch.ElectionPeriod.Vote); uint128 currentEpoch = Council.load().currentElectionId.to128(); SnapshotVotePower.Data storage snapshotVotePower = SnapshotVotePower.load(snapshotContract); if (!snapshotVotePower.enabled) { revert InvalidSnapshotContract(); } SnapshotVotePowerEpoch.Data storage snapshotVotePowerEpoch = snapshotVotePower.epochs[ currentEpoch ]; if (snapshotVotePowerEpoch.snapshotId == 0) { revert SnapshotNotTaken(snapshotContract, currentEpoch); } if (snapshotVotePowerEpoch.recordedVotingPower[voter] > 0) { revert BallotAlreadyPrepared(voter, currentEpoch); } uint256 balance = ISnapshotRecord(snapshotContract).balanceOfOnPeriod( voter, snapshotVotePowerEpoch.snapshotId ); votingPower = SnapshotVotePower.calculateVotingPower(snapshotVotePower, balance); if (votingPower == 0) { revert NoPower(snapshotVotePowerEpoch.snapshotId, voter); } Ballot.Data storage ballot = Ballot.load(currentEpoch, voter, block.chainid); ballot.votingPower += votingPower; snapshotVotePowerEpoch.recordedVotingPower[voter] = votingPower; } function getPreparedBallot(address voter) external view override returns (uint256 power) { uint128 currentEpoch = Council.load().currentElectionId.to128(); Ballot.Data storage ballot = Ballot.load(currentEpoch, voter, block.chainid); return ballot.votingPower; } }
//SPDX-License-Identifier: MIT pragma solidity >=0.8.11 <0.9.0; /** * @title Library for access related errors. */ library AccessError { /** * @dev Thrown when an address tries to perform an unauthorized action. * @param addr The address that attempts the action. */ error Unauthorized(address addr); }
//SPDX-License-Identifier: MIT pragma solidity >=0.8.11 <0.9.0; import "../errors/AccessError.sol"; library OwnableStorage { bytes32 private constant _SLOT_OWNABLE_STORAGE = keccak256(abi.encode("io.synthetix.core-contracts.Ownable")); struct Data { address owner; address nominatedOwner; } function load() internal pure returns (Data storage store) { bytes32 s = _SLOT_OWNABLE_STORAGE; assembly { store.slot := s } } function onlyOwner() internal view { if (msg.sender != getOwner()) { revert AccessError.Unauthorized(msg.sender); } } function getOwner() internal view returns (address) { return OwnableStorage.load().owner; } }
//SPDX-License-Identifier: MIT pragma solidity >=0.8.11 <0.9.0; /** * Utilities that convert numeric types avoiding silent overflows. */ import "./SafeCast/SafeCastU32.sol"; import "./SafeCast/SafeCastI32.sol"; import "./SafeCast/SafeCastI24.sol"; import "./SafeCast/SafeCastU56.sol"; import "./SafeCast/SafeCastI56.sol"; import "./SafeCast/SafeCastU64.sol"; import "./SafeCast/SafeCastI64.sol"; import "./SafeCast/SafeCastI128.sol"; import "./SafeCast/SafeCastI256.sol"; import "./SafeCast/SafeCastU128.sol"; import "./SafeCast/SafeCastU160.sol"; import "./SafeCast/SafeCastU256.sol"; import "./SafeCast/SafeCastAddress.sol"; import "./SafeCast/SafeCastBytes32.sol";
//SPDX-License-Identifier: MIT pragma solidity >=0.8.11 <0.9.0; /** * @title See SafeCast.sol. */ library SafeCastAddress { function to256(address x) internal pure returns (uint256) { return uint256(uint160(x)); } function toBytes32(address x) internal pure returns (bytes32) { return bytes32(uint256(uint160(x))); } }
//SPDX-License-Identifier: MIT pragma solidity >=0.8.11 <0.9.0; /** * @title See SafeCast.sol. */ library SafeCastBytes32 { function toAddress(bytes32 x) internal pure returns (address) { return address(uint160(uint256(x))); } function toUint(bytes32 x) internal pure returns (uint) { return uint(x); } }
//SPDX-License-Identifier: MIT pragma solidity >=0.8.11 <0.9.0; /** * @title See SafeCast.sol. */ library SafeCastI128 { error OverflowInt128ToUint128(); error OverflowInt128ToInt32(); function toUint(int128 x) internal pure returns (uint128) { // ----------------<==============o==============>----------------- // ----------------xxxxxxxxxxxxxxxo===============>---------------- if (x < 0) { revert OverflowInt128ToUint128(); } return uint128(x); } function to256(int128 x) internal pure returns (int256) { return int256(x); } function to32(int128 x) internal pure returns (int32) { // ----------------<==============o==============>----------------- // ----------------xxxxxxxxxxxx<==o==>xxxxxxxxxxxx----------------- if (x < int256(type(int32).min) || x > int256(type(int32).max)) { revert OverflowInt128ToInt32(); } return int32(x); } function zero() internal pure returns (int128) { return int128(0); } }
//SPDX-License-Identifier: MIT pragma solidity >=0.8.11 <0.9.0; /** * @title See SafeCast.sol. */ library SafeCastI24 { function to256(int24 x) internal pure returns (int256) { return int256(x); } }
//SPDX-License-Identifier: MIT pragma solidity >=0.8.11 <0.9.0; /** * @title See SafeCast.sol. */ library SafeCastI256 { error OverflowInt256ToUint256(); error OverflowInt256ToInt128(); error OverflowInt256ToInt24(); function to128(int256 x) internal pure returns (int128) { // ----<==========================o===========================>---- // ----xxxxxxxxxxxx<==============o==============>xxxxxxxxxxxxx---- if (x < int256(type(int128).min) || x > int256(type(int128).max)) { revert OverflowInt256ToInt128(); } return int128(x); } function to24(int256 x) internal pure returns (int24) { // ----<==========================o===========================>---- // ----xxxxxxxxxxxxxxxxxxxx<======o=======>xxxxxxxxxxxxxxxxxxxx---- if (x < int256(type(int24).min) || x > int256(type(int24).max)) { revert OverflowInt256ToInt24(); } return int24(x); } function toUint(int256 x) internal pure returns (uint256) { // ----<==========================o===========================>---- // ----xxxxxxxxxxxxxxxxxxxxxxxxxxxo===============================> if (x < 0) { revert OverflowInt256ToUint256(); } return uint256(x); } function zero() internal pure returns (int256) { return int256(0); } }
//SPDX-License-Identifier: MIT pragma solidity >=0.8.11 <0.9.0; /** * @title See SafeCast.sol. */ library SafeCastI32 { error OverflowInt32ToUint32(); function toUint(int32 x) internal pure returns (uint32) { // ----------------------<========o========>---------------------- // ----------------------xxxxxxxxxo=========>---------------------- if (x < 0) { revert OverflowInt32ToUint32(); } return uint32(x); } }
//SPDX-License-Identifier: MIT pragma solidity >=0.8.11 <0.9.0; /** * @title See SafeCast.sol. */ library SafeCastI56 { error OverflowInt56ToInt24(); function to24(int56 x) internal pure returns (int24) { // ----------------------<========o========>----------------------- // ----------------------xxx<=====o=====>xxx----------------------- if (x < int256(type(int24).min) || x > int256(type(int24).max)) { revert OverflowInt56ToInt24(); } return int24(x); } }
//SPDX-License-Identifier: MIT pragma solidity >=0.8.11 <0.9.0; /** * @title See SafeCast.sol. */ library SafeCastI64 { error OverflowInt64ToUint64(); function toUint(int64 x) internal pure returns (uint64) { // ----------------------<========o========>---------------------- // ----------------------xxxxxxxxxo=========>---------------------- if (x < 0) { revert OverflowInt64ToUint64(); } return uint64(x); } }
//SPDX-License-Identifier: MIT pragma solidity >=0.8.11 <0.9.0; /** * @title See SafeCast.sol. */ library SafeCastU128 { error OverflowUint128ToInt128(); function to256(uint128 x) internal pure returns (uint256) { return uint256(x); } function toInt(uint128 x) internal pure returns (int128) { // -------------------------------o===============>---------------- // ----------------<==============o==============>x---------------- if (x > uint128(type(int128).max)) { revert OverflowUint128ToInt128(); } return int128(x); } function toBytes32(uint128 x) internal pure returns (bytes32) { return bytes32(uint256(x)); } }
//SPDX-License-Identifier: MIT pragma solidity >=0.8.11 <0.9.0; /** * @title See SafeCast.sol. */ library SafeCastU160 { function to256(uint160 x) internal pure returns (uint256) { return uint256(x); } }
//SPDX-License-Identifier: MIT pragma solidity >=0.8.11 <0.9.0; /** * @title See SafeCast.sol. */ library SafeCastU256 { error OverflowUint256ToUint128(); error OverflowUint256ToInt256(); error OverflowUint256ToUint64(); error OverflowUint256ToUint32(); error OverflowUint256ToUint16(); error OverflowUint256ToUint160(); function to128(uint256 x) internal pure returns (uint128) { // -------------------------------o===============================> // -------------------------------o===============>xxxxxxxxxxxxxxxx if (x > type(uint128).max) { revert OverflowUint256ToUint128(); } return uint128(x); } function to64(uint256 x) internal pure returns (uint64) { // -------------------------------o===============================> // -------------------------------o======>xxxxxxxxxxxxxxxxxxxxxxxxx if (x > type(uint64).max) { revert OverflowUint256ToUint64(); } return uint64(x); } function to32(uint256 x) internal pure returns (uint32) { // -------------------------------o===============================> // -------------------------------o===>xxxxxxxxxxxxxxxxxxxxxxxxxxxx if (x > type(uint32).max) { revert OverflowUint256ToUint32(); } return uint32(x); } function to16(uint256 x) internal pure returns (uint16) { // -------------------------------o===============================> // -------------------------------o==>xxxxxxxxxxxxxxxxxxxxxxxxxxxxx if (x > type(uint16).max) { revert OverflowUint256ToUint16(); } return uint16(x); } function to160(uint256 x) internal pure returns (uint160) { // -------------------------------o===============================> // -------------------------------o==================>xxxxxxxxxxxxx if (x > type(uint160).max) { revert OverflowUint256ToUint160(); } return uint160(x); } function toBytes32(uint256 x) internal pure returns (bytes32) { return bytes32(x); } function toInt(uint256 x) internal pure returns (int256) { // -------------------------------o===============================> // ----<==========================o===========================>xxxx if (x > uint256(type(int256).max)) { revert OverflowUint256ToInt256(); } return int256(x); } }
//SPDX-License-Identifier: MIT pragma solidity >=0.8.11 <0.9.0; /** * @title See SafeCast.sol. */ library SafeCastU32 { error OverflowUint32ToInt32(); function toInt(uint32 x) internal pure returns (int32) { // -------------------------------o=========>---------------------- // ----------------------<========o========>x---------------------- if (x > uint32(type(int32).max)) { revert OverflowUint32ToInt32(); } return int32(x); } function to256(uint32 x) internal pure returns (uint256) { return uint256(x); } function to56(uint32 x) internal pure returns (uint56) { return uint56(x); } }
//SPDX-License-Identifier: MIT pragma solidity >=0.8.11 <0.9.0; /** * @title See SafeCast.sol. */ library SafeCastU56 { error OverflowUint56ToInt56(); function toInt(uint56 x) internal pure returns (int56) { // -------------------------------o=========>---------------------- // ----------------------<========o========>x---------------------- if (x > uint56(type(int56).max)) { revert OverflowUint56ToInt56(); } return int56(x); } }
//SPDX-License-Identifier: MIT pragma solidity >=0.8.11 <0.9.0; /** * @title See SafeCast.sol. */ library SafeCastU64 { error OverflowUint64ToInt64(); function toInt(uint64 x) internal pure returns (int64) { // -------------------------------o=========>---------------------- // ----------------------<========o========>x---------------------- if (x > uint64(type(int64).max)) { revert OverflowUint64ToInt64(); } return int64(x); } function to256(uint64 x) internal pure returns (uint256) { return uint256(x); } }
//SPDX-License-Identifier: MIT pragma solidity >=0.8.11 <0.9.0; import "./SafeCast.sol"; library SetUtil { using SafeCastAddress for address; using SafeCastBytes32 for bytes32; using SafeCastU256 for uint256; // ---------------------------------------- // Uint support // ---------------------------------------- struct UintSet { Bytes32Set raw; } function add(UintSet storage set, uint256 value) internal { add(set.raw, value.toBytes32()); } function remove(UintSet storage set, uint256 value) internal { remove(set.raw, value.toBytes32()); } function replace(UintSet storage set, uint256 value, uint256 newValue) internal { replace(set.raw, value.toBytes32(), newValue.toBytes32()); } function contains(UintSet storage set, uint256 value) internal view returns (bool) { return contains(set.raw, value.toBytes32()); } function length(UintSet storage set) internal view returns (uint256) { return length(set.raw); } function valueAt(UintSet storage set, uint256 position) internal view returns (uint256) { return valueAt(set.raw, position).toUint(); } function positionOf(UintSet storage set, uint256 value) internal view returns (uint256) { return positionOf(set.raw, value.toBytes32()); } function values(UintSet storage set) internal view returns (uint256[] memory) { bytes32[] memory store = values(set.raw); uint256[] memory result; assembly { result := store } return result; } // ---------------------------------------- // Address support // ---------------------------------------- struct AddressSet { Bytes32Set raw; } function add(AddressSet storage set, address value) internal { add(set.raw, value.toBytes32()); } function remove(AddressSet storage set, address value) internal { remove(set.raw, value.toBytes32()); } function replace(AddressSet storage set, address value, address newValue) internal { replace(set.raw, value.toBytes32(), newValue.toBytes32()); } function contains(AddressSet storage set, address value) internal view returns (bool) { return contains(set.raw, value.toBytes32()); } function length(AddressSet storage set) internal view returns (uint256) { return length(set.raw); } function valueAt(AddressSet storage set, uint256 position) internal view returns (address) { return valueAt(set.raw, position).toAddress(); } function positionOf(AddressSet storage set, address value) internal view returns (uint256) { return positionOf(set.raw, value.toBytes32()); } function values(AddressSet storage set) internal view returns (address[] memory) { bytes32[] memory store = values(set.raw); address[] memory result; assembly { result := store } return result; } // ---------------------------------------- // Core bytes32 support // ---------------------------------------- error PositionOutOfBounds(); error ValueNotInSet(); error ValueAlreadyInSet(); struct Bytes32Set { bytes32[] _values; mapping(bytes32 => uint256) _positions; // Position zero is never used. } function add(Bytes32Set storage set, bytes32 value) internal { if (contains(set, value)) { revert ValueAlreadyInSet(); } set._values.push(value); set._positions[value] = set._values.length; } function remove(Bytes32Set storage set, bytes32 value) internal { uint256 position = set._positions[value]; if (position == 0) { revert ValueNotInSet(); } uint256 index = position - 1; uint256 lastIndex = set._values.length - 1; // If the element being deleted is not the last in the values, // move the last element to its position. if (index != lastIndex) { bytes32 lastValue = set._values[lastIndex]; set._values[index] = lastValue; set._positions[lastValue] = position; } // Remove the last element in the values. set._values.pop(); delete set._positions[value]; } function replace(Bytes32Set storage set, bytes32 value, bytes32 newValue) internal { if (!contains(set, value)) { revert ValueNotInSet(); } if (contains(set, newValue)) { revert ValueAlreadyInSet(); } uint256 position = set._positions[value]; delete set._positions[value]; uint256 index = position - 1; set._values[index] = newValue; set._positions[newValue] = position; } function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) { return set._positions[value] != 0; } function length(Bytes32Set storage set) internal view returns (uint256) { return set._values.length; } function valueAt(Bytes32Set storage set, uint256 position) internal view returns (bytes32) { if (position == 0 || position > set._values.length) { revert PositionOutOfBounds(); } uint256 index = position - 1; return set._values[index]; } function positionOf(Bytes32Set storage set, bytes32 value) internal view returns (uint256) { if (!contains(set, value)) { revert ValueNotInSet(); } return set._positions[value]; } function values(Bytes32Set storage set) internal view returns (bytes32[] memory) { return set._values; } }
//SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface ISnapshotRecord { function currentPeriodId() external view returns (uint128); function balanceOfOnPeriod(address account, uint256 periodId) external view returns (uint256); function totalSupplyOnPeriod(uint256 periodId) external view returns (uint256); function takeSnapshot(uint128 id) external; }
//SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {SnapshotVotePower} from "../storage/SnapshotVotePower.sol"; interface ISnapshotVotePowerModule { error SnapshotAlreadyTaken(uint128 snapshotId); error BallotAlreadyPrepared(address voter, uint256 electionId); error SnapshotNotTaken(address snapshotContract, uint128 electionId); error NoPower(uint256, address); error InvalidSnapshotContract(); function setSnapshotContract( address snapshotContract, SnapshotVotePower.WeightType weight, bool enabled ) external; function takeVotePowerSnapshot(address snapshotContract) external returns (uint128 snapshotId); function prepareBallotWithSnapshot( address snapshotContract, address voter ) external returns (uint256 votingPower); function getPreparedBallot(address voter) external view returns (uint256 power); function getVotingPowerForUser( address snapshotContract, address voter, uint256 periodId ) external view returns (uint256); }
//SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @title Ballot * @dev A single vote cast by a address/chainId combination. * * A ballot goes through a few stages: * 1. The ballot is empty and all values are 0 * 2. The user who wants to vote proves their voting power in an external function, and increases the `votingPower` field as a result * 3. Once the user has proven their voting power, they can allocate their power to a set of candidates. */ library Ballot { error InvalidBallot(); struct Data { uint256 votingPower; address[] votedCandidates; uint256[] amounts; } function load( uint256 electionId, address voter, uint256 chainId ) internal pure returns (Data storage self) { bytes32 s = keccak256( abi.encode("io.synthetix.governance.Ballot", electionId, voter, chainId) ); assembly { self.slot := s } } function hasVoted(Data storage self) internal view returns (bool) { return self.votedCandidates.length > 0; } function isValid(Data storage self) internal view returns (bool) { if (self.votedCandidates.length != self.amounts.length) { return false; } uint256 totalAmount = 0; for (uint256 i = 0; i < self.votedCandidates.length; i++) { if (self.amounts[i] == 0) { return false; } totalAmount += self.amounts[i]; } return totalAmount == 0 || totalAmount == self.votingPower; } function validate(Data storage self) internal view { if (!isValid(self)) { revert InvalidBallot(); } } }
//SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {SafeCastU256} from "@synthetixio/core-contracts/contracts/utils/SafeCast.sol"; import {Epoch} from "./Epoch.sol"; import {Election} from "./Election.sol"; import {ElectionSettings} from "./ElectionSettings.sol"; library Council { using Epoch for Epoch.Data; using ElectionSettings for ElectionSettings.Data; error NotCallableInCurrentPeriod(Epoch.ElectionPeriod currentPeriod); error InvalidEpochConfiguration(uint256 code, uint64 v1, uint64 v2); error ChangesCurrentPeriod(); bytes32 private constant _SLOT_COUNCIL_STORAGE = keccak256(abi.encode("io.synthetix.governance.Council")); struct Data { // True if initializeElectionModule was called bool initialized; // id of the current epoch uint256 currentElectionId; } function load() internal pure returns (Data storage store) { bytes32 s = _SLOT_COUNCIL_STORAGE; assembly { store.slot := s } } function newElection(Data storage self) internal returns (uint256 newElectionId) { newElectionId = ++self.currentElectionId; } function getCurrentEpoch(Data storage self) internal view returns (Epoch.Data storage epoch) { return Epoch.load(self.currentElectionId); } function getCurrentElection( Data storage self ) internal view returns (Election.Data storage election) { return Election.load(self.currentElectionId); } function getPreviousElection( Data storage self ) internal view returns (Election.Data storage election) { // NOTE: will revert if there was no previous election return Election.load(self.currentElectionId - 1); } function getCurrentElectionSettings( Data storage self ) internal view returns (ElectionSettings.Data storage settings) { return ElectionSettings.load(self.currentElectionId); } function getPreviousElectionSettings( Data storage self ) internal view returns (ElectionSettings.Data storage settings) { // NOTE: will revert if there was no previous settings return ElectionSettings.load(self.currentElectionId - 1); } function getNextElectionSettings( Data storage self ) internal view returns (ElectionSettings.Data storage settings) { return ElectionSettings.load(self.currentElectionId + 1); } /// @dev Used to allow certain functions to only operate within a given period function onlyInPeriod(Epoch.ElectionPeriod period) internal view { Epoch.ElectionPeriod currentPeriod = getCurrentEpoch(load()).getCurrentPeriod(); if (currentPeriod != period) { revert NotCallableInCurrentPeriod(currentPeriod); } } /// @dev Used to allow certain functions to only operate within a given periods function onlyInPeriods( Epoch.ElectionPeriod period1, Epoch.ElectionPeriod period2 ) internal view { Epoch.ElectionPeriod currentPeriod = getCurrentEpoch(load()).getCurrentPeriod(); if (currentPeriod != period1 && currentPeriod != period2) { revert NotCallableInCurrentPeriod(currentPeriod); } } /// @dev Ensures epoch dates are in the correct order, durations are above minimums, etc function validateEpochSchedule( Data storage self, uint64 epochStartDate, uint64 nominationPeriodStartDate, uint64 votingPeriodStartDate, uint64 epochEndDate ) internal view { if (epochEndDate <= votingPeriodStartDate) { revert InvalidEpochConfiguration(1, epochEndDate, votingPeriodStartDate); } else if (votingPeriodStartDate <= nominationPeriodStartDate) { revert InvalidEpochConfiguration(2, votingPeriodStartDate, nominationPeriodStartDate); } else if (nominationPeriodStartDate <= epochStartDate) { revert InvalidEpochConfiguration(3, nominationPeriodStartDate, epochStartDate); } uint64 epochDuration = epochEndDate - epochStartDate; uint64 votingPeriodDuration = epochEndDate - votingPeriodStartDate; uint64 nominationPeriodDuration = votingPeriodStartDate - nominationPeriodStartDate; ElectionSettings.Data storage settings = getCurrentElectionSettings(self); if (epochDuration < settings.nominationPeriodDuration + settings.votingPeriodDuration) { revert InvalidEpochConfiguration( 4, epochDuration, settings.nominationPeriodDuration + settings.votingPeriodDuration ); } else if (nominationPeriodDuration < settings.nominationPeriodDuration) { revert InvalidEpochConfiguration( 5, nominationPeriodDuration, settings.nominationPeriodDuration ); } else if (votingPeriodDuration < settings.votingPeriodDuration) { revert InvalidEpochConfiguration( 6, votingPeriodDuration, settings.votingPeriodDuration ); } } function configureEpochSchedule( Data storage self, Epoch.Data storage epoch, uint64 epochStartDate, uint64 nominationPeriodStartDate, uint64 votingPeriodStartDate, uint64 epochEndDate ) internal { validateEpochSchedule( self, epochStartDate, nominationPeriodStartDate, votingPeriodStartDate, epochEndDate ); epoch.setEpochDates( epochStartDate, nominationPeriodStartDate, votingPeriodStartDate, epochEndDate ); } /// @dev Changes epoch dates, with validations function validateEpochScheduleTweak( Data storage self, Epoch.Data storage currentEpoch, Epoch.Data memory newEpoch ) internal view { ElectionSettings.Data storage settings = getCurrentElectionSettings(self); if ( uint64AbsDifference(newEpoch.endDate, currentEpoch.startDate + settings.epochDuration) > settings.maxDateAdjustmentTolerance || uint64AbsDifference( newEpoch.nominationPeriodStartDate, currentEpoch.nominationPeriodStartDate ) > settings.maxDateAdjustmentTolerance || uint64AbsDifference( newEpoch.votingPeriodStartDate, currentEpoch.votingPeriodStartDate ) > settings.maxDateAdjustmentTolerance ) { revert InvalidEpochConfiguration(7, 0, 0); } validateEpochSchedule( self, currentEpoch.startDate, newEpoch.nominationPeriodStartDate, newEpoch.votingPeriodStartDate, newEpoch.endDate ); if (Epoch.getPeriodFor(newEpoch) != Epoch.ElectionPeriod.Administration) { revert ChangesCurrentPeriod(); } } /// @dev Moves schedule forward to immediately jump to the nomination period function jumpToNominationPeriod(Data storage self) internal { Epoch.Data storage currentEpoch = getCurrentEpoch(self); ElectionSettings.Data storage settings = getCurrentElectionSettings(self); // Keep the previous durations, but shift everything back // so that nominations start now uint64 newNominationPeriodStartDate = SafeCastU256.to64(block.timestamp); uint64 newVotingPeriodStartDate = newNominationPeriodStartDate + settings.nominationPeriodDuration; uint64 newEpochEndDate = newVotingPeriodStartDate + settings.votingPeriodDuration; configureEpochSchedule( self, currentEpoch, currentEpoch.startDate, newNominationPeriodStartDate, newVotingPeriodStartDate, newEpochEndDate ); } function uint64AbsDifference(uint64 valueA, uint64 valueB) private pure returns (uint64) { return valueA > valueB ? valueA - valueB : valueB - valueA; } }
//SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {SetUtil} from "@synthetixio/core-contracts/contracts/utils/SetUtil.sol"; library Election { using SetUtil for SetUtil.Bytes32Set; struct Data { // True if ballots have been counted in this election bool evaluated; // Number of counted ballots in this election uint256 numEvaluatedBallots; // List of nominated candidates in this election SetUtil.AddressSet nominees; // List of winners of this election (requires evaluation) SetUtil.AddressSet winners; // List of all ballot ids in this election SetUtil.Bytes32Set ballotPtrs; // Total votes count for a given candidate mapping(address => uint256) candidateVoteTotals; } function load(uint256 epochIndex) internal pure returns (Data storage election) { bytes32 s = keccak256(abi.encode("io.synthetix.governance.Election", epochIndex)); assembly { election.slot := s } } }
//SPDX-License-Identifier: MIT pragma solidity ^0.8.0; library ElectionSettings { event ElectionSettingsUpdated( uint8 epochSeatCount, uint8 minimumActiveMembers, uint64 epochDuration, uint64 nominationPeriodDuration, uint64 votingPeriodDuration, uint64 maxDateAdjustmentTolerance ); error InvalidElectionSettings(); struct Data { // Number of council members in the current epoch uint8 epochSeatCount; // Minimum active council members. If too many are dismissed an emergency election is triggered uint8 minimumActiveMembers; // Expected duration of the epoch uint64 epochDuration; // Expected nomination period duration uint64 nominationPeriodDuration; // Expected voting period duration uint64 votingPeriodDuration; // Maximum size for tweaking epoch schedules (see tweakEpochSchedule) uint64 maxDateAdjustmentTolerance; } function load(uint256 epochIndex) internal pure returns (Data storage settings) { bytes32 s = keccak256(abi.encode("io.synthetix.governance.ElectionSettings", epochIndex)); assembly { settings.slot := s } } /// @dev Minimum duration for Nomination and Voting periods, making sure that /// they cannot be "deleted" by the current council uint64 private constant _MIN_ELECTION_PERIOD_DURATION = 1 days; function setElectionSettings( Data storage settings, uint8 epochSeatCount, uint8 minimumActiveMembers, uint64 epochDuration, uint64 nominationPeriodDuration, uint64 votingPeriodDuration, uint64 maxDateAdjustmentTolerance ) internal { settings.epochSeatCount = epochSeatCount; settings.minimumActiveMembers = minimumActiveMembers; settings.epochDuration = epochDuration; settings.nominationPeriodDuration = nominationPeriodDuration; settings.votingPeriodDuration = votingPeriodDuration; settings.maxDateAdjustmentTolerance = maxDateAdjustmentTolerance; validate(settings); emit ElectionSettingsUpdated( settings.epochSeatCount, settings.minimumActiveMembers, settings.epochDuration, settings.nominationPeriodDuration, settings.votingPeriodDuration, settings.maxDateAdjustmentTolerance ); } function validate(Data storage settings) internal view { if ( settings.epochSeatCount == 0 || settings.minimumActiveMembers == 0 || settings.minimumActiveMembers > settings.epochSeatCount || settings.epochDuration == 0 || settings.nominationPeriodDuration == 0 || settings.votingPeriodDuration == 0 || settings.nominationPeriodDuration < minimumElectionPeriodDuration(settings) || settings.votingPeriodDuration < minimumElectionPeriodDuration(settings) || settings.epochDuration < settings.nominationPeriodDuration + settings.votingPeriodDuration ) { revert InvalidElectionSettings(); } } function minimumElectionPeriodDuration(Data storage settings) internal view returns (uint256) { return _MIN_ELECTION_PERIOD_DURATION + settings.maxDateAdjustmentTolerance; } function copyMissingFrom(Data storage to, Data storage from) internal { if (to.epochSeatCount == 0) { to.epochSeatCount = from.epochSeatCount; } if (to.minimumActiveMembers == 0) { to.minimumActiveMembers = from.minimumActiveMembers; } if (to.epochDuration == 0) { to.epochDuration = from.epochDuration; } if (to.nominationPeriodDuration == 0) { to.nominationPeriodDuration = from.nominationPeriodDuration; } if (to.votingPeriodDuration == 0) { to.votingPeriodDuration = from.votingPeriodDuration; } if (to.maxDateAdjustmentTolerance == 0) { to.maxDateAdjustmentTolerance = from.maxDateAdjustmentTolerance; } } }
//SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {SafeCastU256} from "@synthetixio/core-contracts/contracts/utils/SafeCast.sol"; library Epoch { using SafeCastU256 for uint256; enum ElectionPeriod { // Council elected and active Administration, // Accepting nominations for next election Nomination, // Accepting votes for ongoing election Vote, // Votes being counted Evaluation } struct Data { // Date at which the epoch started uint64 startDate; // Date at which the epoch's nomination period will start uint64 nominationPeriodStartDate; // Date at which the epoch's voting period will start uint64 votingPeriodStartDate; // Date at which the epoch's voting period will end uint64 endDate; } function load(uint256 epochIndex) internal pure returns (Data storage epoch) { bytes32 s = keccak256(abi.encode("io.synthetix.governance.Epoch", epochIndex)); assembly { epoch.slot := s } } function setEpochDates( Epoch.Data storage self, uint64 startDate, uint64 nominationPeriodStartDate, uint64 votingPeriodStartDate, uint64 endDate ) internal { self.startDate = startDate; self.nominationPeriodStartDate = nominationPeriodStartDate; self.votingPeriodStartDate = votingPeriodStartDate; self.endDate = endDate; } /// @dev Determines the current period type according to the current time and the epoch's dates function getCurrentPeriod(Data storage epoch) internal view returns (Epoch.ElectionPeriod) { uint64 currentTime = block.timestamp.to64(); if (currentTime >= epoch.endDate) { return ElectionPeriod.Evaluation; } if (currentTime >= epoch.votingPeriodStartDate) { return ElectionPeriod.Vote; } if (currentTime >= epoch.nominationPeriodStartDate) { return ElectionPeriod.Nomination; } return ElectionPeriod.Administration; } function getPeriodFor(Data memory epoch) internal view returns (Epoch.ElectionPeriod) { uint64 currentTime = block.timestamp.to64(); if (currentTime >= epoch.endDate) { return ElectionPeriod.Evaluation; } if (currentTime >= epoch.votingPeriodStartDate) { return ElectionPeriod.Vote; } if (currentTime >= epoch.nominationPeriodStartDate) { return ElectionPeriod.Nomination; } return ElectionPeriod.Administration; } }
//SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {MathUtil} from "../utils/MathUtil.sol"; import {SnapshotVotePowerEpoch} from "./SnapshotVotePowerEpoch.sol"; library SnapshotVotePower { error InvalidWeightType(); enum WeightType { Sqrt, Linear, Scaled } struct Data { bool enabled; SnapshotVotePower.WeightType weight; uint256 scale; // 18 decimals mapping(uint128 => SnapshotVotePowerEpoch.Data) epochs; } function load(address snapshotContract) internal pure returns (Data storage self) { bytes32 s = keccak256( abi.encode("io.synthetix.governance.SnapshotVotePower", snapshotContract) ); assembly { self.slot := s } } function calculateVotingPower( SnapshotVotePower.Data storage self, uint256 ballotBalance ) internal view returns (uint256 votePower) { if (self.weight == WeightType.Sqrt) { return MathUtil.sqrt(ballotBalance); } if (self.weight == WeightType.Linear) { return ballotBalance; } if (self.weight == WeightType.Scaled) { // solhint-disable-next-line return (ballotBalance * self.scale) / 10 ** 18; } revert InvalidWeightType(); } }
//SPDX-License-Identifier: MIT pragma solidity ^0.8.0; library SnapshotVotePowerEpoch { struct Data { uint128 snapshotId; mapping(address => uint256) recordedVotingPower; } }
//SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /* Reference implementations: * Solmate - https://github.com/Rari-Capital/solmate/blob/main/src/utils/FixedPointMathLib.sol */ library MathUtil { function sqrt(uint256 x) internal pure returns (uint256 z) { assembly { // Start off with z at 1. z := 1 // Used below to help find a nearby power of 2. let y := x // Find the lowest power of 2 that is at least sqrt(x). if iszero(lt(y, 0x100000000000000000000000000000000)) { y := shr(128, y) // Like dividing by 2 ** 128. z := shl(64, z) // Like multiplying by 2 ** 64. } if iszero(lt(y, 0x10000000000000000)) { y := shr(64, y) // Like dividing by 2 ** 64. z := shl(32, z) // Like multiplying by 2 ** 32. } if iszero(lt(y, 0x100000000)) { y := shr(32, y) // Like dividing by 2 ** 32. z := shl(16, z) // Like multiplying by 2 ** 16. } if iszero(lt(y, 0x10000)) { y := shr(16, y) // Like dividing by 2 ** 16. z := shl(8, z) // Like multiplying by 2 ** 8. } if iszero(lt(y, 0x100)) { y := shr(8, y) // Like dividing by 2 ** 8. z := shl(4, z) // Like multiplying by 2 ** 4. } if iszero(lt(y, 0x10)) { y := shr(4, y) // Like dividing by 2 ** 4. z := shl(2, z) // Like multiplying by 2 ** 2. } if iszero(lt(y, 0x8)) { // Equivalent to 2 ** z. z := shl(1, z) } // Shifting right by 1 is like dividing by 2. z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) // Compute a rounded down version of z. let zRoundDown := div(x, z) // If zRoundDown is smaller, use it. if lt(zRoundDown, z) { z := zRoundDown } } } }
{ "optimizer": { "enabled": true, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"voter","type":"address"},{"internalType":"uint256","name":"electionId","type":"uint256"}],"name":"BallotAlreadyPrepared","type":"error"},{"inputs":[],"name":"InvalidSnapshotContract","type":"error"},{"inputs":[],"name":"InvalidWeightType","type":"error"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"NoPower","type":"error"},{"inputs":[{"internalType":"enum Epoch.ElectionPeriod","name":"currentPeriod","type":"uint8"}],"name":"NotCallableInCurrentPeriod","type":"error"},{"inputs":[],"name":"OverflowUint256ToUint128","type":"error"},{"inputs":[],"name":"OverflowUint256ToUint64","type":"error"},{"inputs":[{"internalType":"uint128","name":"snapshotId","type":"uint128"}],"name":"SnapshotAlreadyTaken","type":"error"},{"inputs":[{"internalType":"address","name":"snapshotContract","type":"address"},{"internalType":"uint128","name":"electionId","type":"uint128"}],"name":"SnapshotNotTaken","type":"error"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"Unauthorized","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"snapshotContract","type":"address"},{"indexed":false,"internalType":"uint256","name":"scale","type":"uint256"}],"name":"ScaleSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"snapshotContract","type":"address"},{"indexed":true,"internalType":"bool","name":"enabled","type":"bool"},{"indexed":false,"internalType":"enum SnapshotVotePower.WeightType","name":"weight","type":"uint8"}],"name":"SnapshotContractSet","type":"event"},{"inputs":[{"internalType":"address","name":"voter","type":"address"}],"name":"getPreparedBallot","outputs":[{"internalType":"uint256","name":"power","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"snapshotContract","type":"address"},{"internalType":"uint128","name":"electionId","type":"uint128"}],"name":"getVotePowerSnapshotId","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"snapshotContract","type":"address"},{"internalType":"address","name":"voter","type":"address"},{"internalType":"uint256","name":"periodId","type":"uint256"}],"name":"getVotingPowerForUser","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"snapshotContract","type":"address"},{"internalType":"address","name":"voter","type":"address"}],"name":"prepareBallotWithSnapshot","outputs":[{"internalType":"uint256","name":"votingPower","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"snapshotContract","type":"address"},{"internalType":"uint256","name":"scale","type":"uint256"}],"name":"setScale","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"snapshotContract","type":"address"},{"internalType":"enum SnapshotVotePower.WeightType","name":"weight","type":"uint8"},{"internalType":"bool","name":"enabled","type":"bool"}],"name":"setSnapshotContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"snapshotContract","type":"address"}],"name":"takeVotePowerSnapshot","outputs":[{"internalType":"uint128","name":"snapshotId","type":"uint128"}],"stateMutability":"nonpayable","type":"function"}]
Deployed Bytecode
0x608060405234801561001057600080fd5b506004361061007c5760003560e01c806372e74f321161005b57806372e74f32146100cf5780639425bb45146100fa578063ac59ec2a1461010d578063af90f4741461012057600080fd5b80628634bd146100815780634a9ceff7146100a75780634b579b8e146100ba575b600080fd5b61009461008f366004610ced565b610133565b6040519081526020015b60405180910390f35b6100946100b5366004610d29565b6101cc565b6100cd6100c8366004610d5c565b6103cb565b005b6100e26100dd366004610dae565b610471565b6040516001600160801b03909116815260200161009e565b6100e2610108366004610de8565b61060a565b6100cd61011b366004610e1f565b61063e565b61009461012e366004610dae565b6106e2565b6040516322896b3d60e21b81526001600160a01b038381166004830152602482018390526000918291861690638a25acf490604401602060405180830381865afa158015610185573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101a99190610e49565b905060006101b686610711565b90506101c28183610799565b9695505050505050565b60006101d86002610853565b60006101ee6101e56108b7565b60010154610919565b905060006101fb85610711565b805490915060ff166102205760405163021aa26560e61b815260040160405180910390fd5b6001600160801b03808316600090815260028301602052604081208054909216900361026c5785836040516305afe4f560e11b8152600401610263929190610e62565b60405180910390fd5b6001600160a01b0385166000908152600182016020526040902054156102a9578483604051630690ab3b60e21b8152600401610263929190610e62565b80546040516322896b3d60e21b81526000916001600160a01b03891691638a25acf4916102e4918a916001600160801b031690600401610e62565b602060405180830381865afa158015610301573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103259190610e49565b90506103318382610799565b945084600003610371578154604051638924946160e01b81526001600160801b0390911660048201526001600160a01b0387166024820152604401610263565b6000610387856001600160801b03168846610947565b90508581600001600082825461039d9190610e9a565b9091555050506001600160a01b03909516600090815260019091016020526040902083905550909392505050565b6103d36109bd565b6103df600060016109fa565b60006103ea84610711565b805460ff19811684151590811783559192508491839161ffff191661ff00199091161761010083600281111561042257610422610ead565b0217905550811515846001600160a01b03167fb207041bd6ec2cca2ce350ee5135db9d1fbc13dd30ca928868a80c42706d2195856040516104639190610ec3565b60405180910390a350505050565b600061047f600160026109fa565b600061048a83610711565b905060006104996101e56108b7565b825490915060ff166104be5760405163021aa26560e61b815260040160405180910390fd5b6001600160801b038082166000908152600284016020526040902080549091161561050a578054604051634a05c11760e11b81526001600160801b039091166004820152602401610263565b846001600160a01b031663988e65956040518163ffffffff1660e01b8152600401602060405180830381865afa158015610548573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061056c9190610edd565b9350846001600160a01b031663abb6de9561058642610919565b6040516001600160e01b031960e084901b1681526001600160801b039091166004820152602401600060405180830381600087803b1580156105c757600080fd5b505af11580156105db573d6000803e3d6000fd5b505082546fffffffffffffffffffffffffffffffff19166001600160801b038716179092555092949350505050565b600061061583610711565b6001600160801b0380841660009081526002929092016020526040909120541690505b92915050565b6106466109bd565b6106506000610853565b600061065b83610711565b905060028154610100900460ff16600281111561067a5761067a610ead565b146106985760405163019c040560e11b815260040160405180910390fd5b600181018290556040518281526001600160a01b038416907ffc70ceaac2e9234e490dd6cbfba44ef0cc644bfb90aefaa722784dca993cb18d9060200160405180910390a2505050565b6000806106f06101e56108b7565b90506000610708826001600160801b03168546610947565b54949350505050565b6000808260405160200161077a919060408082526029908201527f696f2e73796e7468657469782e676f7665726e616e63652e536e617073686f746060820152682b37ba32a837bbb2b960b91b60808201526001600160a01b0391909116602082015260a00190565b60408051601f1981840301815291905280516020909101209392505050565b6000808354610100900460ff1660028111156107b7576107b7610ead565b036107cc576107c582610a85565b9050610638565b60018354610100900460ff1660028111156107e9576107e9610ead565b036107f5575080610638565b60028354610100900460ff16600281111561081257610812610ead565b0361083a57670de0b6b3a76400008360010154836108309190610efa565b6107c59190610f11565b60405163019c040560e11b815260040160405180910390fd5b600061086d6108686108636108b7565b610b59565b610b68565b905081600381111561088157610881610ead565b81600381111561089357610893610ead565b146108b35780604051630d98cc5760e31b81526004016102639190610f33565b5050565b6000806040516020016108fb906020808252601f908201527f696f2e73796e7468657469782e676f7665726e616e63652e436f756e63696c00604082015260600190565b60408051601f19818403018152919052805160209091012092915050565b60006001600160801b0382111561094357604051637d5864af60e11b815260040160405180910390fd5b5090565b6040805160806020808301829052601e60a08401527f696f2e73796e7468657469782e676f7665726e616e63652e42616c6c6f74000060c080850191909152838501979097526001600160a01b039590951660608301528101929092528051808303909401845260e09091019052815191012090565b6109c5610bf2565b6001600160a01b0316336001600160a01b0316146109f85760405163472511eb60e11b8152336004820152602401610263565b565b6000610a0a6108686108636108b7565b9050826003811115610a1e57610a1e610ead565b816003811115610a3057610a30610ead565b14158015610a605750816003811115610a4b57610a4b610ead565b816003811115610a5d57610a5d610ead565b14155b15610a805780604051630d98cc5760e31b81526004016102639190610f33565b505050565b600181600160801b8110610a9e5760409190911b9060801c5b600160401b8110610ab45760209190911b9060401c5b6401000000008110610acb5760109190911b9060201c5b620100008110610ae05760089190911b9060101c5b6101008110610af45760049190911b9060081c5b60108110610b075760029190911b9060041c5b60088110610b16578160011b91505b5080820401600190811c80830401811c80830401811c80830401811c80830401811c80830401811c80830401901c80820481811015610b53578091505b50919050565b60006106388260010154610c0b565b600080610b7442610c56565b835490915067ffffffffffffffff600160c01b909104811690821610610b9d5750600392915050565b825467ffffffffffffffff600160801b909104811690821610610bc35750600292915050565b825467ffffffffffffffff600160401b909104811690821610610be95750600192915050565b50600092915050565b6000610bfc610c81565b546001600160a01b0316919050565b6040805160208101829052601d60608201527f696f2e73796e7468657469782e676f7665726e616e63652e45706f63680000006080820152908101829052600090819060a00161077a565b600067ffffffffffffffff821115610943576040516372b1c34f60e01b815260040160405180910390fd5b6000806040516020016108fb9060208082526023908201527f696f2e73796e7468657469782e636f72652d636f6e7472616374732e4f776e61604082015262626c6560e81b606082015260800190565b80356001600160a01b0381168114610ce857600080fd5b919050565b600080600060608486031215610d0257600080fd5b610d0b84610cd1565b9250610d1960208501610cd1565b9150604084013590509250925092565b60008060408385031215610d3c57600080fd5b610d4583610cd1565b9150610d5360208401610cd1565b90509250929050565b600080600060608486031215610d7157600080fd5b610d7a84610cd1565b9250602084013560038110610d8e57600080fd5b915060408401358015158114610da357600080fd5b809150509250925092565b600060208284031215610dc057600080fd5b610dc982610cd1565b9392505050565b6001600160801b0381168114610de557600080fd5b50565b60008060408385031215610dfb57600080fd5b610e0483610cd1565b91506020830135610e1481610dd0565b809150509250929050565b60008060408385031215610e3257600080fd5b610e3b83610cd1565b946020939093013593505050565b600060208284031215610e5b57600080fd5b5051919050565b6001600160a01b039290921682526001600160801b0316602082015260400190565b634e487b7160e01b600052601160045260246000fd5b8082018082111561063857610638610e84565b634e487b7160e01b600052602160045260246000fd5b6020810160038310610ed757610ed7610ead565b91905290565b600060208284031215610eef57600080fd5b8151610dc981610dd0565b808202811582820484141761063857610638610e84565b600082610f2e57634e487b7160e01b600052601260045260246000fd5b500490565b6020810160048310610ed757610ed7610ead56fea2646970667358221220f539e65021475a449290d63085ed3520223a38524ad9b2e30437bad4e5a954cb64736f6c63430008110033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
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.