Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00Latest 25 from a total of 872 transactions
| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
| Cross Chain Vote | 22752218 | 270 days ago | IN | 0 ETH | 0.00013552 | ||||
| Cross Chain Vote | 22752216 | 270 days ago | IN | 0 ETH | 0.00009952 | ||||
| Cross Chain Vote | 22752216 | 270 days ago | IN | 0 ETH | 0.00013911 | ||||
| Cross Chain Vote | 22752215 | 270 days ago | IN | 0 ETH | 0.00010092 | ||||
| Cross Chain Vote | 22751919 | 270 days ago | IN | 0 ETH | 0.00009963 | ||||
| Cross Chain Vote | 22751917 | 270 days ago | IN | 0 ETH | 0.00012408 | ||||
| Cross Chain Vote | 22751616 | 270 days ago | IN | 0 ETH | 0.0001193 | ||||
| Cross Chain Vote | 22751320 | 270 days ago | IN | 0 ETH | 0.00007615 | ||||
| Cross Chain Vote | 22751318 | 270 days ago | IN | 0 ETH | 0.00010234 | ||||
| Cross Chain Vote | 22751318 | 270 days ago | IN | 0 ETH | 0.00007534 | ||||
| Cross Chain Vote | 22751318 | 270 days ago | IN | 0 ETH | 0.00010459 | ||||
| Cross Chain Vote | 22751317 | 270 days ago | IN | 0 ETH | 0.00007965 | ||||
| Cross Chain Vote | 22751021 | 270 days ago | IN | 0 ETH | 0.00012497 | ||||
| Cross Chain Vote | 22750726 | 270 days ago | IN | 0 ETH | 0.00010851 | ||||
| Cross Chain Vote | 22750423 | 270 days ago | IN | 0 ETH | 0.0001253 | ||||
| Cross Chain Vote | 22750423 | 270 days ago | IN | 0 ETH | 0.00012988 | ||||
| Cross Chain Vote | 22749828 | 270 days ago | IN | 0 ETH | 0.00013404 | ||||
| Cross Chain Vote | 22749229 | 270 days ago | IN | 0 ETH | 0.00012977 | ||||
| Cross Chain Vote | 22748932 | 270 days ago | IN | 0 ETH | 0.00013905 | ||||
| Cross Chain Vote | 22748633 | 270 days ago | IN | 0 ETH | 0.00018339 | ||||
| Cross Chain Vote | 22748335 | 270 days ago | IN | 0 ETH | 0.00017241 | ||||
| Cross Chain Vote | 22748037 | 270 days ago | IN | 0 ETH | 0.00040433 | ||||
| Cross Chain Vote | 22747742 | 271 days ago | IN | 0 ETH | 0.00042742 | ||||
| Cross Chain Vote | 22747740 | 271 days ago | IN | 0 ETH | 0.00032244 | ||||
| Cross Chain Vote | 22747740 | 271 days ago | IN | 0 ETH | 0.00045069 |
Latest 1 internal transaction
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
|
To
|
||
|---|---|---|---|---|---|---|---|
| 0x60c06040 | 22246014 | 341 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Similar Match Source Code This contract matches the deployed Bytecode of the Source Code for Contract 0x59C27a82...7e2239f33 The constructor portion of the code might be different and could alter the actual behaviour of the contract
Contract Name:
HubVotePool
Compiler Version
v0.8.23+commit.f704f362
Optimization Enabled:
Yes with 17750 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.23;
import {ERC165Checker} from "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol";
import {IGovernor} from "@openzeppelin/contracts/governance/IGovernor.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {HubEvmSpokeVoteDecoder} from "src/HubEvmSpokeVoteDecoder.sol";
import {IWormhole} from "wormhole-sdk/interfaces/IWormhole.sol";
import {QueryResponse, ParsedQueryResponse} from "wormhole-sdk/QueryResponse.sol";
import {Checkpoints} from "src/lib/Checkpoints.sol";
import {ISpokeVoteDecoder} from "src/interfaces/ISpokeVoteDecoder.sol";
import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
/// @title HubVotePool
/// @author [ScopeLift](https://scopelift.co)
/// @notice A contract that parses a specific wormhole query type from the `SpokeVoteAggregator`.
contract HubVotePool is QueryResponse, Ownable {
using Checkpoints for Checkpoints.Trace256;
using ERC165Checker for address;
/// @notice The governor where cross chain votes are submitted.
IGovernor public hubGovernor;
/// @notice A necessary param which is ignored when submitting a vote.
uint8 private constant UNUSED_SUPPORT_PARAM = 1;
/// @notice Thrown when the submitted spoke aggregator vote has a vote that is inconsistent with the previously
/// submitted vote.
error InvalidProposalVote();
/// @notice Thrown if a query vote implementation is set to an address that does not support the
/// `ISpokeVoteDecoder` interface.
error InvalidQueryVoteImpl();
/// @notice Thrown if a vote query is submitted with an unsupported query type.
error UnsupportedQueryType();
/// @notice Emitted when the Governor is updated.
event HubGovernorUpdated(address oldGovernor, address newGovernor);
/// @notice Emitted when a new query type is registered.
event QueryTypeRegistered(uint8 indexed queryType, address oldQueryTypeImpl, address newQueryTypeImpl);
/// @notice Emitted when a vote is recorded from a registered spoke vote aggregator.
event SpokeVoteCast(
uint16 indexed emitterChainId, uint256 proposalId, uint256 voteAgainst, uint256 voteFor, uint256 voteAbstain
);
/// @notice Emitted whtn a new spoke vote address is registered.
event SpokeRegistered(uint16 indexed targetChain, bytes32 oldSpokeVoteAddress, bytes32 newSpokeVoteAddress);
/// @dev Contains the distribution of a proposal vote.
struct ProposalVote {
uint256 againstVotes;
uint256 forVotes;
uint256 abstainVotes;
}
/// @dev Contains the information to register a spoke.
struct SpokeVoteAggregator {
uint16 wormholeChainId;
bytes32 wormholeAddress;
}
/// @notice A mapping of a chain and emitter address that determines valid spokes and addresses for receiving votes.
// Add 256 checkpoints for registry
mapping(uint16 emitterChain => Checkpoints.Trace256 emitterAddress) internal emitterRegistry;
mapping(bytes32 spokeProposalId => ProposalVote proposalVotes) public spokeProposalVotes;
mapping(uint8 queryType => ISpokeVoteDecoder voteImpl) public voteTypeDecoder;
constructor(address _core, address _hubGovernor, address _owner) QueryResponse(_core) Ownable(_owner) {
HubEvmSpokeVoteDecoder evmDecoder = new HubEvmSpokeVoteDecoder(_core, address(this));
_registerQueryType(address(evmDecoder), QueryResponse.QT_ETH_CALL_WITH_FINALITY);
_setGovernor(_hubGovernor);
}
function getSpoke(uint16 _emitterChainId, uint256 _timepoint) external view returns (bytes32) {
return bytes32(emitterRegistry[_emitterChainId].upperLookup(_timepoint));
}
/// @notice Registers or unregisters a query type implementation.
/// @dev Can only be called by the contract owner. Unregisters if the implementation address is zero.
/// @param _queryType The type of query to register.
/// @param _implementation The address of the implementation contract for the query type.
function registerQueryType(uint8 _queryType, address _implementation) external {
_checkOwner();
_registerQueryType(_implementation, _queryType);
}
/// @notice Registers a new spoke chain and its vote aggregator address.
/// @dev Can only be called by the contract owner.
/// @param _targetChain The Wormhole chain ID of the spoke chain.
/// @param _spokeVoteAddress The address of the vote aggregator on the spoke chain.
function registerSpoke(uint16 _targetChain, bytes32 _spokeVoteAddress) external {
_checkOwner();
_registerSpoke(_targetChain, _spokeVoteAddress);
}
/// @notice Registers multiple spoke chains with their corresponding vote aggregator in a single call.
/// @param _spokes An an array of spoke vote aggregators to be registered.
function registerSpokes(SpokeVoteAggregator[] memory _spokes) external {
_checkOwner();
for (uint256 i = 0; i < _spokes.length; i++) {
SpokeVoteAggregator memory _aggregator = _spokes[i];
_registerSpoke(_aggregator.wormholeChainId, _aggregator.wormholeAddress);
}
}
/// @notice Updates the address of the hub governor.
/// @dev Can only be called by the contract owner.
/// @param _newGovernor The address of the new hub governor.
function setGovernor(address _newGovernor) external {
_checkOwner();
_setGovernor(_newGovernor);
}
/// @notice Processes cross chain votes from the spokes. Parses and verifies the Wormhole query response, then casts
/// votes on the hub governor.
/// @param _queryResponseRaw The raw bytes of the query response from Wormhole.
/// @param _signatures The signatures verifying the Wormhole message.
function crossChainVote(bytes memory _queryResponseRaw, IWormhole.Signature[] memory _signatures) external {
ParsedQueryResponse memory _queryResponse = parseAndVerifyQueryResponse(_queryResponseRaw, _signatures);
for (uint256 i = 0; i < _queryResponse.responses.length; i++) {
ISpokeVoteDecoder _voteQueryImpl = voteTypeDecoder[_queryResponse.responses[i].queryType];
if (address(_voteQueryImpl) == address(0)) revert UnsupportedQueryType();
ISpokeVoteDecoder.QueryVote memory _voteQuery = _voteQueryImpl.decode(_queryResponse.responses[i], hubGovernor);
ISpokeVoteDecoder.ProposalVote memory _proposalVote = _voteQuery.proposalVote;
ProposalVote memory _existingSpokeVote = spokeProposalVotes[_voteQuery.spokeProposalId];
if (
_existingSpokeVote.againstVotes > _proposalVote.againstVotes
|| _existingSpokeVote.forVotes > _proposalVote.forVotes
|| _existingSpokeVote.abstainVotes > _proposalVote.abstainVotes
) revert InvalidProposalVote();
spokeProposalVotes[_voteQuery.spokeProposalId] =
ProposalVote(_proposalVote.againstVotes, _proposalVote.forVotes, _proposalVote.abstainVotes);
_castVote(
_voteQuery.proposalId,
ProposalVote(
_proposalVote.againstVotes - _existingSpokeVote.againstVotes,
_proposalVote.forVotes - _existingSpokeVote.forVotes,
_proposalVote.abstainVotes - _existingSpokeVote.abstainVotes
),
_voteQuery.chainId
);
}
}
function _castVote(uint256 _proposalId, ProposalVote memory _vote, uint16 _emitterChainId) internal {
bytes memory _votes = abi.encodePacked(
SafeCast.toUint128(_vote.againstVotes), SafeCast.toUint128(_vote.forVotes), SafeCast.toUint128(_vote.abstainVotes)
);
hubGovernor.castVoteWithReasonAndParams(
_proposalId, UNUSED_SUPPORT_PARAM, "rolled-up vote from governance spoke token holders", _votes
);
emit SpokeVoteCast(_emitterChainId, _proposalId, _vote.againstVotes, _vote.forVotes, _vote.abstainVotes);
}
function _registerSpoke(uint16 _targetChain, bytes32 _spokeVoteAddress) internal {
Checkpoints.Trace256 storage registeredAddressCheckpoint = emitterRegistry[_targetChain];
emit SpokeRegistered(
_targetChain, bytes32(registeredAddressCheckpoint.upperLookup(block.timestamp)), _spokeVoteAddress
);
registeredAddressCheckpoint.push(block.timestamp, uint256(_spokeVoteAddress));
}
function _registerQueryType(address _implementation, uint8 _queryType) internal {
emit QueryTypeRegistered(_queryType, address(voteTypeDecoder[_queryType]), _implementation);
if (_implementation == address(0)) {
delete voteTypeDecoder[_queryType];
return;
}
bool _isValid = _implementation.supportsInterface(type(ISpokeVoteDecoder).interfaceId);
if (!_isValid) revert InvalidQueryVoteImpl();
voteTypeDecoder[_queryType] = ISpokeVoteDecoder(_implementation);
}
function _setGovernor(address _newGovernor) internal {
emit HubGovernorUpdated(address(hubGovernor), _newGovernor);
hubGovernor = IGovernor(_newGovernor);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165Checker.sol)
pragma solidity ^0.8.20;
import {IERC165} from "./IERC165.sol";
/**
* @dev Library used to query support of an interface declared via {IERC165}.
*
* Note that these functions return the actual result of the query: they do not
* `revert` if an interface is not supported. It is up to the caller to decide
* what to do in these cases.
*/
library ERC165Checker {
// As per the EIP-165 spec, no interface should ever match 0xffffffff
bytes4 private constant INTERFACE_ID_INVALID = 0xffffffff;
/**
* @dev Returns true if `account` supports the {IERC165} interface.
*/
function supportsERC165(address account) internal view returns (bool) {
// Any contract that implements ERC165 must explicitly indicate support of
// InterfaceId_ERC165 and explicitly indicate non-support of InterfaceId_Invalid
return
supportsERC165InterfaceUnchecked(account, type(IERC165).interfaceId) &&
!supportsERC165InterfaceUnchecked(account, INTERFACE_ID_INVALID);
}
/**
* @dev Returns true if `account` supports the interface defined by
* `interfaceId`. Support for {IERC165} itself is queried automatically.
*
* See {IERC165-supportsInterface}.
*/
function supportsInterface(address account, bytes4 interfaceId) internal view returns (bool) {
// query support of both ERC165 as per the spec and support of _interfaceId
return supportsERC165(account) && supportsERC165InterfaceUnchecked(account, interfaceId);
}
/**
* @dev Returns a boolean array where each value corresponds to the
* interfaces passed in and whether they're supported or not. This allows
* you to batch check interfaces for a contract where your expectation
* is that some interfaces may not be supported.
*
* See {IERC165-supportsInterface}.
*/
function getSupportedInterfaces(
address account,
bytes4[] memory interfaceIds
) internal view returns (bool[] memory) {
// an array of booleans corresponding to interfaceIds and whether they're supported or not
bool[] memory interfaceIdsSupported = new bool[](interfaceIds.length);
// query support of ERC165 itself
if (supportsERC165(account)) {
// query support of each interface in interfaceIds
for (uint256 i = 0; i < interfaceIds.length; i++) {
interfaceIdsSupported[i] = supportsERC165InterfaceUnchecked(account, interfaceIds[i]);
}
}
return interfaceIdsSupported;
}
/**
* @dev Returns true if `account` supports all the interfaces defined in
* `interfaceIds`. Support for {IERC165} itself is queried automatically.
*
* Batch-querying can lead to gas savings by skipping repeated checks for
* {IERC165} support.
*
* See {IERC165-supportsInterface}.
*/
function supportsAllInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool) {
// query support of ERC165 itself
if (!supportsERC165(account)) {
return false;
}
// query support of each interface in interfaceIds
for (uint256 i = 0; i < interfaceIds.length; i++) {
if (!supportsERC165InterfaceUnchecked(account, interfaceIds[i])) {
return false;
}
}
// all interfaces supported
return true;
}
/**
* @notice Query if a contract implements an interface, does not check ERC165 support
* @param account The address of the contract to query for support of an interface
* @param interfaceId The interface identifier, as specified in ERC-165
* @return true if the contract at account indicates support of the interface with
* identifier interfaceId, false otherwise
* @dev Assumes that account contains a contract that supports ERC165, otherwise
* the behavior of this method is undefined. This precondition can be checked
* with {supportsERC165}.
*
* Some precompiled contracts will falsely indicate support for a given interface, so caution
* should be exercised when using this function.
*
* Interface identification is specified in ERC-165.
*/
function supportsERC165InterfaceUnchecked(address account, bytes4 interfaceId) internal view returns (bool) {
// prepare call
bytes memory encodedParams = abi.encodeCall(IERC165.supportsInterface, (interfaceId));
// perform static call
bool success;
uint256 returnSize;
uint256 returnValue;
assembly {
success := staticcall(30000, account, add(encodedParams, 0x20), mload(encodedParams), 0x00, 0x20)
returnSize := returndatasize()
returnValue := mload(0x00)
}
return success && returnSize >= 0x20 && returnValue > 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (governance/IGovernor.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../interfaces/IERC165.sol";
import {IERC6372} from "../interfaces/IERC6372.sol";
/**
* @dev Interface of the {Governor} core.
*/
interface IGovernor is IERC165, IERC6372 {
enum ProposalState {
Pending,
Active,
Canceled,
Defeated,
Succeeded,
Queued,
Expired,
Executed
}
/**
* @dev Empty proposal or a mismatch between the parameters length for a proposal call.
*/
error GovernorInvalidProposalLength(uint256 targets, uint256 calldatas, uint256 values);
/**
* @dev The vote was already cast.
*/
error GovernorAlreadyCastVote(address voter);
/**
* @dev Token deposits are disabled in this contract.
*/
error GovernorDisabledDeposit();
/**
* @dev The `account` is not a proposer.
*/
error GovernorOnlyProposer(address account);
/**
* @dev The `account` is not the governance executor.
*/
error GovernorOnlyExecutor(address account);
/**
* @dev The `proposalId` doesn't exist.
*/
error GovernorNonexistentProposal(uint256 proposalId);
/**
* @dev The current state of a proposal is not the required for performing an operation.
* The `expectedStates` is a bitmap with the bits enabled for each ProposalState enum position
* counting from right to left.
*
* NOTE: If `expectedState` is `bytes32(0)`, the proposal is expected to not be in any state (i.e. not exist).
* This is the case when a proposal that is expected to be unset is already initiated (the proposal is duplicated).
*
* See {Governor-_encodeStateBitmap}.
*/
error GovernorUnexpectedProposalState(uint256 proposalId, ProposalState current, bytes32 expectedStates);
/**
* @dev The voting period set is not a valid period.
*/
error GovernorInvalidVotingPeriod(uint256 votingPeriod);
/**
* @dev The `proposer` does not have the required votes to create a proposal.
*/
error GovernorInsufficientProposerVotes(address proposer, uint256 votes, uint256 threshold);
/**
* @dev The `proposer` is not allowed to create a proposal.
*/
error GovernorRestrictedProposer(address proposer);
/**
* @dev The vote type used is not valid for the corresponding counting module.
*/
error GovernorInvalidVoteType();
/**
* @dev Queue operation is not implemented for this governor. Execute should be called directly.
*/
error GovernorQueueNotImplemented();
/**
* @dev The proposal hasn't been queued yet.
*/
error GovernorNotQueuedProposal(uint256 proposalId);
/**
* @dev The proposal has already been queued.
*/
error GovernorAlreadyQueuedProposal(uint256 proposalId);
/**
* @dev The provided signature is not valid for the expected `voter`.
* If the `voter` is a contract, the signature is not valid using {IERC1271-isValidSignature}.
*/
error GovernorInvalidSignature(address voter);
/**
* @dev Emitted when a proposal is created.
*/
event ProposalCreated(
uint256 proposalId,
address proposer,
address[] targets,
uint256[] values,
string[] signatures,
bytes[] calldatas,
uint256 voteStart,
uint256 voteEnd,
string description
);
/**
* @dev Emitted when a proposal is queued.
*/
event ProposalQueued(uint256 proposalId, uint256 etaSeconds);
/**
* @dev Emitted when a proposal is executed.
*/
event ProposalExecuted(uint256 proposalId);
/**
* @dev Emitted when a proposal is canceled.
*/
event ProposalCanceled(uint256 proposalId);
/**
* @dev Emitted when a vote is cast without params.
*
* Note: `support` values should be seen as buckets. Their interpretation depends on the voting module used.
*/
event VoteCast(address indexed voter, uint256 proposalId, uint8 support, uint256 weight, string reason);
/**
* @dev Emitted when a vote is cast with params.
*
* Note: `support` values should be seen as buckets. Their interpretation depends on the voting module used.
* `params` are additional encoded parameters. Their interpepretation also depends on the voting module used.
*/
event VoteCastWithParams(
address indexed voter,
uint256 proposalId,
uint8 support,
uint256 weight,
string reason,
bytes params
);
/**
* @notice module:core
* @dev Name of the governor instance (used in building the ERC712 domain separator).
*/
function name() external view returns (string memory);
/**
* @notice module:core
* @dev Version of the governor instance (used in building the ERC712 domain separator). Default: "1"
*/
function version() external view returns (string memory);
/**
* @notice module:voting
* @dev A description of the possible `support` values for {castVote} and the way these votes are counted, meant to
* be consumed by UIs to show correct vote options and interpret the results. The string is a URL-encoded sequence of
* key-value pairs that each describe one aspect, for example `support=bravo&quorum=for,abstain`.
*
* There are 2 standard keys: `support` and `quorum`.
*
* - `support=bravo` refers to the vote options 0 = Against, 1 = For, 2 = Abstain, as in `GovernorBravo`.
* - `quorum=bravo` means that only For votes are counted towards quorum.
* - `quorum=for,abstain` means that both For and Abstain votes are counted towards quorum.
*
* If a counting module makes use of encoded `params`, it should include this under a `params` key with a unique
* name that describes the behavior. For example:
*
* - `params=fractional` might refer to a scheme where votes are divided fractionally between for/against/abstain.
* - `params=erc721` might refer to a scheme where specific NFTs are delegated to vote.
*
* NOTE: The string can be decoded by the standard
* https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams[`URLSearchParams`]
* JavaScript class.
*/
// solhint-disable-next-line func-name-mixedcase
function COUNTING_MODE() external view returns (string memory);
/**
* @notice module:core
* @dev Hashing function used to (re)build the proposal id from the proposal details..
*/
function hashProposal(
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas,
bytes32 descriptionHash
) external pure returns (uint256);
/**
* @notice module:core
* @dev Current state of a proposal, following Compound's convention
*/
function state(uint256 proposalId) external view returns (ProposalState);
/**
* @notice module:core
* @dev The number of votes required in order for a voter to become a proposer.
*/
function proposalThreshold() external view returns (uint256);
/**
* @notice module:core
* @dev Timepoint used to retrieve user's votes and quorum. If using block number (as per Compound's Comp), the
* snapshot is performed at the end of this block. Hence, voting for this proposal starts at the beginning of the
* following block.
*/
function proposalSnapshot(uint256 proposalId) external view returns (uint256);
/**
* @notice module:core
* @dev Timepoint at which votes close. If using block number, votes close at the end of this block, so it is
* possible to cast a vote during this block.
*/
function proposalDeadline(uint256 proposalId) external view returns (uint256);
/**
* @notice module:core
* @dev The account that created a proposal.
*/
function proposalProposer(uint256 proposalId) external view returns (address);
/**
* @notice module:core
* @dev The time when a queued proposal becomes executable ("ETA"). Unlike {proposalSnapshot} and
* {proposalDeadline}, this doesn't use the governor clock, and instead relies on the executor's clock which may be
* different. In most cases this will be a timestamp.
*/
function proposalEta(uint256 proposalId) external view returns (uint256);
/**
* @notice module:core
* @dev Whether a proposal needs to be queued before execution.
*/
function proposalNeedsQueuing(uint256 proposalId) external view returns (bool);
/**
* @notice module:user-config
* @dev Delay, between the proposal is created and the vote starts. The unit this duration is expressed in depends
* on the clock (see EIP-6372) this contract uses.
*
* This can be increased to leave time for users to buy voting power, or delegate it, before the voting of a
* proposal starts.
*
* NOTE: While this interface returns a uint256, timepoints are stored as uint48 following the ERC-6372 clock type.
* Consequently this value must fit in a uint48 (when added to the current clock). See {IERC6372-clock}.
*/
function votingDelay() external view returns (uint256);
/**
* @notice module:user-config
* @dev Delay between the vote start and vote end. The unit this duration is expressed in depends on the clock
* (see EIP-6372) this contract uses.
*
* NOTE: The {votingDelay} can delay the start of the vote. This must be considered when setting the voting
* duration compared to the voting delay.
*
* NOTE: This value is stored when the proposal is submitted so that possible changes to the value do not affect
* proposals that have already been submitted. The type used to save it is a uint32. Consequently, while this
* interface returns a uint256, the value it returns should fit in a uint32.
*/
function votingPeriod() external view returns (uint256);
/**
* @notice module:user-config
* @dev Minimum number of cast voted required for a proposal to be successful.
*
* NOTE: The `timepoint` parameter corresponds to the snapshot used for counting vote. This allows to scale the
* quorum depending on values such as the totalSupply of a token at this timepoint (see {ERC20Votes}).
*/
function quorum(uint256 timepoint) external view returns (uint256);
/**
* @notice module:reputation
* @dev Voting power of an `account` at a specific `timepoint`.
*
* Note: this can be implemented in a number of ways, for example by reading the delegated balance from one (or
* multiple), {ERC20Votes} tokens.
*/
function getVotes(address account, uint256 timepoint) external view returns (uint256);
/**
* @notice module:reputation
* @dev Voting power of an `account` at a specific `timepoint` given additional encoded parameters.
*/
function getVotesWithParams(
address account,
uint256 timepoint,
bytes memory params
) external view returns (uint256);
/**
* @notice module:voting
* @dev Returns whether `account` has cast a vote on `proposalId`.
*/
function hasVoted(uint256 proposalId, address account) external view returns (bool);
/**
* @dev Create a new proposal. Vote start after a delay specified by {IGovernor-votingDelay} and lasts for a
* duration specified by {IGovernor-votingPeriod}.
*
* Emits a {ProposalCreated} event.
*/
function propose(
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas,
string memory description
) external returns (uint256 proposalId);
/**
* @dev Queue a proposal. Some governors require this step to be performed before execution can happen. If queuing
* is not necessary, this function may revert.
* Queuing a proposal requires the quorum to be reached, the vote to be successful, and the deadline to be reached.
*
* Emits a {ProposalQueued} event.
*/
function queue(
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas,
bytes32 descriptionHash
) external returns (uint256 proposalId);
/**
* @dev Execute a successful proposal. This requires the quorum to be reached, the vote to be successful, and the
* deadline to be reached. Depending on the governor it might also be required that the proposal was queued and
* that some delay passed.
*
* Emits a {ProposalExecuted} event.
*
* NOTE: Some modules can modify the requirements for execution, for example by adding an additional timelock.
*/
function execute(
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas,
bytes32 descriptionHash
) external payable returns (uint256 proposalId);
/**
* @dev Cancel a proposal. A proposal is cancellable by the proposer, but only while it is Pending state, i.e.
* before the vote starts.
*
* Emits a {ProposalCanceled} event.
*/
function cancel(
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas,
bytes32 descriptionHash
) external returns (uint256 proposalId);
/**
* @dev Cast a vote
*
* Emits a {VoteCast} event.
*/
function castVote(uint256 proposalId, uint8 support) external returns (uint256 balance);
/**
* @dev Cast a vote with a reason
*
* Emits a {VoteCast} event.
*/
function castVoteWithReason(
uint256 proposalId,
uint8 support,
string calldata reason
) external returns (uint256 balance);
/**
* @dev Cast a vote with a reason and additional encoded parameters
*
* Emits a {VoteCast} or {VoteCastWithParams} event depending on the length of params.
*/
function castVoteWithReasonAndParams(
uint256 proposalId,
uint8 support,
string calldata reason,
bytes memory params
) external returns (uint256 balance);
/**
* @dev Cast a vote using the voter's signature, including ERC-1271 signature support.
*
* Emits a {VoteCast} event.
*/
function castVoteBySig(
uint256 proposalId,
uint8 support,
address voter,
bytes memory signature
) external returns (uint256 balance);
/**
* @dev Cast a vote with a reason and additional encoded parameters using the voter's signature,
* including ERC-1271 signature support.
*
* Emits a {VoteCast} or {VoteCastWithParams} event depending on the length of params.
*/
function castVoteWithReasonAndParamsBySig(
uint256 proposalId,
uint8 support,
address voter,
string calldata reason,
bytes memory params,
bytes memory signature
) external returns (uint256 balance);
}// 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: Apache 2
pragma solidity ^0.8.23;
import {IGovernor} from "@openzeppelin/contracts/governance/IGovernor.sol";
import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol";
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {
QueryResponse,
ParsedPerChainQueryResponse,
EthCallData,
EthCallWithFinalityQueryResponse,
InvalidContractAddress,
InvalidFunctionSignature
} from "wormhole-sdk/QueryResponse.sol";
import {fromWormholeFormat} from "wormhole-sdk/Utils.sol";
import {HubVotePool} from "src/HubVotePool.sol";
import {ISpokeVoteDecoder} from "src/interfaces/ISpokeVoteDecoder.sol";
import {BytesParsing} from "wormhole-sdk/libraries/BytesParsing.sol";
/// @title HubEvmSpokeVoteDecoder
/// @author [ScopeLift](https://scopelift.co)
/// @notice A contract that parses a specific wormhole query type from the `SpokeVoteAggregator`.
contract HubEvmSpokeVoteDecoder is ISpokeVoteDecoder, QueryResponse, ERC165 {
using BytesParsing for bytes;
/// @notice The hub vote pool used to validate message emitter.
HubVotePool public immutable HUB_VOTE_POOL;
/// @notice The expected finality for an EVM query.
bytes9 constant REQUEST_FINALITY = bytes9("finalized");
/// @param _core The Wormhole core contract for the hub chain.
/// @param _hubVotePool The address for the hub vote pool.
constructor(address _core, address _hubVotePool) QueryResponse(_core) {
HUB_VOTE_POOL = HubVotePool(_hubVotePool);
}
/// @notice Decodes a parsed per chain query respone for an eth call with finality query containing a spoke vote.
/// @param _perChainResp The parsed per chain response.
/// @param _governor The governor used to fetch a registered spoke.
/// @return The parsed query vote.
function decode(ParsedPerChainQueryResponse memory _perChainResp, IGovernor _governor)
external
view
returns (QueryVote memory)
{
EthCallWithFinalityQueryResponse memory _ethCalls = parseEthCallWithFinalityQueryResponse(_perChainResp);
// verify contract and chain is correct
if (_ethCalls.result.length != 1) revert TooManyEthCallResults(_ethCalls.result.length);
_validateEthCallData(_ethCalls.result[0]);
_ethCalls.requestFinality.checkLength(9);
if (bytes9(_ethCalls.requestFinality) != REQUEST_FINALITY) revert InvalidQueryBlock(_ethCalls.requestBlockId);
_ethCalls.result[0].result.checkLength(128);
(uint256 _proposalId, uint256 _againstVotes, uint256 _forVotes, uint256 _abstainVotes) =
abi.decode(_ethCalls.result[0].result, (uint256, uint256, uint256, uint256));
uint256 _voteStart = _governor.proposalSnapshot(_proposalId);
bytes32 _registeredAddress = HUB_VOTE_POOL.getSpoke(_perChainResp.chainId, _voteStart);
if (
_registeredAddress == bytes32("") || _ethCalls.result[0].contractAddress != fromWormholeFormat(_registeredAddress)
) revert InvalidContractAddress();
bytes32 _spokeProposalId = keccak256(abi.encode(_perChainResp.chainId, _proposalId));
return (
QueryVote({
proposalId: _proposalId,
spokeProposalId: _spokeProposalId,
proposalVote: ProposalVote(_againstVotes, _forVotes, _abstainVotes),
chainId: _perChainResp.chainId
})
);
}
/// @notice An ERC165 compatible method that validates the various interfaces this contract supports.
/// @param _interfaceId The id of the interface that is checked.
/// @return Whether the interface id is supported.
function supportsInterface(bytes4 _interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
return _interfaceId == type(ISpokeVoteDecoder).interfaceId || ERC165.supportsInterface(_interfaceId);
}
/// @notice Validate the query eth calldata was from the expected spoke contract and contains the expected function
/// signature.
/// @param _r The Eth calldata of the query.
function _validateEthCallData(EthCallData memory _r) internal pure {
(bytes4 funcSig,) = _r.callData.asBytes4Unchecked(0);
// The function signature should be bytes4(keccak256(bytes("proposalVotes(uint256)")))
if (funcSig != bytes4(hex"544ffc9c")) revert InvalidFunctionSignature();
}
}// contracts/Messages.sol
// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.0;
interface IWormhole {
struct GuardianSet {
address[] keys;
uint32 expirationTime;
}
struct Signature {
bytes32 r;
bytes32 s;
uint8 v;
uint8 guardianIndex;
}
struct VM {
uint8 version;
uint32 timestamp;
uint32 nonce;
uint16 emitterChainId;
bytes32 emitterAddress;
uint64 sequence;
uint8 consistencyLevel;
bytes payload;
uint32 guardianSetIndex;
Signature[] signatures;
bytes32 hash;
}
struct ContractUpgrade {
bytes32 module;
uint8 action;
uint16 chain;
address newContract;
}
struct GuardianSetUpgrade {
bytes32 module;
uint8 action;
uint16 chain;
GuardianSet newGuardianSet;
uint32 newGuardianSetIndex;
}
struct SetMessageFee {
bytes32 module;
uint8 action;
uint16 chain;
uint256 messageFee;
}
struct TransferFees {
bytes32 module;
uint8 action;
uint16 chain;
uint256 amount;
bytes32 recipient;
}
struct RecoverChainId {
bytes32 module;
uint8 action;
uint256 evmChainId;
uint16 newChainId;
}
event LogMessagePublished(
address indexed sender, uint64 sequence, uint32 nonce, bytes payload, uint8 consistencyLevel
);
event ContractUpgraded(address indexed oldContract, address indexed newContract);
event GuardianSetAdded(uint32 indexed index);
function publishMessage(uint32 nonce, bytes memory payload, uint8 consistencyLevel)
external
payable
returns (uint64 sequence);
function initialize() external;
function parseAndVerifyVM(bytes calldata encodedVM)
external
view
returns (VM memory vm, bool valid, string memory reason);
function verifyVM(VM memory vm) external view returns (bool valid, string memory reason);
function verifySignatures(bytes32 hash, Signature[] memory signatures, GuardianSet memory guardianSet)
external
pure
returns (bool valid, string memory reason);
function parseVM(bytes memory encodedVM) external pure returns (VM memory vm);
function quorum(uint256 numGuardians) external pure returns (uint256 numSignaturesRequiredForQuorum);
function getGuardianSet(uint32 index) external view returns (GuardianSet memory);
function getCurrentGuardianSetIndex() external view returns (uint32);
function getGuardianSetExpiry() external view returns (uint32);
function governanceActionIsConsumed(bytes32 hash) external view returns (bool);
function isInitialized(address impl) external view returns (bool);
function chainId() external view returns (uint16);
function isFork() external view returns (bool);
function governanceChainId() external view returns (uint16);
function governanceContract() external view returns (bytes32);
function messageFee() external view returns (uint256);
function evmChainId() external view returns (uint256);
function nextSequence(address emitter) external view returns (uint64);
function parseContractUpgrade(bytes memory encodedUpgrade) external pure returns (ContractUpgrade memory cu);
function parseGuardianSetUpgrade(bytes memory encodedUpgrade)
external
pure
returns (GuardianSetUpgrade memory gsu);
function parseSetMessageFee(bytes memory encodedSetMessageFee) external pure returns (SetMessageFee memory smf);
function parseTransferFees(bytes memory encodedTransferFees) external pure returns (TransferFees memory tf);
function parseRecoverChainId(bytes memory encodedRecoverChainId)
external
pure
returns (RecoverChainId memory rci);
function submitContractUpgrade(bytes memory _vm) external;
function submitSetMessageFee(bytes memory _vm) external;
function submitNewGuardianSet(bytes memory _vm) external;
function submitTransferFees(bytes memory _vm) external;
function submitRecoverChainId(bytes memory _vm) external;
}// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.4;
import {BytesParsing} from "./libraries/BytesParsing.sol";
import "./interfaces/IWormhole.sol";
// @dev ParsedQueryResponse is returned by QueryResponse.parseAndVerifyQueryResponse().
struct ParsedQueryResponse {
uint8 version;
uint16 senderChainId;
uint32 nonce;
bytes requestId; // 65 byte sig for off-chain, 32 byte vaaHash for on-chain
ParsedPerChainQueryResponse [] responses;
}
// @dev ParsedPerChainQueryResponse describes a single per-chain response.
struct ParsedPerChainQueryResponse {
uint16 chainId;
uint8 queryType;
bytes request;
bytes response;
}
// @dev EthCallQueryResponse describes the response to an ETH call per-chain query.
struct EthCallQueryResponse {
bytes requestBlockId;
uint64 blockNum;
uint64 blockTime;
bytes32 blockHash;
EthCallData [] result;
}
// @dev EthCallByTimestampQueryResponse describes the response to an ETH call by timestamp per-chain query.
struct EthCallByTimestampQueryResponse {
bytes requestTargetBlockIdHint;
bytes requestFollowingBlockIdHint;
uint64 requestTargetTimestamp;
uint64 targetBlockNum;
uint64 targetBlockTime;
uint64 followingBlockNum;
bytes32 targetBlockHash;
bytes32 followingBlockHash;
uint64 followingBlockTime;
EthCallData [] result;
}
// @dev EthCallWithFinalityQueryResponse describes the response to an ETH call with finality per-chain query.
struct EthCallWithFinalityQueryResponse {
bytes requestBlockId;
bytes requestFinality;
uint64 blockNum;
uint64 blockTime;
bytes32 blockHash;
EthCallData [] result;
}
// @dev EthCallData describes a single ETH call query / response pair.
struct EthCallData {
address contractAddress;
bytes callData;
bytes result;
}
// @dev SolanaAccountQueryResponse describes the response to a Solana Account query per-chain query.
struct SolanaAccountQueryResponse {
bytes requestCommitment;
uint64 requestMinContextSlot;
uint64 requestDataSliceOffset;
uint64 requestDataSliceLength;
uint64 slotNumber;
uint64 blockTime;
bytes32 blockHash;
SolanaAccountResult [] results;
}
// @dev SolanaAccountResult describes a single Solana Account query result.
struct SolanaAccountResult {
bytes32 account;
uint64 lamports;
uint64 rentEpoch;
bool executable;
bytes32 owner;
bytes data;
}
// @dev SolanaPdaQueryResponse describes the response to a Solana PDA (Program Derived Address) query per-chain query.
struct SolanaPdaQueryResponse {
bytes requestCommitment;
uint64 requestMinContextSlot;
uint64 requestDataSliceOffset;
uint64 requestDataSliceLength;
uint64 slotNumber;
uint64 blockTime;
bytes32 blockHash;
SolanaPdaResult [] results;
}
// @dev SolanaPdaResult describes a single Solana PDA (Program Derived Address) query result.
struct SolanaPdaResult {
bytes32 programId;
bytes[] seeds;
bytes32 account;
uint64 lamports;
uint64 rentEpoch;
bool executable;
bytes32 owner;
bytes data;
uint8 bump;
}
// Custom errors
error EmptyWormholeAddress();
error InvalidResponseVersion();
error VersionMismatch();
error ZeroQueries();
error NumberOfResponsesMismatch();
error ChainIdMismatch();
error RequestTypeMismatch();
error UnsupportedQueryType(uint8 received);
error WrongQueryType(uint8 received, uint8 expected);
error UnexpectedNumberOfResults();
error InvalidPayloadLength(uint256 received, uint256 expected);
error InvalidContractAddress();
error InvalidFunctionSignature();
error InvalidChainId();
error StaleBlockNum();
error StaleBlockTime();
// @dev QueryResponse is a library that implements the parsing and verification of Cross Chain Query (CCQ) responses.
// For a detailed discussion of these query responses, please see the white paper:
// https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0013_ccq.md
abstract contract QueryResponse {
using BytesParsing for bytes;
IWormhole public immutable wormhole;
bytes public constant responsePrefix = bytes("query_response_0000000000000000000|");
uint8 public constant VERSION = 1;
// TODO: Consider changing these to an enum.
uint8 public constant QT_ETH_CALL = 1;
uint8 public constant QT_ETH_CALL_BY_TIMESTAMP = 2;
uint8 public constant QT_ETH_CALL_WITH_FINALITY = 3;
uint8 public constant QT_SOL_ACCOUNT = 4;
uint8 public constant QT_SOL_PDA = 5;
uint8 public constant QT_MAX = 6; // Keep this last
constructor(address _wormhole) {
if (_wormhole == address(0)) {
revert EmptyWormholeAddress();
}
wormhole = IWormhole(_wormhole);
}
/// @dev getResponseHash computes the hash of the specified query response.
function getResponseHash(bytes memory response) public pure returns (bytes32) {
return keccak256(response);
}
/// @dev getResponseDigest computes the digest of the specified query response.
function getResponseDigest(bytes memory response) public pure returns (bytes32) {
return keccak256(abi.encodePacked(responsePrefix,getResponseHash(response)));
}
/// @dev parseAndVerifyQueryResponse verifies the query response and returns the parsed response.
function parseAndVerifyQueryResponse(bytes memory response, IWormhole.Signature[] memory signatures) public view returns (ParsedQueryResponse memory r) {
verifyQueryResponseSignatures(response, signatures);
uint index;
(r.version, index) = response.asUint8Unchecked(index);
if (r.version != VERSION) {
revert InvalidResponseVersion();
}
(r.senderChainId, index) = response.asUint16Unchecked(index);
// For off chain requests (chainID zero), the requestId is the 65 byte signature. For on chain requests, it is the 32 byte VAA hash.
if (r.senderChainId == 0) {
(r.requestId, index) = response.sliceUnchecked(index, 65);
} else {
(r.requestId, index) = response.sliceUnchecked(index, 32);
}
uint32 len;
(len, index) = response.asUint32Unchecked(index); // query_request_len
uint reqIdx = index;
// Scope to avoid stack-too-deep error
{
uint8 version;
(version, reqIdx) = response.asUint8Unchecked(reqIdx);
if (version != r.version) {
revert VersionMismatch();
}
}
(r.nonce, reqIdx) = response.asUint32Unchecked(reqIdx);
uint8 numPerChainQueries;
(numPerChainQueries, reqIdx) = response.asUint8Unchecked(reqIdx);
// A valid query request has at least one per chain query
if (numPerChainQueries == 0) {
revert ZeroQueries();
}
// The response starts after the request.
uint respIdx = index + len;
uint startOfResponse = respIdx;
uint8 respNumPerChainQueries;
(respNumPerChainQueries, respIdx) = response.asUint8Unchecked(respIdx);
if (respNumPerChainQueries != numPerChainQueries) {
revert NumberOfResponsesMismatch();
}
r.responses = new ParsedPerChainQueryResponse[](numPerChainQueries);
// Walk through the requests and responses in lock step.
for (uint idx; idx < numPerChainQueries;) {
(r.responses[idx].chainId, reqIdx) = response.asUint16Unchecked(reqIdx);
uint16 respChainId;
(respChainId, respIdx) = response.asUint16Unchecked(respIdx);
if (respChainId != r.responses[idx].chainId) {
revert ChainIdMismatch();
}
(r.responses[idx].queryType, reqIdx) = response.asUint8Unchecked(reqIdx);
uint8 respQueryType;
(respQueryType, respIdx) = response.asUint8Unchecked(respIdx);
if (respQueryType != r.responses[idx].queryType) {
revert RequestTypeMismatch();
}
if (r.responses[idx].queryType < QT_ETH_CALL || r.responses[idx].queryType >= QT_MAX) {
revert UnsupportedQueryType(r.responses[idx].queryType);
}
(len, reqIdx) = response.asUint32Unchecked(reqIdx);
(r.responses[idx].request, reqIdx) = response.sliceUnchecked(reqIdx, len);
(len, respIdx) = response.asUint32Unchecked(respIdx);
(r.responses[idx].response, respIdx) = response.sliceUnchecked(respIdx, len);
unchecked { ++idx; }
}
// End of request body should align with start of response body
if (startOfResponse != reqIdx) {
revert InvalidPayloadLength(startOfResponse, reqIdx);
}
checkLength(response, respIdx);
return r;
}
/// @dev parseEthCallQueryResponse parses a ParsedPerChainQueryResponse for an ETH call per-chain query.
function parseEthCallQueryResponse(ParsedPerChainQueryResponse memory pcr) public pure returns (EthCallQueryResponse memory r) {
if (pcr.queryType != QT_ETH_CALL) {
revert WrongQueryType(pcr.queryType, QT_ETH_CALL);
}
uint reqIdx;
uint respIdx;
uint32 len;
(len, reqIdx) = pcr.request.asUint32Unchecked(reqIdx); // block_id_len
(r.requestBlockId, reqIdx) = pcr.request.sliceUnchecked(reqIdx, len);
uint8 numBatchCallData;
(numBatchCallData, reqIdx) = pcr.request.asUint8Unchecked(reqIdx);
(r.blockNum, respIdx) = pcr.response.asUint64Unchecked(respIdx);
(r.blockHash, respIdx) = pcr.response.asBytes32Unchecked(respIdx);
(r.blockTime, respIdx) = pcr.response.asUint64Unchecked(respIdx);
uint8 respNumResults;
(respNumResults, respIdx) = pcr.response.asUint8Unchecked(respIdx);
if (respNumResults != numBatchCallData) {
revert UnexpectedNumberOfResults();
}
r.result = new EthCallData[](numBatchCallData);
// Walk through the call data and results in lock step.
for (uint idx; idx < numBatchCallData;) {
(r.result[idx].contractAddress, reqIdx) = pcr.request.asAddressUnchecked(reqIdx);
(len, reqIdx) = pcr.request.asUint32Unchecked(reqIdx); // call_data_len
(r.result[idx].callData, reqIdx) = pcr.request.sliceUnchecked(reqIdx, len);
(len, respIdx) = pcr.response.asUint32Unchecked(respIdx); // result_len
(r.result[idx].result, respIdx) = pcr.response.sliceUnchecked(respIdx, len);
unchecked { ++idx; }
}
checkLength(pcr.request, reqIdx);
checkLength(pcr.response, respIdx);
return r;
}
/// @dev parseEthCallByTimestampQueryResponse parses a ParsedPerChainQueryResponse for an ETH call per-chain query.
function parseEthCallByTimestampQueryResponse(ParsedPerChainQueryResponse memory pcr) public pure returns (EthCallByTimestampQueryResponse memory r) {
if (pcr.queryType != QT_ETH_CALL_BY_TIMESTAMP) {
revert WrongQueryType(pcr.queryType, QT_ETH_CALL_BY_TIMESTAMP);
}
uint reqIdx;
uint respIdx;
uint32 len;
(r.requestTargetTimestamp, reqIdx) = pcr.request.asUint64Unchecked(reqIdx); // Request target_time_us
(len, reqIdx) = pcr.request.asUint32Unchecked(reqIdx); // Request target_block_id_hint_len
(r.requestTargetBlockIdHint, reqIdx) = pcr.request.sliceUnchecked(reqIdx, len); // Request target_block_id_hint
(len, reqIdx) = pcr.request.asUint32Unchecked(reqIdx); // following_block_id_hint_len
(r.requestFollowingBlockIdHint, reqIdx) = pcr.request.sliceUnchecked(reqIdx, len); // Request following_block_id_hint
uint8 numBatchCallData;
(numBatchCallData, reqIdx) = pcr.request.asUint8Unchecked(reqIdx); // Request num_batch_call_data
(r.targetBlockNum, respIdx) = pcr.response.asUint64Unchecked(respIdx); // Response target_block_number
(r.targetBlockHash, respIdx) = pcr.response.asBytes32Unchecked(respIdx); // Response target_block_hash
(r.targetBlockTime, respIdx) = pcr.response.asUint64Unchecked(respIdx); // Response target_block_time_us
(r.followingBlockNum, respIdx) = pcr.response.asUint64Unchecked(respIdx); // Response following_block_number
(r.followingBlockHash, respIdx) = pcr.response.asBytes32Unchecked(respIdx); // Response following_block_hash
(r.followingBlockTime, respIdx) = pcr.response.asUint64Unchecked(respIdx); // Response following_block_time_us
uint8 respNumResults;
(respNumResults, respIdx) = pcr.response.asUint8Unchecked(respIdx); // Response num_results
if (respNumResults != numBatchCallData) {
revert UnexpectedNumberOfResults();
}
r.result = new EthCallData[](numBatchCallData);
// Walk through the call data and results in lock step.
for (uint idx; idx < numBatchCallData;) {
(r.result[idx].contractAddress, reqIdx) = pcr.request.asAddressUnchecked(reqIdx);
(len, reqIdx) = pcr.request.asUint32Unchecked(reqIdx); // call_data_len
(r.result[idx].callData, reqIdx) = pcr.request.sliceUnchecked(reqIdx, len);
(len, respIdx) = pcr.response.asUint32Unchecked(respIdx); // result_len
(r.result[idx].result, respIdx) = pcr.response.sliceUnchecked(respIdx, len);
unchecked { ++idx; }
}
checkLength(pcr.request, reqIdx);
checkLength(pcr.response, respIdx);
}
/// @dev parseEthCallWithFinalityQueryResponse parses a ParsedPerChainQueryResponse for an ETH call per-chain query.
function parseEthCallWithFinalityQueryResponse(ParsedPerChainQueryResponse memory pcr) public pure returns (EthCallWithFinalityQueryResponse memory r) {
if (pcr.queryType != QT_ETH_CALL_WITH_FINALITY) {
revert WrongQueryType(pcr.queryType, QT_ETH_CALL_WITH_FINALITY);
}
uint reqIdx;
uint respIdx;
uint32 len;
(len, reqIdx) = pcr.request.asUint32Unchecked(reqIdx); // Request block_id_len
(r.requestBlockId, reqIdx) = pcr.request.sliceUnchecked(reqIdx, len); // Request block_id
(len, reqIdx) = pcr.request.asUint32Unchecked(reqIdx); // Request finality_len
(r.requestFinality, reqIdx) = pcr.request.sliceUnchecked(reqIdx, len); // Request finality
uint8 numBatchCallData;
(numBatchCallData, reqIdx) = pcr.request.asUint8Unchecked(reqIdx); // Request num_batch_call_data
(r.blockNum, respIdx) = pcr.response.asUint64Unchecked(respIdx); // Response block_number
(r.blockHash, respIdx) = pcr.response.asBytes32Unchecked(respIdx); // Response block_hash
(r.blockTime, respIdx) = pcr.response.asUint64Unchecked(respIdx); // Response block_time_us
uint8 respNumResults;
(respNumResults, respIdx) = pcr.response.asUint8Unchecked(respIdx); // Response num_results
if (respNumResults != numBatchCallData) {
revert UnexpectedNumberOfResults();
}
r.result = new EthCallData[](numBatchCallData);
// Walk through the call data and results in lock step.
for (uint idx; idx < numBatchCallData;) {
(r.result[idx].contractAddress, reqIdx) = pcr.request.asAddressUnchecked(reqIdx);
(len, reqIdx) = pcr.request.asUint32Unchecked(reqIdx); // call_data_len
(r.result[idx].callData, reqIdx) = pcr.request.sliceUnchecked(reqIdx, len);
(len, respIdx) = pcr.response.asUint32Unchecked(respIdx); // result_len
(r.result[idx].result, respIdx) = pcr.response.sliceUnchecked(respIdx, len);
unchecked { ++idx; }
}
checkLength(pcr.request, reqIdx);
checkLength(pcr.response, respIdx);
}
/// @dev parseSolanaAccountQueryResponse parses a ParsedPerChainQueryResponse for a Solana Account per-chain query.
function parseSolanaAccountQueryResponse(ParsedPerChainQueryResponse memory pcr) public pure returns (SolanaAccountQueryResponse memory r) {
if (pcr.queryType != QT_SOL_ACCOUNT) {
revert WrongQueryType(pcr.queryType, QT_SOL_ACCOUNT);
}
uint reqIdx;
uint respIdx;
uint32 len;
(len, reqIdx) = pcr.request.asUint32Unchecked(reqIdx); // Request commitment_len
(r.requestCommitment, reqIdx) = pcr.request.sliceUnchecked(reqIdx, len); // Request commitment
(r.requestMinContextSlot, reqIdx) = pcr.request.asUint64Unchecked(reqIdx); // Request min_context_slot
(r.requestDataSliceOffset, reqIdx) = pcr.request.asUint64Unchecked(reqIdx); // Request data_slice_offset
(r.requestDataSliceLength, reqIdx) = pcr.request.asUint64Unchecked(reqIdx); // Request data_slice_length
uint8 numAccounts;
(numAccounts, reqIdx) = pcr.request.asUint8Unchecked(reqIdx); // Request num_accounts
(r.slotNumber, respIdx) = pcr.response.asUint64Unchecked(respIdx); // Response slot_number
(r.blockTime, respIdx) = pcr.response.asUint64Unchecked(respIdx); // Response block_time_us
(r.blockHash, respIdx) = pcr.response.asBytes32Unchecked(respIdx); // Response block_hash
uint8 respNumResults;
(respNumResults, respIdx) = pcr.response.asUint8Unchecked(respIdx); // Response num_results
if (respNumResults != numAccounts) {
revert UnexpectedNumberOfResults();
}
r.results = new SolanaAccountResult[](numAccounts);
// Walk through the call data and results in lock step.
for (uint idx; idx < numAccounts;) {
(r.results[idx].account, reqIdx) = pcr.request.asBytes32Unchecked(reqIdx); // Request account
(r.results[idx].lamports, respIdx) = pcr.response.asUint64Unchecked(respIdx); // Response lamports
(r.results[idx].rentEpoch, respIdx) = pcr.response.asUint64Unchecked(respIdx); // Response rent_epoch
(r.results[idx].executable, respIdx) = pcr.response.asBoolUnchecked(respIdx); // Response executable
(r.results[idx].owner, respIdx) = pcr.response.asBytes32Unchecked(respIdx); // Response owner
(len, respIdx) = pcr.response.asUint32Unchecked(respIdx); // result_len
(r.results[idx].data, respIdx) = pcr.response.sliceUnchecked(respIdx, len);
unchecked { ++idx; }
}
checkLength(pcr.request, reqIdx);
checkLength(pcr.response, respIdx);
}
/// @dev parseSolanaPdaQueryResponse parses a ParsedPerChainQueryResponse for a Solana Pda per-chain query.
function parseSolanaPdaQueryResponse(ParsedPerChainQueryResponse memory pcr) public pure returns (SolanaPdaQueryResponse memory r) {
if (pcr.queryType != QT_SOL_PDA) {
revert WrongQueryType(pcr.queryType, QT_SOL_PDA);
}
uint reqIdx;
uint respIdx;
uint32 len;
(len, reqIdx) = pcr.request.asUint32Unchecked(reqIdx); // Request commitment_len
(r.requestCommitment, reqIdx) = pcr.request.sliceUnchecked(reqIdx, len); // Request commitment
(r.requestMinContextSlot, reqIdx) = pcr.request.asUint64Unchecked(reqIdx); // Request min_context_slot
(r.requestDataSliceOffset, reqIdx) = pcr.request.asUint64Unchecked(reqIdx); // Request data_slice_offset
(r.requestDataSliceLength, reqIdx) = pcr.request.asUint64Unchecked(reqIdx); // Request data_slice_length
uint8 numPdas;
(numPdas, reqIdx) = pcr.request.asUint8Unchecked(reqIdx); // Request num_Pdas
(r.slotNumber, respIdx) = pcr.response.asUint64Unchecked(respIdx); // Response slot_number
(r.blockTime, respIdx) = pcr.response.asUint64Unchecked(respIdx); // Response block_time_us
(r.blockHash, respIdx) = pcr.response.asBytes32Unchecked(respIdx); // Response block_hash
uint8 respNumResults;
(respNumResults, respIdx) = pcr.response.asUint8Unchecked(respIdx); // Response num_results
if (respNumResults != numPdas) {
revert UnexpectedNumberOfResults();
}
r.results = new SolanaPdaResult[](numPdas);
// Walk through the call data and results in lock step.
for (uint idx; idx < numPdas;) {
(r.results[idx].programId, reqIdx) = pcr.request.asBytes32Unchecked(reqIdx); // Request programId
uint8 numSeeds; // Request number of seeds
(numSeeds, reqIdx) = pcr.request.asUint8Unchecked(reqIdx);
r.results[idx].seeds = new bytes[](numSeeds);
for (uint idx2; idx2 < numSeeds;) {
uint32 seedLen;
(seedLen, reqIdx) = pcr.request.asUint32Unchecked(reqIdx);
(r.results[idx].seeds[idx2], reqIdx) = pcr.request.sliceUnchecked(reqIdx, seedLen);
unchecked { ++idx2; }
}
(r.results[idx].account, respIdx) = pcr.response.asBytes32Unchecked(respIdx); // Response account
(r.results[idx].bump, respIdx) = pcr.response.asUint8Unchecked(respIdx); // Response bump
(r.results[idx].lamports, respIdx) = pcr.response.asUint64Unchecked(respIdx); // Response lamports
(r.results[idx].rentEpoch, respIdx) = pcr.response.asUint64Unchecked(respIdx); // Response rent_epoch
(r.results[idx].executable, respIdx) = pcr.response.asBoolUnchecked(respIdx); // Response executable
(r.results[idx].owner, respIdx) = pcr.response.asBytes32Unchecked(respIdx); // Response owner
(len, respIdx) = pcr.response.asUint32Unchecked(respIdx); // result_len
(r.results[idx].data, respIdx) = pcr.response.sliceUnchecked(respIdx, len);
unchecked { ++idx; }
}
checkLength(pcr.request, reqIdx);
checkLength(pcr.response, respIdx);
}
/// @dev validateBlockTime validates that the parsed block time isn't stale
/// @param _blockTime Wormhole block time in MICROseconds
/// @param _minBlockTime Minium block time in seconds
function validateBlockTime(uint64 _blockTime, uint256 _minBlockTime) public pure {
uint256 blockTimeInSeconds = _blockTime / 1_000_000; // Rounds down
if (blockTimeInSeconds < _minBlockTime) {
revert StaleBlockTime();
}
}
/// @dev validateBlockNum validates that the parsed blockNum isn't stale
function validateBlockNum(uint64 _blockNum, uint256 _minBlockNum) public pure {
if (_blockNum < _minBlockNum) {
revert StaleBlockNum();
}
}
/// @dev validateChainId validates that the parsed chainId is one of an array of chainIds we expect
function validateChainId(uint16 chainId, uint16[] memory _validChainIds) public pure {
bool validChainId = false;
uint256 numChainIds = _validChainIds.length;
for (uint256 idx; idx < numChainIds;) {
if (chainId == _validChainIds[idx]) {
validChainId = true;
break;
}
unchecked { ++idx; }
}
if (!validChainId) revert InvalidChainId();
}
/// @dev validateMutlipleEthCallData validates that each EthCallData in an array comes from a function signature and contract address we expect
function validateMultipleEthCallData(EthCallData[] memory r, address[] memory _expectedContractAddresses, bytes4[] memory _expectedFunctionSignatures) public pure {
uint256 callDatasLength = r.length;
for (uint256 idx; idx < callDatasLength;) {
validateEthCallData(r[idx], _expectedContractAddresses, _expectedFunctionSignatures);
unchecked { ++idx; }
}
}
/// @dev validateEthCallData validates that EthCallData comes from a function signature and contract address we expect
/// @dev An empty array means we accept all addresses/function signatures
/// @dev Example 1: To accept signatures 0xaaaaaaaa and 0xbbbbbbbb from `address(abcd)` you'd pass in [0xaaaaaaaa, 0xbbbbbbbb], [address(abcd)]
/// @dev Example 2: To accept any function signatures from `address(abcd)` or `address(efab)` you'd pass in [], [address(abcd), address(efab)]
/// @dev Example 3: To accept function signature 0xaaaaaaaa from any address you'd pass in [0xaaaaaaaa], []
/// @dev WARNING Example 4: If you want to accept signature 0xaaaaaaaa from `address(abcd)` and signature 0xbbbbbbbb from `address(efab)` the following input would be incorrect:
/// @dev [0xaaaaaaaa, 0xbbbbbbbb], [address(abcd), address(efab)]
/// @dev This would accept both 0xaaaaaaaa and 0xbbbbbbbb from `address(abcd)` AND `address(efab)`. Instead you should make 2 calls to this method
/// @dev using the pattern in Example 1. [0xaaaaaaaa], [address(abcd)] OR [0xbbbbbbbb], [address(efab)]
function validateEthCallData(EthCallData memory r, address[] memory _expectedContractAddresses, bytes4[] memory _expectedFunctionSignatures) public pure {
bool validContractAddress = _expectedContractAddresses.length == 0 ? true : false;
bool validFunctionSignature = _expectedFunctionSignatures.length == 0 ? true : false;
uint256 contractAddressesLength = _expectedContractAddresses.length;
// Check that the contract address called in the request is expected
for (uint256 idx; idx < contractAddressesLength;) {
if (r.contractAddress == _expectedContractAddresses[idx]) {
validContractAddress = true;
break;
}
unchecked { ++idx; }
}
// Early exit to save gas
if (!validContractAddress) {
revert InvalidContractAddress();
}
uint256 functionSignaturesLength = _expectedFunctionSignatures.length;
// Check that the function signature called is expected
for (uint256 idx; idx < functionSignaturesLength;) {
(bytes4 funcSig,) = r.callData.asBytes4Unchecked(0);
if (funcSig == _expectedFunctionSignatures[idx]) {
validFunctionSignature = true;
break;
}
unchecked { ++idx; }
}
if (!validFunctionSignature) {
revert InvalidFunctionSignature();
}
}
/**
* @dev verifyQueryResponseSignatures verifies the signatures on a query response. It calls into the Wormhole contract.
* IWormhole.Signature expects the last byte to be bumped by 27
* see https://github.com/wormhole-foundation/wormhole/blob/637b1ee657de7de05f783cbb2078dd7d8bfda4d0/ethereum/contracts/Messages.sol#L174
*/
function verifyQueryResponseSignatures(bytes memory response, IWormhole.Signature[] memory signatures) public view {
// It might be worth adding a verifyCurrentQuorum call on the core bridge so that there is only 1 cross call instead of 4.
uint32 gsi = wormhole.getCurrentGuardianSetIndex();
IWormhole.GuardianSet memory guardianSet = wormhole.getGuardianSet(gsi);
bytes32 responseHash = getResponseDigest(response);
/**
* @dev Checks whether the guardianSet has zero keys
* WARNING: This keys check is critical to ensure the guardianSet has keys present AND to ensure
* that guardianSet key size doesn't fall to zero and negatively impact quorum assessment. If guardianSet
* key length is 0 and vm.signatures length is 0, this could compromise the integrity of both vm and
* signature verification.
*/
if(guardianSet.keys.length == 0){
revert("invalid guardian set");
}
/**
* @dev We're using a fixed point number transformation with 1 decimal to deal with rounding.
* WARNING: This quorum check is critical to assessing whether we have enough Guardian signatures to validate a VM
* if making any changes to this, obtain additional peer review. If guardianSet key length is 0 and
* vm.signatures length is 0, this could compromise the integrity of both vm and signature verification.
*/
if (signatures.length < wormhole.quorum(guardianSet.keys.length)){
revert("no quorum");
}
/// @dev Verify the proposed vm.signatures against the guardianSet
(bool signaturesValid, string memory invalidReason) = wormhole.verifySignatures(responseHash, signatures, guardianSet);
if(!signaturesValid){
revert(invalidReason);
}
/// If we are here, we've validated the VM is a valid multi-sig that matches the current guardianSet.
}
/// @dev checkLength verifies that the message was fully consumed.
function checkLength(bytes memory encoded, uint256 expected) private pure {
if (encoded.length != expected) {
revert InvalidPayloadLength(encoded.length, expected);
}
}
}// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.23;
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
/// @dev This library was modified from Openzeppelin's Trace208 checkpoint library:
/// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/01ef448981be9d20ca85f2faf6ebdf591ce409f3/contracts/utils/structs/Checkpoints.sol#L22.
///
/// We removed the use of _unsafe access as the struct is now 2 slots.
library Checkpoints {
/**
* @dev A value was attempted to be inserted on a past checkpoint.
*/
error CheckpointUnorderedInsertion();
struct Trace256 {
Checkpoint256[] _checkpoints;
}
struct Checkpoint256 {
uint256 _key;
uint256 _value;
}
/**
* @dev Pushes a (`key`, `value`) pair into a Trace256 so that it is stored as the checkpoint.
*
* Returns previous value and new value.
*
* IMPORTANT: Never accept `key` as a user input, since an arbitrary `type(uint256).max` key set will disable the
* library.
*/
function push(Trace256 storage self, uint256 key, uint256 value) internal returns (uint256, uint256) {
return _insert(self._checkpoints, key, value);
}
/**
* @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero
* if there is none.
*/
function upperLookup(Trace256 storage self, uint256 key) internal view returns (uint256) {
uint256 len = self._checkpoints.length;
uint256 pos = _upperBinaryLookup(self._checkpoints, key, 0, len);
return pos == 0 ? 0 : self._checkpoints[pos - 1]._value;
}
/**
* @dev Pushes a (`key`, `value`) pair into an ordered list of checkpoints, either by inserting a new checkpoint,
* or by updating the last one.
*/
function _insert(Checkpoint256[] storage self, uint256 key, uint256 value) private returns (uint256, uint256) {
uint256 pos = self.length;
if (pos > 0) {
// Copying to memory is important here.
Checkpoint256 memory last = self[pos - 1];
// Checkpoint keys must be non-decreasing.
if (last._key > key) revert CheckpointUnorderedInsertion();
// Update or push new checkpoint
if (last._key == key) self[pos - 1]._value = value;
else self.push(Checkpoint256({_key: key, _value: value}));
return (last._value, value);
} else {
self.push(Checkpoint256({_key: key, _value: value}));
return (0, value);
}
}
/**
* @dev Return the index of the last (most recent) checkpoint with key lower or equal than the search key, or `high`
* if there is none. `low` and `high` define a section where to do the search, with inclusive `low` and exclusive
* `high`.
*
* WARNING: `high` should not be greater than the array's length.
*/
function _upperBinaryLookup(Checkpoint256[] storage self, uint256 key, uint256 low, uint256 high)
private
view
returns (uint256)
{
while (low < high) {
uint256 mid = Math.average(low, high);
if (self[mid]._key > key) high = mid;
else low = mid + 1;
}
return high;
}
}// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.23;
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {IGovernor} from "@openzeppelin/contracts/governance/IGovernor.sol";
import {ParsedPerChainQueryResponse} from "wormhole-sdk/QueryResponse.sol";
interface ISpokeVoteDecoder is IERC165 {
struct ProposalVote {
uint256 againstVotes;
uint256 forVotes;
uint256 abstainVotes;
}
struct QueryVote {
uint256 proposalId;
bytes32 spokeProposalId;
ProposalVote proposalVote;
uint16 chainId;
}
error TooManyEthCallResults(uint256);
error InvalidProposalVote();
error InvalidQueryBlock(bytes);
function decode(ParsedPerChainQueryResponse memory _queryResponse, IGovernor _governor)
external
view
returns (QueryVote memory);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.
pragma solidity ^0.8.20;
/**
* @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
* checks.
*
* Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
* easily result in undesired exploitation or bugs, since developers usually
* assume that overflows raise errors. `SafeCast` restores this intuition by
* reverting the transaction when such an operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeCast {
/**
* @dev Value doesn't fit in an uint of `bits` size.
*/
error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);
/**
* @dev An int value doesn't fit in an uint of `bits` size.
*/
error SafeCastOverflowedIntToUint(int256 value);
/**
* @dev Value doesn't fit in an int of `bits` size.
*/
error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);
/**
* @dev An uint value doesn't fit in an int of `bits` size.
*/
error SafeCastOverflowedUintToInt(uint256 value);
/**
* @dev Returns the downcasted uint248 from uint256, reverting on
* overflow (when the input is greater than largest uint248).
*
* Counterpart to Solidity's `uint248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*/
function toUint248(uint256 value) internal pure returns (uint248) {
if (value > type(uint248).max) {
revert SafeCastOverflowedUintDowncast(248, value);
}
return uint248(value);
}
/**
* @dev Returns the downcasted uint240 from uint256, reverting on
* overflow (when the input is greater than largest uint240).
*
* Counterpart to Solidity's `uint240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*/
function toUint240(uint256 value) internal pure returns (uint240) {
if (value > type(uint240).max) {
revert SafeCastOverflowedUintDowncast(240, value);
}
return uint240(value);
}
/**
* @dev Returns the downcasted uint232 from uint256, reverting on
* overflow (when the input is greater than largest uint232).
*
* Counterpart to Solidity's `uint232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*/
function toUint232(uint256 value) internal pure returns (uint232) {
if (value > type(uint232).max) {
revert SafeCastOverflowedUintDowncast(232, value);
}
return uint232(value);
}
/**
* @dev Returns the downcasted uint224 from uint256, reverting on
* overflow (when the input is greater than largest uint224).
*
* Counterpart to Solidity's `uint224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*/
function toUint224(uint256 value) internal pure returns (uint224) {
if (value > type(uint224).max) {
revert SafeCastOverflowedUintDowncast(224, value);
}
return uint224(value);
}
/**
* @dev Returns the downcasted uint216 from uint256, reverting on
* overflow (when the input is greater than largest uint216).
*
* Counterpart to Solidity's `uint216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*/
function toUint216(uint256 value) internal pure returns (uint216) {
if (value > type(uint216).max) {
revert SafeCastOverflowedUintDowncast(216, value);
}
return uint216(value);
}
/**
* @dev Returns the downcasted uint208 from uint256, reverting on
* overflow (when the input is greater than largest uint208).
*
* Counterpart to Solidity's `uint208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*/
function toUint208(uint256 value) internal pure returns (uint208) {
if (value > type(uint208).max) {
revert SafeCastOverflowedUintDowncast(208, value);
}
return uint208(value);
}
/**
* @dev Returns the downcasted uint200 from uint256, reverting on
* overflow (when the input is greater than largest uint200).
*
* Counterpart to Solidity's `uint200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*/
function toUint200(uint256 value) internal pure returns (uint200) {
if (value > type(uint200).max) {
revert SafeCastOverflowedUintDowncast(200, value);
}
return uint200(value);
}
/**
* @dev Returns the downcasted uint192 from uint256, reverting on
* overflow (when the input is greater than largest uint192).
*
* Counterpart to Solidity's `uint192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*/
function toUint192(uint256 value) internal pure returns (uint192) {
if (value > type(uint192).max) {
revert SafeCastOverflowedUintDowncast(192, value);
}
return uint192(value);
}
/**
* @dev Returns the downcasted uint184 from uint256, reverting on
* overflow (when the input is greater than largest uint184).
*
* Counterpart to Solidity's `uint184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*/
function toUint184(uint256 value) internal pure returns (uint184) {
if (value > type(uint184).max) {
revert SafeCastOverflowedUintDowncast(184, value);
}
return uint184(value);
}
/**
* @dev Returns the downcasted uint176 from uint256, reverting on
* overflow (when the input is greater than largest uint176).
*
* Counterpart to Solidity's `uint176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*/
function toUint176(uint256 value) internal pure returns (uint176) {
if (value > type(uint176).max) {
revert SafeCastOverflowedUintDowncast(176, value);
}
return uint176(value);
}
/**
* @dev Returns the downcasted uint168 from uint256, reverting on
* overflow (when the input is greater than largest uint168).
*
* Counterpart to Solidity's `uint168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*/
function toUint168(uint256 value) internal pure returns (uint168) {
if (value > type(uint168).max) {
revert SafeCastOverflowedUintDowncast(168, value);
}
return uint168(value);
}
/**
* @dev Returns the downcasted uint160 from uint256, reverting on
* overflow (when the input is greater than largest uint160).
*
* Counterpart to Solidity's `uint160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*/
function toUint160(uint256 value) internal pure returns (uint160) {
if (value > type(uint160).max) {
revert SafeCastOverflowedUintDowncast(160, value);
}
return uint160(value);
}
/**
* @dev Returns the downcasted uint152 from uint256, reverting on
* overflow (when the input is greater than largest uint152).
*
* Counterpart to Solidity's `uint152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*/
function toUint152(uint256 value) internal pure returns (uint152) {
if (value > type(uint152).max) {
revert SafeCastOverflowedUintDowncast(152, value);
}
return uint152(value);
}
/**
* @dev Returns the downcasted uint144 from uint256, reverting on
* overflow (when the input is greater than largest uint144).
*
* Counterpart to Solidity's `uint144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*/
function toUint144(uint256 value) internal pure returns (uint144) {
if (value > type(uint144).max) {
revert SafeCastOverflowedUintDowncast(144, value);
}
return uint144(value);
}
/**
* @dev Returns the downcasted uint136 from uint256, reverting on
* overflow (when the input is greater than largest uint136).
*
* Counterpart to Solidity's `uint136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*/
function toUint136(uint256 value) internal pure returns (uint136) {
if (value > type(uint136).max) {
revert SafeCastOverflowedUintDowncast(136, value);
}
return uint136(value);
}
/**
* @dev Returns the downcasted uint128 from uint256, reverting on
* overflow (when the input is greater than largest uint128).
*
* Counterpart to Solidity's `uint128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*/
function toUint128(uint256 value) internal pure returns (uint128) {
if (value > type(uint128).max) {
revert SafeCastOverflowedUintDowncast(128, value);
}
return uint128(value);
}
/**
* @dev Returns the downcasted uint120 from uint256, reverting on
* overflow (when the input is greater than largest uint120).
*
* Counterpart to Solidity's `uint120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*/
function toUint120(uint256 value) internal pure returns (uint120) {
if (value > type(uint120).max) {
revert SafeCastOverflowedUintDowncast(120, value);
}
return uint120(value);
}
/**
* @dev Returns the downcasted uint112 from uint256, reverting on
* overflow (when the input is greater than largest uint112).
*
* Counterpart to Solidity's `uint112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*/
function toUint112(uint256 value) internal pure returns (uint112) {
if (value > type(uint112).max) {
revert SafeCastOverflowedUintDowncast(112, value);
}
return uint112(value);
}
/**
* @dev Returns the downcasted uint104 from uint256, reverting on
* overflow (when the input is greater than largest uint104).
*
* Counterpart to Solidity's `uint104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*/
function toUint104(uint256 value) internal pure returns (uint104) {
if (value > type(uint104).max) {
revert SafeCastOverflowedUintDowncast(104, value);
}
return uint104(value);
}
/**
* @dev Returns the downcasted uint96 from uint256, reverting on
* overflow (when the input is greater than largest uint96).
*
* Counterpart to Solidity's `uint96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*/
function toUint96(uint256 value) internal pure returns (uint96) {
if (value > type(uint96).max) {
revert SafeCastOverflowedUintDowncast(96, value);
}
return uint96(value);
}
/**
* @dev Returns the downcasted uint88 from uint256, reverting on
* overflow (when the input is greater than largest uint88).
*
* Counterpart to Solidity's `uint88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*/
function toUint88(uint256 value) internal pure returns (uint88) {
if (value > type(uint88).max) {
revert SafeCastOverflowedUintDowncast(88, value);
}
return uint88(value);
}
/**
* @dev Returns the downcasted uint80 from uint256, reverting on
* overflow (when the input is greater than largest uint80).
*
* Counterpart to Solidity's `uint80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*/
function toUint80(uint256 value) internal pure returns (uint80) {
if (value > type(uint80).max) {
revert SafeCastOverflowedUintDowncast(80, value);
}
return uint80(value);
}
/**
* @dev Returns the downcasted uint72 from uint256, reverting on
* overflow (when the input is greater than largest uint72).
*
* Counterpart to Solidity's `uint72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*/
function toUint72(uint256 value) internal pure returns (uint72) {
if (value > type(uint72).max) {
revert SafeCastOverflowedUintDowncast(72, value);
}
return uint72(value);
}
/**
* @dev Returns the downcasted uint64 from uint256, reverting on
* overflow (when the input is greater than largest uint64).
*
* Counterpart to Solidity's `uint64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*/
function toUint64(uint256 value) internal pure returns (uint64) {
if (value > type(uint64).max) {
revert SafeCastOverflowedUintDowncast(64, value);
}
return uint64(value);
}
/**
* @dev Returns the downcasted uint56 from uint256, reverting on
* overflow (when the input is greater than largest uint56).
*
* Counterpart to Solidity's `uint56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*/
function toUint56(uint256 value) internal pure returns (uint56) {
if (value > type(uint56).max) {
revert SafeCastOverflowedUintDowncast(56, value);
}
return uint56(value);
}
/**
* @dev Returns the downcasted uint48 from uint256, reverting on
* overflow (when the input is greater than largest uint48).
*
* Counterpart to Solidity's `uint48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*/
function toUint48(uint256 value) internal pure returns (uint48) {
if (value > type(uint48).max) {
revert SafeCastOverflowedUintDowncast(48, value);
}
return uint48(value);
}
/**
* @dev Returns the downcasted uint40 from uint256, reverting on
* overflow (when the input is greater than largest uint40).
*
* Counterpart to Solidity's `uint40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*/
function toUint40(uint256 value) internal pure returns (uint40) {
if (value > type(uint40).max) {
revert SafeCastOverflowedUintDowncast(40, value);
}
return uint40(value);
}
/**
* @dev Returns the downcasted uint32 from uint256, reverting on
* overflow (when the input is greater than largest uint32).
*
* Counterpart to Solidity's `uint32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*/
function toUint32(uint256 value) internal pure returns (uint32) {
if (value > type(uint32).max) {
revert SafeCastOverflowedUintDowncast(32, value);
}
return uint32(value);
}
/**
* @dev Returns the downcasted uint24 from uint256, reverting on
* overflow (when the input is greater than largest uint24).
*
* Counterpart to Solidity's `uint24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*/
function toUint24(uint256 value) internal pure returns (uint24) {
if (value > type(uint24).max) {
revert SafeCastOverflowedUintDowncast(24, value);
}
return uint24(value);
}
/**
* @dev Returns the downcasted uint16 from uint256, reverting on
* overflow (when the input is greater than largest uint16).
*
* Counterpart to Solidity's `uint16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*/
function toUint16(uint256 value) internal pure returns (uint16) {
if (value > type(uint16).max) {
revert SafeCastOverflowedUintDowncast(16, value);
}
return uint16(value);
}
/**
* @dev Returns the downcasted uint8 from uint256, reverting on
* overflow (when the input is greater than largest uint8).
*
* Counterpart to Solidity's `uint8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*/
function toUint8(uint256 value) internal pure returns (uint8) {
if (value > type(uint8).max) {
revert SafeCastOverflowedUintDowncast(8, value);
}
return uint8(value);
}
/**
* @dev Converts a signed int256 into an unsigned uint256.
*
* Requirements:
*
* - input must be greater than or equal to 0.
*/
function toUint256(int256 value) internal pure returns (uint256) {
if (value < 0) {
revert SafeCastOverflowedIntToUint(value);
}
return uint256(value);
}
/**
* @dev Returns the downcasted int248 from int256, reverting on
* overflow (when the input is less than smallest int248 or
* greater than largest int248).
*
* Counterpart to Solidity's `int248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*/
function toInt248(int256 value) internal pure returns (int248 downcasted) {
downcasted = int248(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(248, value);
}
}
/**
* @dev Returns the downcasted int240 from int256, reverting on
* overflow (when the input is less than smallest int240 or
* greater than largest int240).
*
* Counterpart to Solidity's `int240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*/
function toInt240(int256 value) internal pure returns (int240 downcasted) {
downcasted = int240(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(240, value);
}
}
/**
* @dev Returns the downcasted int232 from int256, reverting on
* overflow (when the input is less than smallest int232 or
* greater than largest int232).
*
* Counterpart to Solidity's `int232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*/
function toInt232(int256 value) internal pure returns (int232 downcasted) {
downcasted = int232(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(232, value);
}
}
/**
* @dev Returns the downcasted int224 from int256, reverting on
* overflow (when the input is less than smallest int224 or
* greater than largest int224).
*
* Counterpart to Solidity's `int224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*/
function toInt224(int256 value) internal pure returns (int224 downcasted) {
downcasted = int224(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(224, value);
}
}
/**
* @dev Returns the downcasted int216 from int256, reverting on
* overflow (when the input is less than smallest int216 or
* greater than largest int216).
*
* Counterpart to Solidity's `int216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*/
function toInt216(int256 value) internal pure returns (int216 downcasted) {
downcasted = int216(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(216, value);
}
}
/**
* @dev Returns the downcasted int208 from int256, reverting on
* overflow (when the input is less than smallest int208 or
* greater than largest int208).
*
* Counterpart to Solidity's `int208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*/
function toInt208(int256 value) internal pure returns (int208 downcasted) {
downcasted = int208(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(208, value);
}
}
/**
* @dev Returns the downcasted int200 from int256, reverting on
* overflow (when the input is less than smallest int200 or
* greater than largest int200).
*
* Counterpart to Solidity's `int200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*/
function toInt200(int256 value) internal pure returns (int200 downcasted) {
downcasted = int200(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(200, value);
}
}
/**
* @dev Returns the downcasted int192 from int256, reverting on
* overflow (when the input is less than smallest int192 or
* greater than largest int192).
*
* Counterpart to Solidity's `int192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*/
function toInt192(int256 value) internal pure returns (int192 downcasted) {
downcasted = int192(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(192, value);
}
}
/**
* @dev Returns the downcasted int184 from int256, reverting on
* overflow (when the input is less than smallest int184 or
* greater than largest int184).
*
* Counterpart to Solidity's `int184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*/
function toInt184(int256 value) internal pure returns (int184 downcasted) {
downcasted = int184(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(184, value);
}
}
/**
* @dev Returns the downcasted int176 from int256, reverting on
* overflow (when the input is less than smallest int176 or
* greater than largest int176).
*
* Counterpart to Solidity's `int176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*/
function toInt176(int256 value) internal pure returns (int176 downcasted) {
downcasted = int176(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(176, value);
}
}
/**
* @dev Returns the downcasted int168 from int256, reverting on
* overflow (when the input is less than smallest int168 or
* greater than largest int168).
*
* Counterpart to Solidity's `int168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*/
function toInt168(int256 value) internal pure returns (int168 downcasted) {
downcasted = int168(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(168, value);
}
}
/**
* @dev Returns the downcasted int160 from int256, reverting on
* overflow (when the input is less than smallest int160 or
* greater than largest int160).
*
* Counterpart to Solidity's `int160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*/
function toInt160(int256 value) internal pure returns (int160 downcasted) {
downcasted = int160(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(160, value);
}
}
/**
* @dev Returns the downcasted int152 from int256, reverting on
* overflow (when the input is less than smallest int152 or
* greater than largest int152).
*
* Counterpart to Solidity's `int152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*/
function toInt152(int256 value) internal pure returns (int152 downcasted) {
downcasted = int152(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(152, value);
}
}
/**
* @dev Returns the downcasted int144 from int256, reverting on
* overflow (when the input is less than smallest int144 or
* greater than largest int144).
*
* Counterpart to Solidity's `int144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*/
function toInt144(int256 value) internal pure returns (int144 downcasted) {
downcasted = int144(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(144, value);
}
}
/**
* @dev Returns the downcasted int136 from int256, reverting on
* overflow (when the input is less than smallest int136 or
* greater than largest int136).
*
* Counterpart to Solidity's `int136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*/
function toInt136(int256 value) internal pure returns (int136 downcasted) {
downcasted = int136(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(136, value);
}
}
/**
* @dev Returns the downcasted int128 from int256, reverting on
* overflow (when the input is less than smallest int128 or
* greater than largest int128).
*
* Counterpart to Solidity's `int128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*/
function toInt128(int256 value) internal pure returns (int128 downcasted) {
downcasted = int128(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(128, value);
}
}
/**
* @dev Returns the downcasted int120 from int256, reverting on
* overflow (when the input is less than smallest int120 or
* greater than largest int120).
*
* Counterpart to Solidity's `int120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*/
function toInt120(int256 value) internal pure returns (int120 downcasted) {
downcasted = int120(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(120, value);
}
}
/**
* @dev Returns the downcasted int112 from int256, reverting on
* overflow (when the input is less than smallest int112 or
* greater than largest int112).
*
* Counterpart to Solidity's `int112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*/
function toInt112(int256 value) internal pure returns (int112 downcasted) {
downcasted = int112(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(112, value);
}
}
/**
* @dev Returns the downcasted int104 from int256, reverting on
* overflow (when the input is less than smallest int104 or
* greater than largest int104).
*
* Counterpart to Solidity's `int104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*/
function toInt104(int256 value) internal pure returns (int104 downcasted) {
downcasted = int104(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(104, value);
}
}
/**
* @dev Returns the downcasted int96 from int256, reverting on
* overflow (when the input is less than smallest int96 or
* greater than largest int96).
*
* Counterpart to Solidity's `int96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*/
function toInt96(int256 value) internal pure returns (int96 downcasted) {
downcasted = int96(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(96, value);
}
}
/**
* @dev Returns the downcasted int88 from int256, reverting on
* overflow (when the input is less than smallest int88 or
* greater than largest int88).
*
* Counterpart to Solidity's `int88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*/
function toInt88(int256 value) internal pure returns (int88 downcasted) {
downcasted = int88(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(88, value);
}
}
/**
* @dev Returns the downcasted int80 from int256, reverting on
* overflow (when the input is less than smallest int80 or
* greater than largest int80).
*
* Counterpart to Solidity's `int80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*/
function toInt80(int256 value) internal pure returns (int80 downcasted) {
downcasted = int80(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(80, value);
}
}
/**
* @dev Returns the downcasted int72 from int256, reverting on
* overflow (when the input is less than smallest int72 or
* greater than largest int72).
*
* Counterpart to Solidity's `int72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*/
function toInt72(int256 value) internal pure returns (int72 downcasted) {
downcasted = int72(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(72, value);
}
}
/**
* @dev Returns the downcasted int64 from int256, reverting on
* overflow (when the input is less than smallest int64 or
* greater than largest int64).
*
* Counterpart to Solidity's `int64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*/
function toInt64(int256 value) internal pure returns (int64 downcasted) {
downcasted = int64(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(64, value);
}
}
/**
* @dev Returns the downcasted int56 from int256, reverting on
* overflow (when the input is less than smallest int56 or
* greater than largest int56).
*
* Counterpart to Solidity's `int56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*/
function toInt56(int256 value) internal pure returns (int56 downcasted) {
downcasted = int56(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(56, value);
}
}
/**
* @dev Returns the downcasted int48 from int256, reverting on
* overflow (when the input is less than smallest int48 or
* greater than largest int48).
*
* Counterpart to Solidity's `int48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*/
function toInt48(int256 value) internal pure returns (int48 downcasted) {
downcasted = int48(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(48, value);
}
}
/**
* @dev Returns the downcasted int40 from int256, reverting on
* overflow (when the input is less than smallest int40 or
* greater than largest int40).
*
* Counterpart to Solidity's `int40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*/
function toInt40(int256 value) internal pure returns (int40 downcasted) {
downcasted = int40(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(40, value);
}
}
/**
* @dev Returns the downcasted int32 from int256, reverting on
* overflow (when the input is less than smallest int32 or
* greater than largest int32).
*
* Counterpart to Solidity's `int32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*/
function toInt32(int256 value) internal pure returns (int32 downcasted) {
downcasted = int32(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(32, value);
}
}
/**
* @dev Returns the downcasted int24 from int256, reverting on
* overflow (when the input is less than smallest int24 or
* greater than largest int24).
*
* Counterpart to Solidity's `int24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*/
function toInt24(int256 value) internal pure returns (int24 downcasted) {
downcasted = int24(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(24, value);
}
}
/**
* @dev Returns the downcasted int16 from int256, reverting on
* overflow (when the input is less than smallest int16 or
* greater than largest int16).
*
* Counterpart to Solidity's `int16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*/
function toInt16(int256 value) internal pure returns (int16 downcasted) {
downcasted = int16(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(16, value);
}
}
/**
* @dev Returns the downcasted int8 from int256, reverting on
* overflow (when the input is less than smallest int8 or
* greater than largest int8).
*
* Counterpart to Solidity's `int8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*/
function toInt8(int256 value) internal pure returns (int8 downcasted) {
downcasted = int8(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(8, value);
}
}
/**
* @dev Converts an unsigned uint256 into a signed int256.
*
* Requirements:
*
* - input must be less than or equal to maxInt256.
*/
function toInt256(uint256 value) internal pure returns (int256) {
// Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
if (value > uint256(type(int256).max)) {
revert SafeCastOverflowedUintToInt(value);
}
return int256(value);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../utils/introspection/IERC165.sol";// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC6372.sol)
pragma solidity ^0.8.20;
interface IERC6372 {
/**
* @dev Clock used for flagging checkpoints. Can be overridden to implement timestamp based checkpoints (and voting).
*/
function clock() external view returns (uint48);
/**
* @dev Description of the clock
*/
// solhint-disable-next-line func-name-mixedcase
function CLOCK_MODE() external view returns (string memory);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.13;
import "./interfaces/IWormholeRelayer.sol";
function toWormholeFormat(address addr) pure returns (bytes32) {
return bytes32(uint256(uint160(addr)));
}
function fromWormholeFormat(bytes32 whFormatAddress) pure returns (address) {
if (uint256(whFormatAddress) >> 160 != 0) {
revert NotAnEvmAddress(whFormatAddress);
}
return address(uint160(uint256(whFormatAddress)));
}// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.13;
library BytesParsing {
uint256 private constant freeMemoryPtr = 0x40;
uint256 private constant wordSize = 32;
error OutOfBounds(uint256 offset, uint256 length);
error LengthMismatch(uint256 encodedLength, uint256 expectedLength);
error InvalidBoolVal(uint8 val);
function checkBound(uint offset, uint length) internal pure {
if (offset > length)
revert OutOfBounds(offset, length);
}
function checkLength(bytes memory encoded, uint256 expected) internal pure {
if (encoded.length != expected)
revert LengthMismatch(encoded.length, expected);
}
function sliceUnchecked(
bytes memory encoded,
uint offset,
uint length
) internal pure returns (bytes memory ret, uint nextOffset) {
//bail early for degenerate case
if (length == 0)
return (new bytes(0), offset);
assembly ("memory-safe") {
nextOffset := add(offset, length)
ret := mload(freeMemoryPtr)
//Explanation on how we copy data here:
// The bytes type has the following layout in memory:
// [length: 32 bytes, data: length bytes]
// So if we allocate `bytes memory foo = new bytes(1);` then `foo` will be a pointer to 33
// bytes where the first 32 bytes contain the length and the last byte is the actual data.
// Since mload always loads 32 bytes of memory at once, we use our shift variable to align
// our reads so that our last read lines up exactly with the last 32 bytes of `encoded`.
// However this also means that if the length of `encoded` is not a multiple of 32 bytes, our
// first read will necessarily partly contain bytes from `encoded`'s 32 length bytes that
// will be written into the length part of our `ret` slice.
// We remedy this issue by writing the length of our `ret` slice at the end, thus
// overwritting those garbage bytes.
let shift := and(length, 31) //equivalent to `mod(length, 32)` but 2 gas cheaper
if iszero(shift) {
shift := wordSize
}
let dest := add(ret, shift)
let end := add(dest, length)
for {
let src := add(add(encoded, shift), offset)
} lt(dest, end) {
src := add(src, wordSize)
dest := add(dest, wordSize)
} {
mstore(dest, mload(src))
}
mstore(ret, length)
//When compiling with --via-ir then normally allocated memory (i.e. via new) will have 32 byte
// memory alignment and so we enforce the same memory alignment here.
mstore(freeMemoryPtr, and(add(dest, 31), not(31)))
}
}
function slice(
bytes memory encoded,
uint offset,
uint length
) internal pure returns (bytes memory ret, uint nextOffset) {
(ret, nextOffset) = sliceUnchecked(encoded, offset, length);
checkBound(nextOffset, encoded.length);
}
function asAddressUnchecked(
bytes memory encoded,
uint offset
) internal pure returns (address, uint) {
(uint160 ret, uint nextOffset) = asUint160Unchecked(encoded, offset);
return (address(ret), nextOffset);
}
function asAddress(
bytes memory encoded,
uint offset
) internal pure returns (address ret, uint nextOffset) {
(ret, nextOffset) = asAddressUnchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBoolUnchecked(
bytes memory encoded,
uint offset
) internal pure returns (bool, uint) {
(uint8 val, uint nextOffset) = asUint8Unchecked(encoded, offset);
if (val & 0xfe != 0)
revert InvalidBoolVal(val);
uint cleanedVal = uint(val);
bool ret;
//skip 2x iszero opcode
assembly ("memory-safe") {
ret := cleanedVal
}
return (ret, nextOffset);
}
function asBool(
bytes memory encoded,
uint offset
) internal pure returns (bool ret, uint nextOffset) {
(ret, nextOffset) = asBoolUnchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
/* -------------------------------------------------------------------------------------------------
Remaining library code below was auto-generated by via the following js/node code:
for (let bytes = 1; bytes <= 32; ++bytes) {
const bits = bytes*8;
console.log(
`function asUint${bits}Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint${bits} ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, ${bytes})
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint${bits}(
bytes memory encoded,
uint offset
) internal pure returns (uint${bits} ret, uint nextOffset) {
(ret, nextOffset) = asUint${bits}Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes${bytes}Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes${bytes}, uint) {
(uint${bits} ret, uint nextOffset) = asUint${bits}Unchecked(encoded, offset);
return (bytes${bytes}(ret), nextOffset);
}
function asBytes${bytes}(
bytes memory encoded,
uint offset
) internal pure returns (bytes${bytes}, uint) {
(uint${bits} ret, uint nextOffset) = asUint${bits}(encoded, offset);
return (bytes${bytes}(ret), nextOffset);
}
`
);
}
------------------------------------------------------------------------------------------------- */
function asUint8Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint8 ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, 1)
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint8(
bytes memory encoded,
uint offset
) internal pure returns (uint8 ret, uint nextOffset) {
(ret, nextOffset) = asUint8Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes1Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes1, uint) {
(uint8 ret, uint nextOffset) = asUint8Unchecked(encoded, offset);
return (bytes1(ret), nextOffset);
}
function asBytes1(
bytes memory encoded,
uint offset
) internal pure returns (bytes1, uint) {
(uint8 ret, uint nextOffset) = asUint8(encoded, offset);
return (bytes1(ret), nextOffset);
}
function asUint16Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint16 ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, 2)
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint16(
bytes memory encoded,
uint offset
) internal pure returns (uint16 ret, uint nextOffset) {
(ret, nextOffset) = asUint16Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes2Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes2, uint) {
(uint16 ret, uint nextOffset) = asUint16Unchecked(encoded, offset);
return (bytes2(ret), nextOffset);
}
function asBytes2(
bytes memory encoded,
uint offset
) internal pure returns (bytes2, uint) {
(uint16 ret, uint nextOffset) = asUint16(encoded, offset);
return (bytes2(ret), nextOffset);
}
function asUint24Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint24 ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, 3)
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint24(
bytes memory encoded,
uint offset
) internal pure returns (uint24 ret, uint nextOffset) {
(ret, nextOffset) = asUint24Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes3Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes3, uint) {
(uint24 ret, uint nextOffset) = asUint24Unchecked(encoded, offset);
return (bytes3(ret), nextOffset);
}
function asBytes3(
bytes memory encoded,
uint offset
) internal pure returns (bytes3, uint) {
(uint24 ret, uint nextOffset) = asUint24(encoded, offset);
return (bytes3(ret), nextOffset);
}
function asUint32Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint32 ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, 4)
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint32(
bytes memory encoded,
uint offset
) internal pure returns (uint32 ret, uint nextOffset) {
(ret, nextOffset) = asUint32Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes4Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes4, uint) {
(uint32 ret, uint nextOffset) = asUint32Unchecked(encoded, offset);
return (bytes4(ret), nextOffset);
}
function asBytes4(
bytes memory encoded,
uint offset
) internal pure returns (bytes4, uint) {
(uint32 ret, uint nextOffset) = asUint32(encoded, offset);
return (bytes4(ret), nextOffset);
}
function asUint40Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint40 ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, 5)
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint40(
bytes memory encoded,
uint offset
) internal pure returns (uint40 ret, uint nextOffset) {
(ret, nextOffset) = asUint40Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes5Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes5, uint) {
(uint40 ret, uint nextOffset) = asUint40Unchecked(encoded, offset);
return (bytes5(ret), nextOffset);
}
function asBytes5(
bytes memory encoded,
uint offset
) internal pure returns (bytes5, uint) {
(uint40 ret, uint nextOffset) = asUint40(encoded, offset);
return (bytes5(ret), nextOffset);
}
function asUint48Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint48 ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, 6)
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint48(
bytes memory encoded,
uint offset
) internal pure returns (uint48 ret, uint nextOffset) {
(ret, nextOffset) = asUint48Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes6Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes6, uint) {
(uint48 ret, uint nextOffset) = asUint48Unchecked(encoded, offset);
return (bytes6(ret), nextOffset);
}
function asBytes6(
bytes memory encoded,
uint offset
) internal pure returns (bytes6, uint) {
(uint48 ret, uint nextOffset) = asUint48(encoded, offset);
return (bytes6(ret), nextOffset);
}
function asUint56Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint56 ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, 7)
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint56(
bytes memory encoded,
uint offset
) internal pure returns (uint56 ret, uint nextOffset) {
(ret, nextOffset) = asUint56Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes7Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes7, uint) {
(uint56 ret, uint nextOffset) = asUint56Unchecked(encoded, offset);
return (bytes7(ret), nextOffset);
}
function asBytes7(
bytes memory encoded,
uint offset
) internal pure returns (bytes7, uint) {
(uint56 ret, uint nextOffset) = asUint56(encoded, offset);
return (bytes7(ret), nextOffset);
}
function asUint64Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint64 ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, 8)
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint64(
bytes memory encoded,
uint offset
) internal pure returns (uint64 ret, uint nextOffset) {
(ret, nextOffset) = asUint64Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes8Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes8, uint) {
(uint64 ret, uint nextOffset) = asUint64Unchecked(encoded, offset);
return (bytes8(ret), nextOffset);
}
function asBytes8(
bytes memory encoded,
uint offset
) internal pure returns (bytes8, uint) {
(uint64 ret, uint nextOffset) = asUint64(encoded, offset);
return (bytes8(ret), nextOffset);
}
function asUint72Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint72 ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, 9)
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint72(
bytes memory encoded,
uint offset
) internal pure returns (uint72 ret, uint nextOffset) {
(ret, nextOffset) = asUint72Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes9Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes9, uint) {
(uint72 ret, uint nextOffset) = asUint72Unchecked(encoded, offset);
return (bytes9(ret), nextOffset);
}
function asBytes9(
bytes memory encoded,
uint offset
) internal pure returns (bytes9, uint) {
(uint72 ret, uint nextOffset) = asUint72(encoded, offset);
return (bytes9(ret), nextOffset);
}
function asUint80Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint80 ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, 10)
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint80(
bytes memory encoded,
uint offset
) internal pure returns (uint80 ret, uint nextOffset) {
(ret, nextOffset) = asUint80Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes10Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes10, uint) {
(uint80 ret, uint nextOffset) = asUint80Unchecked(encoded, offset);
return (bytes10(ret), nextOffset);
}
function asBytes10(
bytes memory encoded,
uint offset
) internal pure returns (bytes10, uint) {
(uint80 ret, uint nextOffset) = asUint80(encoded, offset);
return (bytes10(ret), nextOffset);
}
function asUint88Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint88 ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, 11)
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint88(
bytes memory encoded,
uint offset
) internal pure returns (uint88 ret, uint nextOffset) {
(ret, nextOffset) = asUint88Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes11Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes11, uint) {
(uint88 ret, uint nextOffset) = asUint88Unchecked(encoded, offset);
return (bytes11(ret), nextOffset);
}
function asBytes11(
bytes memory encoded,
uint offset
) internal pure returns (bytes11, uint) {
(uint88 ret, uint nextOffset) = asUint88(encoded, offset);
return (bytes11(ret), nextOffset);
}
function asUint96Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint96 ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, 12)
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint96(
bytes memory encoded,
uint offset
) internal pure returns (uint96 ret, uint nextOffset) {
(ret, nextOffset) = asUint96Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes12Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes12, uint) {
(uint96 ret, uint nextOffset) = asUint96Unchecked(encoded, offset);
return (bytes12(ret), nextOffset);
}
function asBytes12(
bytes memory encoded,
uint offset
) internal pure returns (bytes12, uint) {
(uint96 ret, uint nextOffset) = asUint96(encoded, offset);
return (bytes12(ret), nextOffset);
}
function asUint104Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint104 ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, 13)
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint104(
bytes memory encoded,
uint offset
) internal pure returns (uint104 ret, uint nextOffset) {
(ret, nextOffset) = asUint104Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes13Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes13, uint) {
(uint104 ret, uint nextOffset) = asUint104Unchecked(encoded, offset);
return (bytes13(ret), nextOffset);
}
function asBytes13(
bytes memory encoded,
uint offset
) internal pure returns (bytes13, uint) {
(uint104 ret, uint nextOffset) = asUint104(encoded, offset);
return (bytes13(ret), nextOffset);
}
function asUint112Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint112 ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, 14)
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint112(
bytes memory encoded,
uint offset
) internal pure returns (uint112 ret, uint nextOffset) {
(ret, nextOffset) = asUint112Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes14Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes14, uint) {
(uint112 ret, uint nextOffset) = asUint112Unchecked(encoded, offset);
return (bytes14(ret), nextOffset);
}
function asBytes14(
bytes memory encoded,
uint offset
) internal pure returns (bytes14, uint) {
(uint112 ret, uint nextOffset) = asUint112(encoded, offset);
return (bytes14(ret), nextOffset);
}
function asUint120Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint120 ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, 15)
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint120(
bytes memory encoded,
uint offset
) internal pure returns (uint120 ret, uint nextOffset) {
(ret, nextOffset) = asUint120Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes15Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes15, uint) {
(uint120 ret, uint nextOffset) = asUint120Unchecked(encoded, offset);
return (bytes15(ret), nextOffset);
}
function asBytes15(
bytes memory encoded,
uint offset
) internal pure returns (bytes15, uint) {
(uint120 ret, uint nextOffset) = asUint120(encoded, offset);
return (bytes15(ret), nextOffset);
}
function asUint128Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint128 ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, 16)
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint128(
bytes memory encoded,
uint offset
) internal pure returns (uint128 ret, uint nextOffset) {
(ret, nextOffset) = asUint128Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes16Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes16, uint) {
(uint128 ret, uint nextOffset) = asUint128Unchecked(encoded, offset);
return (bytes16(ret), nextOffset);
}
function asBytes16(
bytes memory encoded,
uint offset
) internal pure returns (bytes16, uint) {
(uint128 ret, uint nextOffset) = asUint128(encoded, offset);
return (bytes16(ret), nextOffset);
}
function asUint136Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint136 ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, 17)
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint136(
bytes memory encoded,
uint offset
) internal pure returns (uint136 ret, uint nextOffset) {
(ret, nextOffset) = asUint136Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes17Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes17, uint) {
(uint136 ret, uint nextOffset) = asUint136Unchecked(encoded, offset);
return (bytes17(ret), nextOffset);
}
function asBytes17(
bytes memory encoded,
uint offset
) internal pure returns (bytes17, uint) {
(uint136 ret, uint nextOffset) = asUint136(encoded, offset);
return (bytes17(ret), nextOffset);
}
function asUint144Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint144 ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, 18)
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint144(
bytes memory encoded,
uint offset
) internal pure returns (uint144 ret, uint nextOffset) {
(ret, nextOffset) = asUint144Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes18Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes18, uint) {
(uint144 ret, uint nextOffset) = asUint144Unchecked(encoded, offset);
return (bytes18(ret), nextOffset);
}
function asBytes18(
bytes memory encoded,
uint offset
) internal pure returns (bytes18, uint) {
(uint144 ret, uint nextOffset) = asUint144(encoded, offset);
return (bytes18(ret), nextOffset);
}
function asUint152Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint152 ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, 19)
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint152(
bytes memory encoded,
uint offset
) internal pure returns (uint152 ret, uint nextOffset) {
(ret, nextOffset) = asUint152Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes19Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes19, uint) {
(uint152 ret, uint nextOffset) = asUint152Unchecked(encoded, offset);
return (bytes19(ret), nextOffset);
}
function asBytes19(
bytes memory encoded,
uint offset
) internal pure returns (bytes19, uint) {
(uint152 ret, uint nextOffset) = asUint152(encoded, offset);
return (bytes19(ret), nextOffset);
}
function asUint160Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint160 ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, 20)
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint160(
bytes memory encoded,
uint offset
) internal pure returns (uint160 ret, uint nextOffset) {
(ret, nextOffset) = asUint160Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes20Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes20, uint) {
(uint160 ret, uint nextOffset) = asUint160Unchecked(encoded, offset);
return (bytes20(ret), nextOffset);
}
function asBytes20(
bytes memory encoded,
uint offset
) internal pure returns (bytes20, uint) {
(uint160 ret, uint nextOffset) = asUint160(encoded, offset);
return (bytes20(ret), nextOffset);
}
function asUint168Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint168 ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, 21)
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint168(
bytes memory encoded,
uint offset
) internal pure returns (uint168 ret, uint nextOffset) {
(ret, nextOffset) = asUint168Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes21Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes21, uint) {
(uint168 ret, uint nextOffset) = asUint168Unchecked(encoded, offset);
return (bytes21(ret), nextOffset);
}
function asBytes21(
bytes memory encoded,
uint offset
) internal pure returns (bytes21, uint) {
(uint168 ret, uint nextOffset) = asUint168(encoded, offset);
return (bytes21(ret), nextOffset);
}
function asUint176Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint176 ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, 22)
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint176(
bytes memory encoded,
uint offset
) internal pure returns (uint176 ret, uint nextOffset) {
(ret, nextOffset) = asUint176Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes22Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes22, uint) {
(uint176 ret, uint nextOffset) = asUint176Unchecked(encoded, offset);
return (bytes22(ret), nextOffset);
}
function asBytes22(
bytes memory encoded,
uint offset
) internal pure returns (bytes22, uint) {
(uint176 ret, uint nextOffset) = asUint176(encoded, offset);
return (bytes22(ret), nextOffset);
}
function asUint184Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint184 ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, 23)
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint184(
bytes memory encoded,
uint offset
) internal pure returns (uint184 ret, uint nextOffset) {
(ret, nextOffset) = asUint184Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes23Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes23, uint) {
(uint184 ret, uint nextOffset) = asUint184Unchecked(encoded, offset);
return (bytes23(ret), nextOffset);
}
function asBytes23(
bytes memory encoded,
uint offset
) internal pure returns (bytes23, uint) {
(uint184 ret, uint nextOffset) = asUint184(encoded, offset);
return (bytes23(ret), nextOffset);
}
function asUint192Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint192 ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, 24)
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint192(
bytes memory encoded,
uint offset
) internal pure returns (uint192 ret, uint nextOffset) {
(ret, nextOffset) = asUint192Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes24Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes24, uint) {
(uint192 ret, uint nextOffset) = asUint192Unchecked(encoded, offset);
return (bytes24(ret), nextOffset);
}
function asBytes24(
bytes memory encoded,
uint offset
) internal pure returns (bytes24, uint) {
(uint192 ret, uint nextOffset) = asUint192(encoded, offset);
return (bytes24(ret), nextOffset);
}
function asUint200Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint200 ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, 25)
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint200(
bytes memory encoded,
uint offset
) internal pure returns (uint200 ret, uint nextOffset) {
(ret, nextOffset) = asUint200Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes25Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes25, uint) {
(uint200 ret, uint nextOffset) = asUint200Unchecked(encoded, offset);
return (bytes25(ret), nextOffset);
}
function asBytes25(
bytes memory encoded,
uint offset
) internal pure returns (bytes25, uint) {
(uint200 ret, uint nextOffset) = asUint200(encoded, offset);
return (bytes25(ret), nextOffset);
}
function asUint208Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint208 ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, 26)
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint208(
bytes memory encoded,
uint offset
) internal pure returns (uint208 ret, uint nextOffset) {
(ret, nextOffset) = asUint208Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes26Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes26, uint) {
(uint208 ret, uint nextOffset) = asUint208Unchecked(encoded, offset);
return (bytes26(ret), nextOffset);
}
function asBytes26(
bytes memory encoded,
uint offset
) internal pure returns (bytes26, uint) {
(uint208 ret, uint nextOffset) = asUint208(encoded, offset);
return (bytes26(ret), nextOffset);
}
function asUint216Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint216 ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, 27)
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint216(
bytes memory encoded,
uint offset
) internal pure returns (uint216 ret, uint nextOffset) {
(ret, nextOffset) = asUint216Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes27Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes27, uint) {
(uint216 ret, uint nextOffset) = asUint216Unchecked(encoded, offset);
return (bytes27(ret), nextOffset);
}
function asBytes27(
bytes memory encoded,
uint offset
) internal pure returns (bytes27, uint) {
(uint216 ret, uint nextOffset) = asUint216(encoded, offset);
return (bytes27(ret), nextOffset);
}
function asUint224Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint224 ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, 28)
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint224(
bytes memory encoded,
uint offset
) internal pure returns (uint224 ret, uint nextOffset) {
(ret, nextOffset) = asUint224Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes28Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes28, uint) {
(uint224 ret, uint nextOffset) = asUint224Unchecked(encoded, offset);
return (bytes28(ret), nextOffset);
}
function asBytes28(
bytes memory encoded,
uint offset
) internal pure returns (bytes28, uint) {
(uint224 ret, uint nextOffset) = asUint224(encoded, offset);
return (bytes28(ret), nextOffset);
}
function asUint232Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint232 ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, 29)
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint232(
bytes memory encoded,
uint offset
) internal pure returns (uint232 ret, uint nextOffset) {
(ret, nextOffset) = asUint232Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes29Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes29, uint) {
(uint232 ret, uint nextOffset) = asUint232Unchecked(encoded, offset);
return (bytes29(ret), nextOffset);
}
function asBytes29(
bytes memory encoded,
uint offset
) internal pure returns (bytes29, uint) {
(uint232 ret, uint nextOffset) = asUint232(encoded, offset);
return (bytes29(ret), nextOffset);
}
function asUint240Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint240 ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, 30)
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint240(
bytes memory encoded,
uint offset
) internal pure returns (uint240 ret, uint nextOffset) {
(ret, nextOffset) = asUint240Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes30Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes30, uint) {
(uint240 ret, uint nextOffset) = asUint240Unchecked(encoded, offset);
return (bytes30(ret), nextOffset);
}
function asBytes30(
bytes memory encoded,
uint offset
) internal pure returns (bytes30, uint) {
(uint240 ret, uint nextOffset) = asUint240(encoded, offset);
return (bytes30(ret), nextOffset);
}
function asUint248Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint248 ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, 31)
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint248(
bytes memory encoded,
uint offset
) internal pure returns (uint248 ret, uint nextOffset) {
(ret, nextOffset) = asUint248Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes31Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes31, uint) {
(uint248 ret, uint nextOffset) = asUint248Unchecked(encoded, offset);
return (bytes31(ret), nextOffset);
}
function asBytes31(
bytes memory encoded,
uint offset
) internal pure returns (bytes31, uint) {
(uint248 ret, uint nextOffset) = asUint248(encoded, offset);
return (bytes31(ret), nextOffset);
}
function asUint256Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (uint256 ret, uint nextOffset) {
assembly ("memory-safe") {
nextOffset := add(offset, 32)
ret := mload(add(encoded, nextOffset))
}
return (ret, nextOffset);
}
function asUint256(
bytes memory encoded,
uint offset
) internal pure returns (uint256 ret, uint nextOffset) {
(ret, nextOffset) = asUint256Unchecked(encoded, offset);
checkBound(nextOffset, encoded.length);
}
function asBytes32Unchecked(
bytes memory encoded,
uint offset
) internal pure returns (bytes32, uint) {
(uint256 ret, uint nextOffset) = asUint256Unchecked(encoded, offset);
return (bytes32(ret), nextOffset);
}
function asBytes32(
bytes memory encoded,
uint offset
) internal pure returns (bytes32, uint) {
(uint256 ret, uint nextOffset) = asUint256(encoded, offset);
return (bytes32(ret), nextOffset);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
/**
* @dev Muldiv operation overflow.
*/
error MathOverflowedMulDiv();
enum Rounding {
Floor, // Toward negative infinity
Ceil, // Toward positive infinity
Trunc, // Toward zero
Expand // Away from zero
}
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the subtraction of two unsigned integers, with an overflow flag.
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds towards infinity instead
* of rounding towards zero.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
if (b == 0) {
// Guarantee the same behavior as in a regular Solidity division.
return a / b;
}
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
* denominator == 0.
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
* Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0 = x * y; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
if (denominator <= prod1) {
revert MathOverflowedMulDiv();
}
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator.
// Always >= 1. See https://cs.stackexchange.com/q/138556/92363.
uint256 twos = denominator & (0 - denominator);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also
// works in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
* towards zero.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256 of a positive value rounded towards zero.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);
}
}
/**
* @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
*/
function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
return uint8(rounding) % 2 == 1;
}
}// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.0;
/**
* @title WormholeRelayer
* @author
* @notice This project allows developers to build cross-chain applications powered by Wormhole without needing to
* write and run their own relaying infrastructure
*
* We implement the IWormholeRelayer interface that allows users to request a delivery provider to relay a payload (and/or additional messages)
* to a chain and address of their choice.
*/
/**
* @notice VaaKey identifies a wormhole message
*
* @custom:member chainId Wormhole chain ID of the chain where this VAA was emitted from
* @custom:member emitterAddress Address of the emitter of the VAA, in Wormhole bytes32 format
* @custom:member sequence Sequence number of the VAA
*/
struct VaaKey {
uint16 chainId;
bytes32 emitterAddress;
uint64 sequence;
}
// 0-127 are reserved for standardized KeyTypes, 128-255 are for custom use
uint8 constant VAA_KEY_TYPE = 1;
struct MessageKey {
uint8 keyType; // 0-127 are reserved for standardized KeyTypes, 128-255 are for custom use
bytes encodedKey;
}
interface IWormholeRelayerBase {
event SendEvent(
uint64 indexed sequence,
uint256 deliveryQuote,
uint256 paymentForExtraReceiverValue
);
function getRegisteredWormholeRelayerContract(
uint16 chainId
) external view returns (bytes32);
/**
* @notice Returns true if a delivery has been attempted for the given deliveryHash
* Note: invalid deliveries where the tx reverts are not considered attempted
*/
function deliveryAttempted(
bytes32 deliveryHash
) external view returns (bool attempted);
/**
* @notice block number at which a delivery was successfully executed
*/
function deliverySuccessBlock(
bytes32 deliveryHash
) external view returns (uint256 blockNumber);
/**
* @notice block number of the latest attempt to execute a delivery that failed
*/
function deliveryFailureBlock(
bytes32 deliveryHash
) external view returns (uint256 blockNumber);
}
/**
* @title IWormholeRelayerSend
* @notice The interface to request deliveries
*/
interface IWormholeRelayerSend is IWormholeRelayerBase {
/**
* @notice Publishes an instruction for the default delivery provider
* to relay a payload to the address `targetAddress` on chain `targetChain`
* with gas limit `gasLimit` and `msg.value` equal to `receiverValue`
*
* `targetAddress` must implement the IWormholeReceiver interface
*
* This function must be called with `msg.value` equal to `quoteEVMDeliveryPrice(targetChain, receiverValue, gasLimit)`
*
* Any refunds (from leftover gas) will be paid to the delivery provider. In order to receive the refunds, use the `sendPayloadToEvm` function
* with `refundChain` and `refundAddress` as parameters
*
* @param targetChain in Wormhole Chain ID format
* @param targetAddress address to call on targetChain (that implements IWormholeReceiver)
* @param payload arbitrary bytes to pass in as parameter in call to `targetAddress`
* @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units)
* @param gasLimit gas limit with which to call `targetAddress`.
* @return sequence sequence number of published VAA containing delivery instructions
*/
function sendPayloadToEvm(
uint16 targetChain,
address targetAddress,
bytes memory payload,
uint256 receiverValue,
uint256 gasLimit
) external payable returns (uint64 sequence);
/**
* @notice Publishes an instruction for the default delivery provider
* to relay a payload to the address `targetAddress` on chain `targetChain`
* with gas limit `gasLimit` and `msg.value` equal to `receiverValue`
*
* Any refunds (from leftover gas) will be sent to `refundAddress` on chain `refundChain`
* `targetAddress` must implement the IWormholeReceiver interface
*
* This function must be called with `msg.value` equal to `quoteEVMDeliveryPrice(targetChain, receiverValue, gasLimit)`
*
* @param targetChain in Wormhole Chain ID format
* @param targetAddress address to call on targetChain (that implements IWormholeReceiver)
* @param payload arbitrary bytes to pass in as parameter in call to `targetAddress`
* @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units)
* @param gasLimit gas limit with which to call `targetAddress`. Any units of gas unused will be refunded according to the
* `targetChainRefundPerGasUnused` rate quoted by the delivery provider
* @param refundChain The chain to deliver any refund to, in Wormhole Chain ID format
* @param refundAddress The address on `refundChain` to deliver any refund to
* @return sequence sequence number of published VAA containing delivery instructions
*/
function sendPayloadToEvm(
uint16 targetChain,
address targetAddress,
bytes memory payload,
uint256 receiverValue,
uint256 gasLimit,
uint16 refundChain,
address refundAddress
) external payable returns (uint64 sequence);
/**
* @notice Publishes an instruction for the default delivery provider
* to relay a payload and VAAs specified by `vaaKeys` to the address `targetAddress` on chain `targetChain`
* with gas limit `gasLimit` and `msg.value` equal to `receiverValue`
*
* `targetAddress` must implement the IWormholeReceiver interface
*
* This function must be called with `msg.value` equal to `quoteEVMDeliveryPrice(targetChain, receiverValue, gasLimit)`
*
* Any refunds (from leftover gas) will be paid to the delivery provider. In order to receive the refunds, use the `sendVaasToEvm` function
* with `refundChain` and `refundAddress` as parameters
*
* @param targetChain in Wormhole Chain ID format
* @param targetAddress address to call on targetChain (that implements IWormholeReceiver)
* @param payload arbitrary bytes to pass in as parameter in call to `targetAddress`
* @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units)
* @param gasLimit gas limit with which to call `targetAddress`.
* @param vaaKeys Additional VAAs to pass in as parameter in call to `targetAddress`
* @return sequence sequence number of published VAA containing delivery instructions
*/
function sendVaasToEvm(
uint16 targetChain,
address targetAddress,
bytes memory payload,
uint256 receiverValue,
uint256 gasLimit,
VaaKey[] memory vaaKeys
) external payable returns (uint64 sequence);
/**
* @notice Publishes an instruction for the default delivery provider
* to relay a payload and VAAs specified by `vaaKeys` to the address `targetAddress` on chain `targetChain`
* with gas limit `gasLimit` and `msg.value` equal to `receiverValue`
*
* Any refunds (from leftover gas) will be sent to `refundAddress` on chain `refundChain`
* `targetAddress` must implement the IWormholeReceiver interface
*
* This function must be called with `msg.value` equal to `quoteEVMDeliveryPrice(targetChain, receiverValue, gasLimit)`
*
* @param targetChain in Wormhole Chain ID format
* @param targetAddress address to call on targetChain (that implements IWormholeReceiver)
* @param payload arbitrary bytes to pass in as parameter in call to `targetAddress`
* @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units)
* @param gasLimit gas limit with which to call `targetAddress`. Any units of gas unused will be refunded according to the
* `targetChainRefundPerGasUnused` rate quoted by the delivery provider
* @param vaaKeys Additional VAAs to pass in as parameter in call to `targetAddress`
* @param refundChain The chain to deliver any refund to, in Wormhole Chain ID format
* @param refundAddress The address on `refundChain` to deliver any refund to
* @return sequence sequence number of published VAA containing delivery instructions
*/
function sendVaasToEvm(
uint16 targetChain,
address targetAddress,
bytes memory payload,
uint256 receiverValue,
uint256 gasLimit,
VaaKey[] memory vaaKeys,
uint16 refundChain,
address refundAddress
) external payable returns (uint64 sequence);
/**
* @notice Publishes an instruction for the delivery provider at `deliveryProviderAddress`
* to relay a payload and VAAs specified by `vaaKeys` to the address `targetAddress` on chain `targetChain`
* with gas limit `gasLimit` and `msg.value` equal to
* receiverValue + (arbitrary amount that is paid for by paymentForExtraReceiverValue of this chain's wei) in targetChain wei.
*
* Any refunds (from leftover gas) will be sent to `refundAddress` on chain `refundChain`
* `targetAddress` must implement the IWormholeReceiver interface
*
* This function must be called with `msg.value` equal to
* quoteEVMDeliveryPrice(targetChain, receiverValue, gasLimit, deliveryProviderAddress) + paymentForExtraReceiverValue
*
* @param targetChain in Wormhole Chain ID format
* @param targetAddress address to call on targetChain (that implements IWormholeReceiver)
* @param payload arbitrary bytes to pass in as parameter in call to `targetAddress`
* @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units)
* @param paymentForExtraReceiverValue amount (in current chain currency units) to spend on extra receiverValue
* (in addition to the `receiverValue` specified)
* @param gasLimit gas limit with which to call `targetAddress`. Any units of gas unused will be refunded according to the
* `targetChainRefundPerGasUnused` rate quoted by the delivery provider
* @param refundChain The chain to deliver any refund to, in Wormhole Chain ID format
* @param refundAddress The address on `refundChain` to deliver any refund to
* @param deliveryProviderAddress The address of the desired delivery provider's implementation of IDeliveryProvider
* @param vaaKeys Additional VAAs to pass in as parameter in call to `targetAddress`
* @param consistencyLevel Consistency level with which to publish the delivery instructions - see
* https://book.wormhole.com/wormhole/3_coreLayerContracts.html?highlight=consistency#consistency-levels
* @return sequence sequence number of published VAA containing delivery instructions
*/
function sendToEvm(
uint16 targetChain,
address targetAddress,
bytes memory payload,
uint256 receiverValue,
uint256 paymentForExtraReceiverValue,
uint256 gasLimit,
uint16 refundChain,
address refundAddress,
address deliveryProviderAddress,
VaaKey[] memory vaaKeys,
uint8 consistencyLevel
) external payable returns (uint64 sequence);
/**
* @notice Publishes an instruction for the delivery provider at `deliveryProviderAddress`
* to relay a payload and external messages specified by `messageKeys` to the address `targetAddress` on chain `targetChain`
* with gas limit `gasLimit` and `msg.value` equal to
* receiverValue + (arbitrary amount that is paid for by paymentForExtraReceiverValue of this chain's wei) in targetChain wei.
*
* Any refunds (from leftover gas) will be sent to `refundAddress` on chain `refundChain`
* `targetAddress` must implement the IWormholeReceiver interface
*
* This function must be called with `msg.value` equal to
* quoteEVMDeliveryPrice(targetChain, receiverValue, gasLimit, deliveryProviderAddress) + paymentForExtraReceiverValue
*
* Note: MessageKeys can specify wormhole messages (VaaKeys) or other types of messages (ex. USDC CCTP attestations). Ensure the selected
* DeliveryProvider supports all the MessageKey.keyType values specified or it will not be delivered!
*
* @param targetChain in Wormhole Chain ID format
* @param targetAddress address to call on targetChain (that implements IWormholeReceiver)
* @param payload arbitrary bytes to pass in as parameter in call to `targetAddress`
* @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units)
* @param paymentForExtraReceiverValue amount (in current chain currency units) to spend on extra receiverValue
* (in addition to the `receiverValue` specified)
* @param gasLimit gas limit with which to call `targetAddress`. Any units of gas unused will be refunded according to the
* `targetChainRefundPerGasUnused` rate quoted by the delivery provider
* @param refundChain The chain to deliver any refund to, in Wormhole Chain ID format
* @param refundAddress The address on `refundChain` to deliver any refund to
* @param deliveryProviderAddress The address of the desired delivery provider's implementation of IDeliveryProvider
* @param messageKeys Additional messagess to pass in as parameter in call to `targetAddress`
* @param consistencyLevel Consistency level with which to publish the delivery instructions - see
* https://book.wormhole.com/wormhole/3_coreLayerContracts.html?highlight=consistency#consistency-levels
* @return sequence sequence number of published VAA containing delivery instructions
*/
function sendToEvm(
uint16 targetChain,
address targetAddress,
bytes memory payload,
uint256 receiverValue,
uint256 paymentForExtraReceiverValue,
uint256 gasLimit,
uint16 refundChain,
address refundAddress,
address deliveryProviderAddress,
MessageKey[] memory messageKeys,
uint8 consistencyLevel
) external payable returns (uint64 sequence);
/**
* @notice Publishes an instruction for the delivery provider at `deliveryProviderAddress`
* to relay a payload and VAAs specified by `vaaKeys` to the address `targetAddress` on chain `targetChain`
* with `msg.value` equal to
* receiverValue + (arbitrary amount that is paid for by paymentForExtraReceiverValue of this chain's wei) in targetChain wei.
*
* Any refunds (from leftover gas) will be sent to `refundAddress` on chain `refundChain`
* `targetAddress` must implement the IWormholeReceiver interface
*
* This function must be called with `msg.value` equal to
* quoteDeliveryPrice(targetChain, receiverValue, encodedExecutionParameters, deliveryProviderAddress) + paymentForExtraReceiverValue
*
* @param targetChain in Wormhole Chain ID format
* @param targetAddress address to call on targetChain (that implements IWormholeReceiver), in Wormhole bytes32 format
* @param payload arbitrary bytes to pass in as parameter in call to `targetAddress`
* @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units)
* @param paymentForExtraReceiverValue amount (in current chain currency units) to spend on extra receiverValue
* (in addition to the `receiverValue` specified)
* @param encodedExecutionParameters encoded information on how to execute delivery that may impact pricing
* e.g. for version EVM_V1, this is a struct that encodes the `gasLimit` with which to call `targetAddress`
* @param refundChain The chain to deliver any refund to, in Wormhole Chain ID format
* @param refundAddress The address on `refundChain` to deliver any refund to, in Wormhole bytes32 format
* @param deliveryProviderAddress The address of the desired delivery provider's implementation of IDeliveryProvider
* @param vaaKeys Additional VAAs to pass in as parameter in call to `targetAddress`
* @param consistencyLevel Consistency level with which to publish the delivery instructions - see
* https://book.wormhole.com/wormhole/3_coreLayerContracts.html?highlight=consistency#consistency-levels
* @return sequence sequence number of published VAA containing delivery instructions
*/
function send(
uint16 targetChain,
bytes32 targetAddress,
bytes memory payload,
uint256 receiverValue,
uint256 paymentForExtraReceiverValue,
bytes memory encodedExecutionParameters,
uint16 refundChain,
bytes32 refundAddress,
address deliveryProviderAddress,
VaaKey[] memory vaaKeys,
uint8 consistencyLevel
) external payable returns (uint64 sequence);
/**
* @notice Publishes an instruction for the delivery provider at `deliveryProviderAddress`
* to relay a payload and VAAs specified by `vaaKeys` to the address `targetAddress` on chain `targetChain`
* with `msg.value` equal to
* receiverValue + (arbitrary amount that is paid for by paymentForExtraReceiverValue of this chain's wei) in targetChain wei.
*
* Any refunds (from leftover gas) will be sent to `refundAddress` on chain `refundChain`
* `targetAddress` must implement the IWormholeReceiver interface
*
* This function must be called with `msg.value` equal to
* quoteDeliveryPrice(targetChain, receiverValue, encodedExecutionParameters, deliveryProviderAddress) + paymentForExtraReceiverValue
*
* Note: MessageKeys can specify wormhole messages (VaaKeys) or other types of messages (ex. USDC CCTP attestations). Ensure the selected
* DeliveryProvider supports all the MessageKey.keyType values specified or it will not be delivered!
*
* @param targetChain in Wormhole Chain ID format
* @param targetAddress address to call on targetChain (that implements IWormholeReceiver), in Wormhole bytes32 format
* @param payload arbitrary bytes to pass in as parameter in call to `targetAddress`
* @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units)
* @param paymentForExtraReceiverValue amount (in current chain currency units) to spend on extra receiverValue
* (in addition to the `receiverValue` specified)
* @param encodedExecutionParameters encoded information on how to execute delivery that may impact pricing
* e.g. for version EVM_V1, this is a struct that encodes the `gasLimit` with which to call `targetAddress`
* @param refundChain The chain to deliver any refund to, in Wormhole Chain ID format
* @param refundAddress The address on `refundChain` to deliver any refund to, in Wormhole bytes32 format
* @param deliveryProviderAddress The address of the desired delivery provider's implementation of IDeliveryProvider
* @param messageKeys Additional messagess to pass in as parameter in call to `targetAddress`
* @param consistencyLevel Consistency level with which to publish the delivery instructions - see
* https://book.wormhole.com/wormhole/3_coreLayerContracts.html?highlight=consistency#consistency-levels
* @return sequence sequence number of published VAA containing delivery instructions
*/
function send(
uint16 targetChain,
bytes32 targetAddress,
bytes memory payload,
uint256 receiverValue,
uint256 paymentForExtraReceiverValue,
bytes memory encodedExecutionParameters,
uint16 refundChain,
bytes32 refundAddress,
address deliveryProviderAddress,
MessageKey[] memory messageKeys,
uint8 consistencyLevel
) external payable returns (uint64 sequence);
/**
* @notice Requests a previously published delivery instruction to be redelivered
* (e.g. with a different delivery provider)
*
* This function must be called with `msg.value` equal to
* quoteEVMDeliveryPrice(targetChain, newReceiverValue, newGasLimit, newDeliveryProviderAddress)
*
* @notice *** This will only be able to succeed if the following is true **
* - newGasLimit >= gas limit of the old instruction
* - newReceiverValue >= receiver value of the old instruction
* - newDeliveryProvider's `targetChainRefundPerGasUnused` >= old relay provider's `targetChainRefundPerGasUnused`
*
* @param deliveryVaaKey VaaKey identifying the wormhole message containing the
* previously published delivery instructions
* @param targetChain The target chain that the original delivery targeted. Must match targetChain from original delivery instructions
* @param newReceiverValue new msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units)
* @param newGasLimit gas limit with which to call `targetAddress`. Any units of gas unused will be refunded according to the
* `targetChainRefundPerGasUnused` rate quoted by the delivery provider, to the refund chain and address specified in the original request
* @param newDeliveryProviderAddress The address of the desired delivery provider's implementation of IDeliveryProvider
* @return sequence sequence number of published VAA containing redelivery instructions
*
* @notice *** This will only be able to succeed if the following is true **
* - newGasLimit >= gas limit of the old instruction
* - newReceiverValue >= receiver value of the old instruction
*/
function resendToEvm(
VaaKey memory deliveryVaaKey,
uint16 targetChain,
uint256 newReceiverValue,
uint256 newGasLimit,
address newDeliveryProviderAddress
) external payable returns (uint64 sequence);
/**
* @notice Requests a previously published delivery instruction to be redelivered
*
*
* This function must be called with `msg.value` equal to
* quoteDeliveryPrice(targetChain, newReceiverValue, newEncodedExecutionParameters, newDeliveryProviderAddress)
*
* @param deliveryVaaKey VaaKey identifying the wormhole message containing the
* previously published delivery instructions
* @param targetChain The target chain that the original delivery targeted. Must match targetChain from original delivery instructions
* @param newReceiverValue new msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units)
* @param newEncodedExecutionParameters new encoded information on how to execute delivery that may impact pricing
* e.g. for version EVM_V1, this is a struct that encodes the `gasLimit` with which to call `targetAddress`
* @param newDeliveryProviderAddress The address of the desired delivery provider's implementation of IDeliveryProvider
* @return sequence sequence number of published VAA containing redelivery instructions
*
* @notice *** This will only be able to succeed if the following is true **
* - (For EVM_V1) newGasLimit >= gas limit of the old instruction
* - newReceiverValue >= receiver value of the old instruction
* - (For EVM_V1) newDeliveryProvider's `targetChainRefundPerGasUnused` >= old relay provider's `targetChainRefundPerGasUnused`
*/
function resend(
VaaKey memory deliveryVaaKey,
uint16 targetChain,
uint256 newReceiverValue,
bytes memory newEncodedExecutionParameters,
address newDeliveryProviderAddress
) external payable returns (uint64 sequence);
/**
* @notice Returns the price to request a relay to chain `targetChain`, using the default delivery provider
*
* @param targetChain in Wormhole Chain ID format
* @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units)
* @param gasLimit gas limit with which to call `targetAddress`.
* @return nativePriceQuote Price, in units of current chain currency, that the delivery provider charges to perform the relay
* @return targetChainRefundPerGasUnused amount of target chain currency that will be refunded per unit of gas unused,
* if a refundAddress is specified.
* Note: This value can be overridden by the delivery provider on the target chain. The returned value here should be considered to be a
* promise by the delivery provider of the amount of refund per gas unused that will be returned to the refundAddress at the target chain.
* If a delivery provider decides to override, this will be visible as part of the emitted Delivery event on the target chain.
*/
function quoteEVMDeliveryPrice(
uint16 targetChain,
uint256 receiverValue,
uint256 gasLimit
)
external
view
returns (
uint256 nativePriceQuote,
uint256 targetChainRefundPerGasUnused
);
/**
* @notice Returns the price to request a relay to chain `targetChain`, using delivery provider `deliveryProviderAddress`
*
* @param targetChain in Wormhole Chain ID format
* @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units)
* @param gasLimit gas limit with which to call `targetAddress`.
* @param deliveryProviderAddress The address of the desired delivery provider's implementation of IDeliveryProvider
* @return nativePriceQuote Price, in units of current chain currency, that the delivery provider charges to perform the relay
* @return targetChainRefundPerGasUnused amount of target chain currency that will be refunded per unit of gas unused,
* if a refundAddress is specified
* Note: This value can be overridden by the delivery provider on the target chain. The returned value here should be considered to be a
* promise by the delivery provider of the amount of refund per gas unused that will be returned to the refundAddress at the target chain.
* If a delivery provider decides to override, this will be visible as part of the emitted Delivery event on the target chain.
*/
function quoteEVMDeliveryPrice(
uint16 targetChain,
uint256 receiverValue,
uint256 gasLimit,
address deliveryProviderAddress
)
external
view
returns (
uint256 nativePriceQuote,
uint256 targetChainRefundPerGasUnused
);
/**
* @notice Returns the price to request a relay to chain `targetChain`, using delivery provider `deliveryProviderAddress`
*
* @param targetChain in Wormhole Chain ID format
* @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units)
* @param encodedExecutionParameters encoded information on how to execute delivery that may impact pricing
* e.g. for version EVM_V1, this is a struct that encodes the `gasLimit` with which to call `targetAddress`
* @param deliveryProviderAddress The address of the desired delivery provider's implementation of IDeliveryProvider
* @return nativePriceQuote Price, in units of current chain currency, that the delivery provider charges to perform the relay
* @return encodedExecutionInfo encoded information on how the delivery will be executed
* e.g. for version EVM_V1, this is a struct that encodes the `gasLimit` and `targetChainRefundPerGasUnused`
* (which is the amount of target chain currency that will be refunded per unit of gas unused,
* if a refundAddress is specified)
*/
function quoteDeliveryPrice(
uint16 targetChain,
uint256 receiverValue,
bytes memory encodedExecutionParameters,
address deliveryProviderAddress
)
external
view
returns (uint256 nativePriceQuote, bytes memory encodedExecutionInfo);
/**
* @notice Returns the (extra) amount of target chain currency that `targetAddress`
* will be called with, if the `paymentForExtraReceiverValue` field is set to `currentChainAmount`
*
* @param targetChain in Wormhole Chain ID format
* @param currentChainAmount The value that `paymentForExtraReceiverValue` will be set to
* @param deliveryProviderAddress The address of the desired delivery provider's implementation of IDeliveryProvider
* @return targetChainAmount The amount such that if `targetAddress` will be called with `msg.value` equal to
* receiverValue + targetChainAmount
*/
function quoteNativeForChain(
uint16 targetChain,
uint256 currentChainAmount,
address deliveryProviderAddress
) external view returns (uint256 targetChainAmount);
/**
* @notice Returns the address of the current default delivery provider
* @return deliveryProvider The address of (the default delivery provider)'s contract on this source
* chain. This must be a contract that implements IDeliveryProvider.
*/
function getDefaultDeliveryProvider()
external
view
returns (address deliveryProvider);
}
/**
* @title IWormholeRelayerDelivery
* @notice The interface to execute deliveries. Only relevant for Delivery Providers
*/
interface IWormholeRelayerDelivery is IWormholeRelayerBase {
enum DeliveryStatus {
SUCCESS,
RECEIVER_FAILURE
}
enum RefundStatus {
REFUND_SENT,
REFUND_FAIL,
CROSS_CHAIN_REFUND_SENT,
CROSS_CHAIN_REFUND_FAIL_PROVIDER_NOT_SUPPORTED,
CROSS_CHAIN_REFUND_FAIL_NOT_ENOUGH,
NO_REFUND_REQUESTED
}
/**
* @custom:member recipientContract - The target contract address
* @custom:member sourceChain - The chain which this delivery was requested from (in wormhole
* ChainID format)
* @custom:member sequence - The wormhole sequence number of the delivery VAA on the source chain
* corresponding to this delivery request
* @custom:member deliveryVaaHash - The hash of the delivery VAA corresponding to this delivery
* request
* @custom:member gasUsed - The amount of gas that was used to call your target contract
* @custom:member status:
* - RECEIVER_FAILURE, if the target contract reverts
* - SUCCESS, if the target contract doesn't revert
* @custom:member additionalStatusInfo:
* - If status is SUCCESS, then this is empty.
* - If status is RECEIVER_FAILURE, this is `RETURNDATA_TRUNCATION_THRESHOLD` bytes of the
* return data (i.e. potentially truncated revert reason information).
* @custom:member refundStatus - Result of the refund. REFUND_SUCCESS or REFUND_FAIL are for
* refunds where targetChain=refundChain; the others are for targetChain!=refundChain,
* where a cross chain refund is necessary, or if the default code path is used where no refund is requested (NO_REFUND_REQUESTED)
* @custom:member overridesInfo:
* - If not an override: empty bytes array
* - Otherwise: An encoded `DeliveryOverride`
*/
event Delivery(
address indexed recipientContract,
uint16 indexed sourceChain,
uint64 indexed sequence,
bytes32 deliveryVaaHash,
DeliveryStatus status,
uint256 gasUsed,
RefundStatus refundStatus,
bytes additionalStatusInfo,
bytes overridesInfo
);
/**
* @notice The delivery provider calls `deliver` to relay messages as described by one delivery instruction
*
* The delivery provider must pass in the specified (by VaaKeys[]) signed wormhole messages (VAAs) from the source chain
* as well as the signed wormhole message with the delivery instructions (the delivery VAA)
*
* The messages will be relayed to the target address (with the specified gas limit and receiver value) iff the following checks are met:
* - the delivery VAA has a valid signature
* - the delivery VAA's emitter is one of these WormholeRelayer contracts
* - the delivery provider passed in at least enough of this chain's currency as msg.value (enough meaning the maximum possible refund)
* - the instruction's target chain is this chain
* - the relayed signed VAAs match the descriptions in container.messages (the VAA hashes match, or the emitter address, sequence number pair matches, depending on the description given)
*
* @param encodedVMs - An array of signed wormhole messages (all from the same source chain
* transaction)
* @param encodedDeliveryVAA - Signed wormhole message from the source chain's WormholeRelayer
* contract with payload being the encoded delivery instruction container
* @param relayerRefundAddress - The address to which any refunds to the delivery provider
* should be sent
* @param deliveryOverrides - Optional overrides field which must be either an empty bytes array or
* an encoded DeliveryOverride struct
*/
function deliver(
bytes[] memory encodedVMs,
bytes memory encodedDeliveryVAA,
address payable relayerRefundAddress,
bytes memory deliveryOverrides
) external payable;
}
interface IWormholeRelayer is IWormholeRelayerDelivery, IWormholeRelayerSend {}
/*
* Errors thrown by IWormholeRelayer contract
*/
// Bound chosen by the following formula: `memoryWord * 4 + selectorSize`.
// This means that an error identifier plus four fixed size arguments should be available to developers.
// In the case of a `require` revert with error message, this should provide 2 memory word's worth of data.
uint256 constant RETURNDATA_TRUNCATION_THRESHOLD = 132;
//When msg.value was not equal to `delivery provider's quoted delivery price` + `paymentForExtraReceiverValue`
error InvalidMsgValue(uint256 msgValue, uint256 totalFee);
error RequestedGasLimitTooLow();
error DeliveryProviderDoesNotSupportTargetChain(
address relayer,
uint16 chainId
);
error DeliveryProviderCannotReceivePayment();
error DeliveryProviderDoesNotSupportMessageKeyType(uint8 keyType);
//When calling `delivery()` a second time even though a delivery is already in progress
error ReentrantDelivery(address msgSender, address lockedBy);
error InvalidPayloadId(uint8 parsed, uint8 expected);
error InvalidPayloadLength(uint256 received, uint256 expected);
error InvalidVaaKeyType(uint8 parsed);
error TooManyMessageKeys(uint256 numMessageKeys);
error InvalidDeliveryVaa(string reason);
//When the delivery VAA (signed wormhole message with delivery instructions) was not emitted by the
// registered WormholeRelayer contract
error InvalidEmitter(bytes32 emitter, bytes32 registered, uint16 chainId);
error MessageKeysLengthDoesNotMatchMessagesLength(uint256 keys, uint256 vaas);
error VaaKeysDoNotMatchVaas(uint8 index);
//When someone tries to call an external function of the WormholeRelayer that is only intended to be
// called by the WormholeRelayer itself (to allow retroactive reverts for atomicity)
error RequesterNotWormholeRelayer();
//When trying to relay a `DeliveryInstruction` to any other chain but the one it was specified for
error TargetChainIsNotThisChain(uint16 targetChain);
//When a `DeliveryOverride` contains a gas limit that's less than the original
error InvalidOverrideGasLimit();
//When a `DeliveryOverride` contains a receiver value that's less than the original
error InvalidOverrideReceiverValue();
//When a `DeliveryOverride` contains a 'refund per unit of gas unused' that's less than the original
error InvalidOverrideRefundPerGasUnused();
//When the delivery provider doesn't pass in sufficient funds (i.e. msg.value does not cover the
// maximum possible refund to the user)
error InsufficientRelayerFunds(uint256 msgValue, uint256 minimum);
//When a bytes32 field can't be converted into a 20 byte EVM address, because the 12 padding bytes
// are non-zero (duplicated from Utils.sol)
error NotAnEvmAddress(bytes32);{
"remappings": [
"lib/wormhole/ethereum:@openzeppelin/contracts/=lib/openzeppelin-contracts-4/contracts/",
"@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
"wormhole/=lib/wormhole/ethereum/contracts/",
"wormhole-sdk/=lib/wormhole-solidity-sdk/src/",
"src/=src/",
"test/=test/",
"script/=script/",
"@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
"ds-test/=lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/src/",
"erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
"forge-std/=lib/forge-std/src/",
"openzeppelin-contracts-4/=lib/openzeppelin-contracts-4/",
"openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/",
"wormhole-solidity-sdk/=lib/wormhole-solidity-sdk/src/"
],
"optimizer": {
"enabled": true,
"runs": 17750
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "paris",
"viaIR": false,
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_core","type":"address"},{"internalType":"address","name":"_hubGovernor","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ChainIdMismatch","type":"error"},{"inputs":[],"name":"CheckpointUnorderedInsertion","type":"error"},{"inputs":[],"name":"EmptyWormholeAddress","type":"error"},{"inputs":[{"internalType":"uint8","name":"val","type":"uint8"}],"name":"InvalidBoolVal","type":"error"},{"inputs":[],"name":"InvalidChainId","type":"error"},{"inputs":[],"name":"InvalidContractAddress","type":"error"},{"inputs":[],"name":"InvalidFunctionSignature","type":"error"},{"inputs":[{"internalType":"uint256","name":"received","type":"uint256"},{"internalType":"uint256","name":"expected","type":"uint256"}],"name":"InvalidPayloadLength","type":"error"},{"inputs":[],"name":"InvalidProposalVote","type":"error"},{"inputs":[],"name":"InvalidQueryVoteImpl","type":"error"},{"inputs":[],"name":"InvalidResponseVersion","type":"error"},{"inputs":[],"name":"NumberOfResponsesMismatch","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"RequestTypeMismatch","type":"error"},{"inputs":[{"internalType":"uint8","name":"bits","type":"uint8"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"SafeCastOverflowedUintDowncast","type":"error"},{"inputs":[],"name":"StaleBlockNum","type":"error"},{"inputs":[],"name":"StaleBlockTime","type":"error"},{"inputs":[],"name":"UnexpectedNumberOfResults","type":"error"},{"inputs":[{"internalType":"uint8","name":"received","type":"uint8"}],"name":"UnsupportedQueryType","type":"error"},{"inputs":[],"name":"UnsupportedQueryType","type":"error"},{"inputs":[],"name":"VersionMismatch","type":"error"},{"inputs":[{"internalType":"uint8","name":"received","type":"uint8"},{"internalType":"uint8","name":"expected","type":"uint8"}],"name":"WrongQueryType","type":"error"},{"inputs":[],"name":"ZeroQueries","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldGovernor","type":"address"},{"indexed":false,"internalType":"address","name":"newGovernor","type":"address"}],"name":"HubGovernorUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint8","name":"queryType","type":"uint8"},{"indexed":false,"internalType":"address","name":"oldQueryTypeImpl","type":"address"},{"indexed":false,"internalType":"address","name":"newQueryTypeImpl","type":"address"}],"name":"QueryTypeRegistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint16","name":"targetChain","type":"uint16"},{"indexed":false,"internalType":"bytes32","name":"oldSpokeVoteAddress","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"newSpokeVoteAddress","type":"bytes32"}],"name":"SpokeRegistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint16","name":"emitterChainId","type":"uint16"},{"indexed":false,"internalType":"uint256","name":"proposalId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"voteAgainst","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"voteFor","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"voteAbstain","type":"uint256"}],"name":"SpokeVoteCast","type":"event"},{"inputs":[],"name":"QT_ETH_CALL","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"QT_ETH_CALL_BY_TIMESTAMP","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"QT_ETH_CALL_WITH_FINALITY","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"QT_MAX","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"QT_SOL_ACCOUNT","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"QT_SOL_PDA","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VERSION","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"_queryResponseRaw","type":"bytes"},{"components":[{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"uint8","name":"guardianIndex","type":"uint8"}],"internalType":"struct IWormhole.Signature[]","name":"_signatures","type":"tuple[]"}],"name":"crossChainVote","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"response","type":"bytes"}],"name":"getResponseDigest","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"response","type":"bytes"}],"name":"getResponseHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint16","name":"_emitterChainId","type":"uint16"},{"internalType":"uint256","name":"_timepoint","type":"uint256"}],"name":"getSpoke","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"hubGovernor","outputs":[{"internalType":"contract IGovernor","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"response","type":"bytes"},{"components":[{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"uint8","name":"guardianIndex","type":"uint8"}],"internalType":"struct IWormhole.Signature[]","name":"signatures","type":"tuple[]"}],"name":"parseAndVerifyQueryResponse","outputs":[{"components":[{"internalType":"uint8","name":"version","type":"uint8"},{"internalType":"uint16","name":"senderChainId","type":"uint16"},{"internalType":"uint32","name":"nonce","type":"uint32"},{"internalType":"bytes","name":"requestId","type":"bytes"},{"components":[{"internalType":"uint16","name":"chainId","type":"uint16"},{"internalType":"uint8","name":"queryType","type":"uint8"},{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"bytes","name":"response","type":"bytes"}],"internalType":"struct ParsedPerChainQueryResponse[]","name":"responses","type":"tuple[]"}],"internalType":"struct ParsedQueryResponse","name":"r","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint16","name":"chainId","type":"uint16"},{"internalType":"uint8","name":"queryType","type":"uint8"},{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"bytes","name":"response","type":"bytes"}],"internalType":"struct ParsedPerChainQueryResponse","name":"pcr","type":"tuple"}],"name":"parseEthCallByTimestampQueryResponse","outputs":[{"components":[{"internalType":"bytes","name":"requestTargetBlockIdHint","type":"bytes"},{"internalType":"bytes","name":"requestFollowingBlockIdHint","type":"bytes"},{"internalType":"uint64","name":"requestTargetTimestamp","type":"uint64"},{"internalType":"uint64","name":"targetBlockNum","type":"uint64"},{"internalType":"uint64","name":"targetBlockTime","type":"uint64"},{"internalType":"uint64","name":"followingBlockNum","type":"uint64"},{"internalType":"bytes32","name":"targetBlockHash","type":"bytes32"},{"internalType":"bytes32","name":"followingBlockHash","type":"bytes32"},{"internalType":"uint64","name":"followingBlockTime","type":"uint64"},{"components":[{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"bytes","name":"result","type":"bytes"}],"internalType":"struct EthCallData[]","name":"result","type":"tuple[]"}],"internalType":"struct EthCallByTimestampQueryResponse","name":"r","type":"tuple"}],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"internalType":"uint16","name":"chainId","type":"uint16"},{"internalType":"uint8","name":"queryType","type":"uint8"},{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"bytes","name":"response","type":"bytes"}],"internalType":"struct ParsedPerChainQueryResponse","name":"pcr","type":"tuple"}],"name":"parseEthCallQueryResponse","outputs":[{"components":[{"internalType":"bytes","name":"requestBlockId","type":"bytes"},{"internalType":"uint64","name":"blockNum","type":"uint64"},{"internalType":"uint64","name":"blockTime","type":"uint64"},{"internalType":"bytes32","name":"blockHash","type":"bytes32"},{"components":[{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"bytes","name":"result","type":"bytes"}],"internalType":"struct EthCallData[]","name":"result","type":"tuple[]"}],"internalType":"struct EthCallQueryResponse","name":"r","type":"tuple"}],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"internalType":"uint16","name":"chainId","type":"uint16"},{"internalType":"uint8","name":"queryType","type":"uint8"},{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"bytes","name":"response","type":"bytes"}],"internalType":"struct ParsedPerChainQueryResponse","name":"pcr","type":"tuple"}],"name":"parseEthCallWithFinalityQueryResponse","outputs":[{"components":[{"internalType":"bytes","name":"requestBlockId","type":"bytes"},{"internalType":"bytes","name":"requestFinality","type":"bytes"},{"internalType":"uint64","name":"blockNum","type":"uint64"},{"internalType":"uint64","name":"blockTime","type":"uint64"},{"internalType":"bytes32","name":"blockHash","type":"bytes32"},{"components":[{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"bytes","name":"result","type":"bytes"}],"internalType":"struct EthCallData[]","name":"result","type":"tuple[]"}],"internalType":"struct EthCallWithFinalityQueryResponse","name":"r","type":"tuple"}],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"internalType":"uint16","name":"chainId","type":"uint16"},{"internalType":"uint8","name":"queryType","type":"uint8"},{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"bytes","name":"response","type":"bytes"}],"internalType":"struct ParsedPerChainQueryResponse","name":"pcr","type":"tuple"}],"name":"parseSolanaAccountQueryResponse","outputs":[{"components":[{"internalType":"bytes","name":"requestCommitment","type":"bytes"},{"internalType":"uint64","name":"requestMinContextSlot","type":"uint64"},{"internalType":"uint64","name":"requestDataSliceOffset","type":"uint64"},{"internalType":"uint64","name":"requestDataSliceLength","type":"uint64"},{"internalType":"uint64","name":"slotNumber","type":"uint64"},{"internalType":"uint64","name":"blockTime","type":"uint64"},{"internalType":"bytes32","name":"blockHash","type":"bytes32"},{"components":[{"internalType":"bytes32","name":"account","type":"bytes32"},{"internalType":"uint64","name":"lamports","type":"uint64"},{"internalType":"uint64","name":"rentEpoch","type":"uint64"},{"internalType":"bool","name":"executable","type":"bool"},{"internalType":"bytes32","name":"owner","type":"bytes32"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct SolanaAccountResult[]","name":"results","type":"tuple[]"}],"internalType":"struct SolanaAccountQueryResponse","name":"r","type":"tuple"}],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"internalType":"uint16","name":"chainId","type":"uint16"},{"internalType":"uint8","name":"queryType","type":"uint8"},{"internalType":"bytes","name":"request","type":"bytes"},{"internalType":"bytes","name":"response","type":"bytes"}],"internalType":"struct ParsedPerChainQueryResponse","name":"pcr","type":"tuple"}],"name":"parseSolanaPdaQueryResponse","outputs":[{"components":[{"internalType":"bytes","name":"requestCommitment","type":"bytes"},{"internalType":"uint64","name":"requestMinContextSlot","type":"uint64"},{"internalType":"uint64","name":"requestDataSliceOffset","type":"uint64"},{"internalType":"uint64","name":"requestDataSliceLength","type":"uint64"},{"internalType":"uint64","name":"slotNumber","type":"uint64"},{"internalType":"uint64","name":"blockTime","type":"uint64"},{"internalType":"bytes32","name":"blockHash","type":"bytes32"},{"components":[{"internalType":"bytes32","name":"programId","type":"bytes32"},{"internalType":"bytes[]","name":"seeds","type":"bytes[]"},{"internalType":"bytes32","name":"account","type":"bytes32"},{"internalType":"uint64","name":"lamports","type":"uint64"},{"internalType":"uint64","name":"rentEpoch","type":"uint64"},{"internalType":"bool","name":"executable","type":"bool"},{"internalType":"bytes32","name":"owner","type":"bytes32"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint8","name":"bump","type":"uint8"}],"internalType":"struct SolanaPdaResult[]","name":"results","type":"tuple[]"}],"internalType":"struct SolanaPdaQueryResponse","name":"r","type":"tuple"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint8","name":"_queryType","type":"uint8"},{"internalType":"address","name":"_implementation","type":"address"}],"name":"registerQueryType","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_targetChain","type":"uint16"},{"internalType":"bytes32","name":"_spokeVoteAddress","type":"bytes32"}],"name":"registerSpoke","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint16","name":"wormholeChainId","type":"uint16"},{"internalType":"bytes32","name":"wormholeAddress","type":"bytes32"}],"internalType":"struct HubVotePool.SpokeVoteAggregator[]","name":"_spokes","type":"tuple[]"}],"name":"registerSpokes","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"responsePrefix","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_newGovernor","type":"address"}],"name":"setGovernor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"spokeProposalId","type":"bytes32"}],"name":"spokeProposalVotes","outputs":[{"internalType":"uint256","name":"againstVotes","type":"uint256"},{"internalType":"uint256","name":"forVotes","type":"uint256"},{"internalType":"uint256","name":"abstainVotes","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"_blockNum","type":"uint64"},{"internalType":"uint256","name":"_minBlockNum","type":"uint256"}],"name":"validateBlockNum","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint64","name":"_blockTime","type":"uint64"},{"internalType":"uint256","name":"_minBlockTime","type":"uint256"}],"name":"validateBlockTime","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint16","name":"chainId","type":"uint16"},{"internalType":"uint16[]","name":"_validChainIds","type":"uint16[]"}],"name":"validateChainId","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"bytes","name":"result","type":"bytes"}],"internalType":"struct EthCallData","name":"r","type":"tuple"},{"internalType":"address[]","name":"_expectedContractAddresses","type":"address[]"},{"internalType":"bytes4[]","name":"_expectedFunctionSignatures","type":"bytes4[]"}],"name":"validateEthCallData","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"bytes","name":"result","type":"bytes"}],"internalType":"struct EthCallData[]","name":"r","type":"tuple[]"},{"internalType":"address[]","name":"_expectedContractAddresses","type":"address[]"},{"internalType":"bytes4[]","name":"_expectedFunctionSignatures","type":"bytes4[]"}],"name":"validateMultipleEthCallData","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"response","type":"bytes"},{"components":[{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"uint8","name":"guardianIndex","type":"uint8"}],"internalType":"struct IWormhole.Signature[]","name":"signatures","type":"tuple[]"}],"name":"verifyQueryResponseSignatures","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"queryType","type":"uint8"}],"name":"voteTypeDecoder","outputs":[{"internalType":"contract ISpokeVoteDecoder","name":"voteImpl","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"wormhole","outputs":[{"internalType":"contract IWormhole","name":"","type":"address"}],"stateMutability":"view","type":"function"}]Contract Creation Code
0x60a06040523480156200001157600080fd5b50604051620090e8380380620090e88339810160408190526200003491620003d8565b80836001600160a01b0381166200005e57604051638ef9698f60e01b815260040160405180910390fd5b6001600160a01b0390811660805281166200009357604051631e4fbdf760e01b81526000600482015260240160405180910390fd5b6200009e816200010a565b5060008330604051620000b190620003ad565b6001600160a01b03928316815291166020820152604001604051809103906000f080158015620000e5573d6000803e3d6000fd5b509050620000f58160036200015a565b620001008362000257565b5050505062000422565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60ff81166000818152600460209081526040918290205482516001600160a01b039182168152908616918101919091527f605377a362d179f8f97f433900dc88f457846f29a6a43430b454a11f4995c385910160405180910390a26001600160a01b038216620001e65760ff16600090815260046020526040902080546001600160a01b031916905550565b6000620002046001600160a01b03841663da841d3960e01b620002c0565b905080620002255760405163d62f4a2760e01b815260040160405180910390fd5b5060ff16600090815260046020526040902080546001600160a01b0319166001600160a01b0392909216919091179055565b600154604080516001600160a01b03928316815291831660208301527f1deb63b37f154ad5b5f92db0edea9bccf74dc0c235e80a86242dfddb2e33a0ec910160405180910390a1600180546001600160a01b0319166001600160a01b0392909216919091179055565b6000620002cd83620002e8565b8015620002e15750620002e1838362000321565b9392505050565b6000620002fd826301ffc9a760e01b62000321565b80156200031b575062000319826001600160e01b031962000321565b155b92915050565b6040516001600160e01b031982166024820152600090819060440160408051601f19818403018152919052602080820180516001600160e01b03166301ffc9a760e01b178152825192935060009283928392909183918a617530fa92503d9150600051905082801562000395575060208210155b8015620003a25750600081115b979650505050505050565b6141d58062004f1383390190565b80516001600160a01b0381168114620003d357600080fd5b919050565b600080600060608486031215620003ee57600080fd5b620003f984620003bb565b92506200040960208501620003bb565b91506200041960408501620003bb565b90509250925092565b608051614ab96200045a6000396000818161041601528181610f1201528181610fee0152818161110c01526111fb0152614ab96000f3fe608060405234801561001057600080fd5b50600436106102415760003560e01c806384acd1bb11610145578063c42cf535116100bd578063e6a3c0e81161008c578063f2fde38b11610071578063f2fde38b1461054a578063fa2ae3601461055d578063ffa1ad741461038257600080fd5b8063e6a3c0e81461052f578063eb1d6b961461053757600080fd5b8063c42cf535146104d4578063c895dec6146104e7578063dc37e93e14610507578063e0b54d301461052757600080fd5b8063a8024ef111610114578063ba89369e116100f9578063ba89369e1461048c578063bda269f21461049f578063c008e156146104bf57600080fd5b8063a8024ef114610466578063b0bf66381461047957600080fd5b806384acd1bb146104115780638a8f2868146104385780638da5cb5b14610440578063a0f419fa1461045e57600080fd5b806345ee36c5116101d8578063571354e2116101a757806371b632c81161018c57806371b632c8146103c5578063767b9daa146103de57806378cc4030146103fe57600080fd5b8063571354e21461039d578063715018a6146103bd57600080fd5b806345ee36c51461035c57806347bdbbcf1461036f5780634d63d473146103825780634f098c0a1461038a57600080fd5b80632df2f978116102145780632df2f978146102bb57806331e0ff7a146102db5780633896fc121461033657806345e16cd31461034957600080fd5b806316476dcc146102465780632ac96ea11461025b5780632b2077ad146102815780632b7e1cd8146102a1575b600080fd5b610259610254366004613568565b6105a7565b005b61026e6102693660046135b1565b610601565b6040519081526020015b60405180910390f35b61029461028f366004613732565b610627565b6040516102789190613978565b6102a9600281565b60405160ff9091168152602001610278565b6102ce6102c9366004613732565b610c06565b6040516102789190613acb565b6103116102e9366004613b32565b60046020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610278565b610259610344366004613b71565b610f0e565b610259610357366004613c74565b6112e1565b61025961036a366004613568565b611332565b61025961037d366004613ecd565b611376565b6102a9600181565b610259610398366004613f55565b611516565b6103b06103ab366004613b71565b611556565b604051610278919061405d565b610259611b02565b61026e6103d336600461410c565b805160209091012090565b6001546103119073ffffffffffffffffffffffffffffffffffffffff1681565b61025961040c366004614149565b611b16565b6103117f000000000000000000000000000000000000000000000000000000000000000081565b6102a9600681565b60005473ffffffffffffffffffffffffffffffffffffffff16610311565b6102a9600381565b61026e61047436600461410c565b611b9c565b610259610487366004613b71565b611bec565b61025961049a3660046141f8565b611ec3565b6104b26104ad366004613732565b611ed5565b604051610278919061422f565b6104c76122a4565b6040516102789190614321565b6102596104e2366004614334565b6122c0565b6104fa6104f5366004613732565b6122d4565b60405161027891906143f2565b61051a610515366004613732565b6126ee565b60405161027891906144a9565b6102a9600481565b6102a9600581565b6102596105453660046135b1565b612a52565b610259610558366004614334565b612a64565b61058c61056b366004614530565b60036020526000908152604090208054600182015460029092015490919083565b60408051938452602084019290925290820152606001610278565b60006105b6620f4240846145a7565b67ffffffffffffffff169050818110156105fc576040517f3a04ceca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050565b61ffff8216600090815260026020526040812061061e9083612ac5565b90505b92915050565b60408051610100810182526060808252600060208084018290529383018190528183018190526080830181905260a0830181905260c083015260e08201529082015160ff166005146106bc5760208201516040517f96b8e05b00000000000000000000000000000000000000000000000000000000815260ff9091166004820152600560248201526044015b60405180910390fd5b60008060006106d8838660400151612b1e90919063ffffffff16565b60408701519094509091506106f7908463ffffffff80851690612b2c16565b90855260408681018051830160089081015167ffffffffffffffff90811660208a0152825185016010908101518216948a0194909452825185016018015181166060808b019190915292518501601990810151938b018051890190930151821660808b01528251880185015190911660a08a01529051930195509301929061077f9084612bbd565b60c0870191909152606087015160019082018101519101935060ff828116908216146107d7576040517f5e7bd6ec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8160ff1667ffffffffffffffff8111156107f3576107f36135cf565b60405190808252806020026020018201604052801561088757816020015b60408051610120810182526000808252606060208084018290529383018290528083018290526080830182905260a0830182905260c0830182905260e083015261010082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019101816108115790505b5060e087015260005b8260ff16811015610bdf5760408801516108aa9087612bbd565b8860e0015183815181106108c0576108c06145ce565b602090810291909101015191909152604089015160019082018101519101965060ff811667ffffffffffffffff8111156108fc576108fc6135cf565b60405190808252806020026020018201604052801561092f57816020015b606081526020019060019003908161091a5790505b508860e001518381518110610946576109466145ce565b60200260200101516020018190525060005b8160ff168110156109d45760408a0151600489820181015199019890610988908a63ffffffff80851690612b2c16565b8b60e00151868151811061099e5761099e6145ce565b60200260200101516020015184815181106109bb576109bb6145ce565b6020908102919091010191909152985050600101610958565b5060608901516109e49087612bbd565b8960e0015184815181106109fa576109fa6145ce565b6020026020010151604001819850828152505050610a25868a60600151612baf90919063ffffffff16565b8960e001518481518110610a3b57610a3b6145ce565b6020026020010151610100018198508260ff1660ff168152505050610a6d868a60600151612ba190919063ffffffff16565b8960e001518481518110610a8357610a836145ce565b602090810291909101015167ffffffffffffffff92909216606092830152908a0151810160089081015191975087018960e001518481518110610ac857610ac86145ce565b60200260200101516080018198508267ffffffffffffffff1667ffffffffffffffff168152505050610b07868a60600151612be390919063ffffffff16565b8960e001518481518110610b1d57610b1d6145ce565b602002602001015160a00181985082151515158152505050610b4c868a60600151612bbd90919063ffffffff16565b8960e001518481518110610b6257610b626145ce565b602002602001015160c001819850828152505050610b8d868a60600151612b1e90919063ffffffff16565b60608b0151909750909550610bac908763ffffffff80891690612b2c16565b8960e001518481518110610bc257610bc26145ce565b602090810291909101015160e00191909152955050600101610890565b50610bee876040015186612c51565b610bfc876060015185612c51565b5050505050919050565b6040805160a0810182526060808252600060208084018290529383018190528183015260808201529082015160ff16600114610c805760208201516040517f96b8e05b00000000000000000000000000000000000000000000000000000000815260ff9091166004820152600160248201526044016106b3565b6000806000610c9c838660400151612b1e90919063ffffffff16565b6040870151909450909150610cbb908463ffffffff80851690612b2c16565b90855260408601516001908201810151606088018051600890870181015167ffffffffffffffff1660208a015290519290930195509190930192610cff9084612bbd565b606087810192909252908701805182016008015167ffffffffffffffff1660408801525181016009908101519101935060ff80821690831614610d6e576040517f5e7bd6ec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8160ff1667ffffffffffffffff811115610d8a57610d8a6135cf565b604051908082528060200260200182016040528015610df557816020015b610de26040518060600160405280600073ffffffffffffffffffffffffffffffffffffffff16815260200160608152602001606081525090565b815260200190600190039081610da85790505b50608087015260005b8260ff16811015610bdf576040880151610e189087612c98565b88608001518381518110610e2e57610e2e6145ce565b602090810291909101015173ffffffffffffffffffffffffffffffffffffffff929092169091526040890151600481830181015192019750909450610e7d908763ffffffff80881690612b2c16565b88608001518381518110610e9357610e936145ce565b60200260200101516020018198508290525050610ebd858960600151612b1e90919063ffffffff16565b60608a0151909650909450610edc908663ffffffff80881690612b2c16565b88608001518381518110610ef257610ef26145ce565b6020908102919091010151604001919091529450600101610dfe565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16631cfe79516040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f7b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f9f9190614611565b6040517ff951975a00000000000000000000000000000000000000000000000000000000815263ffffffff8216600482015290915060009073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063f951975a90602401600060405180830381865afa158015611035573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261105d919081019061462c565b9050600061106a85611b9c565b8251519091506000036110d9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f696e76616c696420677561726469616e2073657400000000000000000000000060448201526064016106b3565b8151516040517ff8ce560a00000000000000000000000000000000000000000000000000000000815260048101919091527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063f8ce560a90602401602060405180830381865afa158015611168573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061118c919061470a565b845110156111f6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f6e6f2071756f72756d000000000000000000000000000000000000000000000060448201526064016106b3565b6000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663a0cce1b38488876040518463ffffffff1660e01b815260040161125693929190614793565b600060405180830381865afa158015611273573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261129b9190810190614820565b91509150816112d857806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106b39190614321565b50505050505050565b6112e9612cb1565b60005b815181101561132e576000828281518110611309576113096145ce565b6020026020010151905061132581600001518260200151612d04565b506001016112ec565b5050565b808267ffffffffffffffff16101561132e576040517fb10b0aec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000825160001461138857600061138b565b60015b90506000825160001461139f5760006113a2565b60015b845190915060005b81811015611413578581815181106113c4576113c46145ce565b602002602001015173ffffffffffffffffffffffffffffffffffffffff16876000015173ffffffffffffffffffffffffffffffffffffffff160361140b5760019350611413565b6001016113aa565b508261144b576040517fa710429d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b835160005b818110156114de57602088015160009061146a9082612d65565b50905086828151811061147f5761147f6145ce565b60200260200101517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916036114d55760019450506114de565b50600101611450565b50826112d8576040517f8076dd8a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b825160005b8181101561154f57611547858281518110611538576115386145ce565b60200260200101518585611376565b60010161151b565b5050505050565b6040805160a081018252600080825260208201819052918101919091526060808201819052608082015261158a8383610f0e565b60018381015160ff1680835281146115ce576040517f1d9617a000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600284820181015161ffff1660208401819052910190600003611606576115f784826041612b2c565b6060840191909152905061161d565b61161284826020612b2c565b606084019190915290505b80840160048181015160059283015185519285019491939091019160ff90811690821614611677576040517f714f551300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50600486820181015163ffffffff90811660408701529101906000906116a19088908490612baf16565b9250905060ff81166000036116e2576040517fbb6b170d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006116f463ffffffff8516866148b2565b905080600061170c8a83600191810182015192910190565b9350905060ff8082169085161461174f576040517f84ae4a3000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8360ff1667ffffffffffffffff81111561176b5761176b6135cf565b6040519080825280602002602001820160405280156117bf57816020015b60408051608081018252600080825260208201526060918101829052818101919091528152602001906001900390816117895790505b50608089015260005b8460ff16811015611aa75760028b87018101519087018a6080015183815181106117f4576117f46145ce565b602090810291909101015161ffff9092169091529550600061181f8c86600291810182015192910190565b60808c015180519197509192508390811061183c5761183c6145ce565b60200260200101516000015161ffff168161ffff1614611888576040517fa179f8c900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60018c88018101519088018b6080015184815181106118a9576118a96145ce565b60209081029190910181015160ff909316920191909152965060006118d78d87600191810182015192910190565b60808d01518051919850919250849081106118f4576118f46145ce565b60200260200101516020015160ff168160ff161461193e576040517f0216496100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600160ff168b608001518481518110611959576119596145ce565b60200260200101516020015160ff16108061199c5750600660ff168b60800151848151811061198a5761198a6145ce565b60200260200101516020015160ff1610155b156119ff578a6080015183815181106119b7576119b76145ce565b6020026020010151602001516040517f51ee58530000000000000000000000000000000000000000000000000000000081526004016106b3919060ff91909116815260200190565b60048d89018101519089019099509750611a238d8963ffffffff808d1690612b2c16565b8c608001518581518110611a3957611a396145ce565b60209081029190910101516040019190915260048e880181015191995087019099509550611a718d8763ffffffff808d1690612b2c16565b8c608001518581518110611a8757611a876145ce565b6020026020010151606001819850829052505082600101925050506117c8565b50848214611aeb576040517fc37906a000000000000000000000000000000000000000000000000000000000815260048101839052602481018690526044016106b3565b611af58a84612c51565b5050505050505092915050565b611b0a612cb1565b611b146000612d90565b565b8051600090815b81811015611b5e57838181518110611b3757611b376145ce565b602002602001015161ffff168561ffff1603611b565760019250611b5e565b600101611b1d565b5081611b96576040517f7a47c9a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050565b6000604051806060016040528060238152602001614a616023913982516020840120604051602001611bcf9291906148c5565b604051602081830303815290604052805190602001209050919050565b6000611bf88383611556565b905060005b816080015151811015611b965760006004600084608001518481518110611c2657611c266145ce565b60209081029190910181015181015160ff1682528101919091526040016000205473ffffffffffffffffffffffffffffffffffffffff16905080611c96576040517fae67532100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008173ffffffffffffffffffffffffffffffffffffffff1663da841d3985608001518581518110611cca57611cca6145ce565b60209081029190910101516001546040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b168152611d28929173ffffffffffffffffffffffffffffffffffffffff16906004016148e7565b60c060405180830381865afa158015611d45573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d69919061491f565b6040808201516020808401516000908152600382528390208351606081018552815480825260018301549382019390935260029091015493810193909352815193945090921080611dc1575081602001518160200151115b80611dd3575081604001518160400151115b15611e0a576040517f4efc1f9100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805160608082018352845182526020808601518184019081528685015184860190815288830151600090815260039093529185902093518455516001840155516002909201919091558451825191820190925282518451611eb39392918291611e7591906149bd565b815260200184602001518660200151611e8e91906149bd565b815260200184604001518660400151611ea791906149bd565b90526060860151612e05565b505060019092019150611bfd9050565b611ecb612cb1565b61132e8183612f91565b604080516101408101825260608082526020820181905260009282018390528082018390526080820183905260a0820183905260c0820183905260e08201839052610100820192909252610120810191909152602082015160ff16600214611f7b5760208201516040517f96b8e05b00000000000000000000000000000000000000000000000000000000815260ff9091166004820152600260248201526044016106b3565b6000806000611f97838660400151612ba190919063ffffffff16565b67ffffffffffffffff91909116604086810191909152860151600481830181015192019450909150611fd3908463ffffffff80851690612b2c16565b9085526040860151600481830181015192019450909150611ffe908463ffffffff80851690612b2c16565b60208601919091526040860151600190820181015160608089018051600890880181015167ffffffffffffffff16928a01929092525192909301955091909301926120499084612bbd565b60c087019190915260608701805182016008015167ffffffffffffffff90811660808901528151830160109081015190911660a08901529051910193506120909084612bbd565b60e087019190915260608701805182016008015167ffffffffffffffff166101008801525181016009908101519101935060ff80821690831614612100576040517f5e7bd6ec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8160ff1667ffffffffffffffff81111561211c5761211c6135cf565b60405190808252806020026020018201604052801561218757816020015b6121746040518060600160405280600073ffffffffffffffffffffffffffffffffffffffff16815260200160608152602001606081525090565b81526020019060019003908161213a5790505b5061012087015260005b8260ff16811015610bdf5760408801516121ab9087612c98565b88610120015183815181106121c2576121c26145ce565b602090810291909101015173ffffffffffffffffffffffffffffffffffffffff929092169091526040890151600481830181015192019750909450612211908763ffffffff80881690612b2c16565b8861012001518381518110612228576122286145ce565b60200260200101516020018198508290525050612252858960600151612b1e90919063ffffffff16565b60608a0151909650909450612271908663ffffffff80881690612b2c16565b8861012001518381518110612288576122886145ce565b6020908102919091010151604001919091529450600101612191565b604051806060016040528060238152602001614a616023913981565b6122c8612cb1565b6122d181613120565b50565b60408051610100810182526060808252600060208084018290529383018190528183018190526080830181905260a0830181905260c083015260e08201529082015160ff166004146123665760208201516040517f96b8e05b00000000000000000000000000000000000000000000000000000000815260ff90911660048281019190915260248201526044016106b3565b6000806000612382838660400151612b1e90919063ffffffff16565b60408701519094509091506123a1908463ffffffff80851690612b2c16565b90855260408681018051830160089081015167ffffffffffffffff90811660208a0152825185016010908101518216948a0194909452825185016018015181166060808b019190915292518501601990810151938b018051890190930151821660808b01528251880185015190911660a08a0152905193019550930192906124299084612bbd565b60c0870191909152606087015160019082018101519101935060ff82811690821614612481576040517f5e7bd6ec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8160ff1667ffffffffffffffff81111561249d5761249d6135cf565b60405190808252806020026020018201604052801561251d57816020015b6040805160c081018252600080825260208083018290529282018190526060808301829052608083019190915260a082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019101816124bb5790505b5060e087015260005b8260ff16811015610bdf5760408801516125409087612bbd565b8860e001518381518110612556576125566145ce565b6020908102919091010151919091526060890151860160089081015191975086018860e00151838151811061258d5761258d6145ce565b60200260200101516020018197508267ffffffffffffffff1667ffffffffffffffff1681525050506125cc858960600151612ba190919063ffffffff16565b8860e0015183815181106125e2576125e26145ce565b60200260200101516040018197508267ffffffffffffffff1667ffffffffffffffff168152505050612621858960600151612be390919063ffffffff16565b8860e001518381518110612637576126376145ce565b60209081029190910101519115156060928301529089015190955061265c9086612bbd565b8860e001518381518110612672576126726145ce565b602002602001015160800181975082815250505061269d858960600151612b1e90919063ffffffff16565b60608a01519096509094506126bc908663ffffffff80881690612b2c16565b8860e0015183815181106126d2576126d26145ce565b602090810291909101015160a001919091529450600101612526565b61273e6040518060c001604052806060815260200160608152602001600067ffffffffffffffff168152602001600067ffffffffffffffff16815260200160008019168152602001606081525090565b602082015160ff166003146127915760208201516040517f96b8e05b00000000000000000000000000000000000000000000000000000000815260ff9091166004820152600360248201526044016106b3565b60008060006127ad838660400151612b1e90919063ffffffff16565b60408701519094509091506127cc908463ffffffff80851690612b2c16565b90855260408601516004818301810151920194509091506127f7908463ffffffff80851690612b2c16565b60208601919091526040868101516001908301810151606089018051600890880181015167ffffffffffffffff16948a0194909452519190930195509301926128409084612bbd565b60808701919091526060878101805183016008015167ffffffffffffffff16918801919091525181016009908101519101935060ff808216908316146128b2576040517f5e7bd6ec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8160ff1667ffffffffffffffff8111156128ce576128ce6135cf565b60405190808252806020026020018201604052801561293957816020015b6129266040518060600160405280600073ffffffffffffffffffffffffffffffffffffffff16815260200160608152602001606081525090565b8152602001906001900390816128ec5790505b5060a087015260005b8260ff16811015610bdf57604088015161295c9087612c98565b8860a001518381518110612972576129726145ce565b602090810291909101015173ffffffffffffffffffffffffffffffffffffffff9290921690915260408901516004818301810151920197509094506129c1908763ffffffff80881690612b2c16565b8860a0015183815181106129d7576129d76145ce565b60200260200101516020018198508290525050612a01858960600151612b1e90919063ffffffff16565b60608a0151909650909450612a20908663ffffffff80881690612b2c16565b8860a001518381518110612a3657612a366145ce565b6020908102919091010151604001919091529450600101612942565b612a5a612cb1565b61132e8282612d04565b612a6c612cb1565b73ffffffffffffffffffffffffffffffffffffffff8116612abc576040517f1e4fbdf7000000000000000000000000000000000000000000000000000000008152600060048201526024016106b3565b6122d181612d90565b815460009081612ad7858583856131bb565b90508015612b125784612aeb6001836149bd565b81548110612afb57612afb6145ce565b906000526020600020906002020160010154612b15565b60005b95945050505050565b600491810182015192910190565b6060600082600003612b4f57505060408051600081526020810190915282612b99565b5050604051828201601f831680612b64575060205b80830184810186838901015b81831015612b88578051835260209283019201612b70565b5050848452601f01601f1916604052505b935093915050565b600891810182015192910190565b600191810182015192910190565b600080600080612bd68686602091810182015192910190565b9097909650945050505050565b600080600080612bfc8686600191810182015192910190565b909250905060fe821615612c41576040517ff7a37b0700000000000000000000000000000000000000000000000000000000815260ff831660048201526024016106b3565b60ff909116925090509250929050565b8082511461132e5781516040517fc37906a00000000000000000000000000000000000000000000000000000000081526004810191909152602481018290526044016106b3565b600080600080612bd68686601491810182015192910190565b60005473ffffffffffffffffffffffffffffffffffffffff163314611b14576040517f118cdaa70000000000000000000000000000000000000000000000000000000081523360048201526024016106b3565b61ffff82166000818152600260205260409020907fcb4fd51bf3a0766e39ffe0f81893291c14a84be4b8da0d352df1fee57f19609f612d438342612ac5565b60408051918252602082018690520160405180910390a261154f814284613223565b600080600080612d7e8686600491810182015192910190565b60e09190911b97909650945050505050565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000612e14836000015161323d565b612e21846020015161323d565b612e2e856040015161323d565b604051602001612e7e93929190608093841b7fffffffffffffffffffffffffffffffff00000000000000000000000000000000908116825292841b83166010820152921b16602082015260300190565b60408051601f1981840301815290829052600180547f5f398a1400000000000000000000000000000000000000000000000000000000845291935073ffffffffffffffffffffffffffffffffffffffff90911691635f398a1491612ee99188919086906004016149d0565b6020604051808303816000875af1158015612f08573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f2c919061470a565b5082516020840151604080860151905161ffff8616937f6afc719c5986033c8ee04237de6ef98d6eacf19eb6daa60939de50d0618ce95f93612f83938a845260208401929092526040830152606082015260800190565b60405180910390a250505050565b60ff811660008181526004602090815260409182902054825173ffffffffffffffffffffffffffffffffffffffff9182168152908616918101919091527f605377a362d179f8f97f433900dc88f457846f29a6a43430b454a11f4995c385910160405180910390a273ffffffffffffffffffffffffffffffffffffffff821661304e5760ff16600090815260046020526040902080547fffffffffffffffffffffffff000000000000000000000000000000000000000016905550565b600061309073ffffffffffffffffffffffffffffffffffffffff84167fda841d3900000000000000000000000000000000000000000000000000000000613297565b9050806130c9576040517fd62f4a2700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5060ff16600090815260046020526040902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b6001546040805173ffffffffffffffffffffffffffffffffffffffff928316815291831660208301527f1deb63b37f154ad5b5f92db0edea9bccf74dc0c235e80a86242dfddb2e33a0ec910160405180910390a1600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60005b8183101561321b5760006131d284846132b3565b9050848682815481106131e7576131e76145ce565b906000526020600020906002020160000154111561320757809250613215565b6132128160016148b2565b93505b506131be565b509392505050565b6000806132318585856132ce565b91509150935093915050565b60006fffffffffffffffffffffffffffffffff821115613293576040517f6dfcc65000000000000000000000000000000000000000000000000000000000815260806004820152602481018390526044016106b3565b5090565b60006132a283613434565b801561061e575061061e8383613498565b60006132c26002848418614a4c565b61061e908484166148b2565b8254600090819080156133ef576000866132e96001846149bd565b815481106132f9576132f96145ce565b90600052602060002090600202016040518060400160405290816000820154815260200160018201548152505090508581600001511115613366576040517f2520601d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80518690036133a657848761337c6001856149bd565b8154811061338c5761338c6145ce565b9060005260206000209060020201600101819055506133df565b604080518082019091528681526020808201878152895460018181018c5560008c81529390932093516002909102909301928355519101555b602001519250839150612b999050565b50506040805180820190915283815260208082018481528654600181810189556000898152938420945160029092029094019081559051920191909155905081612b99565b6000613460827f01ffc9a700000000000000000000000000000000000000000000000000000000613498565b80156106215750613491827fffffffff00000000000000000000000000000000000000000000000000000000613498565b1592915050565b6040517fffffffff0000000000000000000000000000000000000000000000000000000082166024820152600090819060440160408051601f19818403018152919052602080820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f01ffc9a700000000000000000000000000000000000000000000000000000000178152825192935060009283928392909183918a617530fa92503d91506000519050828015613551575060208210155b801561355d5750600081115b979650505050505050565b6000806040838503121561357b57600080fd5b823567ffffffffffffffff8116811461359357600080fd5b946020939093013593505050565b61ffff811681146122d157600080fd5b600080604083850312156135c457600080fd5b8235613593816135a1565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516080810167ffffffffffffffff81118282101715613621576136216135cf565b60405290565b6040805190810167ffffffffffffffff81118282101715613621576136216135cf565b6040516060810167ffffffffffffffff81118282101715613621576136216135cf565b604051601f8201601f1916810167ffffffffffffffff81118282101715613696576136966135cf565b604052919050565b803560ff811681146136af57600080fd5b919050565b600067ffffffffffffffff8211156136ce576136ce6135cf565b50601f01601f191660200190565b600082601f8301126136ed57600080fd5b81356137006136fb826136b4565b61366d565b81815284602083860101111561371557600080fd5b816020850160208301376000918101602001919091529392505050565b60006020828403121561374457600080fd5b813567ffffffffffffffff8082111561375c57600080fd5b908301906080828603121561377057600080fd5b6137786135fe565b8235613783816135a1565b81526137916020840161369e565b60208201526040830135828111156137a857600080fd5b6137b4878286016136dc565b6040830152506060830135828111156137cc57600080fd5b6137d8878286016136dc565b60608301525095945050505050565b60005b838110156138025781810151838201526020016137ea565b50506000910152565b600081518084526138238160208601602086016137e7565b601f01601f19169290920160200192915050565b60008282518085526020808601955060208260051b8401016020860160005b8481101561388457601f1986840301895261387283835161380b565b98840198925090830190600101613856565b5090979650505050505050565b600082825180855260208086019550808260051b84010181860160005b8481101561388457601f198684030189528151610120815185528582015181878701526138dd82870182613837565b91505060408083015181870152506060808301516139068288018267ffffffffffffffff169052565b505060808281015167ffffffffffffffff169086015260a08083015115159086015260c0808301519086015260e08083015186830382880152613949838261380b565b925050506101008083015192506139648187018460ff169052565b5099850199935050908301906001016138ae565b602081526000825161010080602085015261399761012085018361380b565b915067ffffffffffffffff602086015116604085015260408501516139c8606086018267ffffffffffffffff169052565b50606085015167ffffffffffffffff8116608086015250608085015167ffffffffffffffff811660a08601525060a085015167ffffffffffffffff811660c08601525060c085015160e085015260e0850151601f198584030182860152613a2f8382613891565b9695505050505050565b600082825180855260208086019550808260051b84010181860160005b8481101561388457601f198684030189528151606073ffffffffffffffffffffffffffffffffffffffff8251168552858201518187870152613a9a8287018261380b565b91505060408083015192508582038187015250613ab7818361380b565b9a86019a9450505090830190600101613a56565b602081526000825160a06020840152613ae760c084018261380b565b9050602084015167ffffffffffffffff80821660408601528060408701511660608601525050606084015160808401526080840151601f198483030160a0850152612b158282613a39565b600060208284031215613b4457600080fd5b61061e8261369e565b600067ffffffffffffffff821115613b6757613b676135cf565b5060051b60200190565b6000806040808486031215613b8557600080fd5b833567ffffffffffffffff80821115613b9d57600080fd5b613ba9878388016136dc565b9450602091508186013581811115613bc057600080fd5b86019050601f81018713613bd357600080fd5b8035613be16136fb82613b4d565b81815260079190911b82018301908381019089831115613c0057600080fd5b928401925b82841015613c64576080848b031215613c1e5760008081fd5b613c266135fe565b843581528585013586820152613c3d87860161369e565b878201526060613c4e81870161369e565b9082015282526080939093019290840190613c05565b8096505050505050509250929050565b60006020808385031215613c8757600080fd5b823567ffffffffffffffff811115613c9e57600080fd5b8301601f81018513613caf57600080fd5b8035613cbd6136fb82613b4d565b81815260069190911b82018301908381019087831115613cdc57600080fd5b928401925b8284101561355d5760408489031215613cfa5760008081fd5b613d02613627565b8435613d0d816135a1565b81528486013586820152825260409093019290840190613ce1565b73ffffffffffffffffffffffffffffffffffffffff811681146122d157600080fd5b600060608284031215613d5c57600080fd5b613d6461364a565b90508135613d7181613d28565b8152602082013567ffffffffffffffff80821115613d8e57600080fd5b613d9a858386016136dc565b60208401526040840135915080821115613db357600080fd5b50613dc0848285016136dc565b60408301525092915050565b600082601f830112613ddd57600080fd5b81356020613ded6136fb83613b4d565b8083825260208201915060208460051b870101935086841115613e0f57600080fd5b602086015b84811015613e34578035613e2781613d28565b8352918301918301613e14565b509695505050505050565b600082601f830112613e5057600080fd5b81356020613e606136fb83613b4d565b8083825260208201915060208460051b870101935086841115613e8257600080fd5b602086015b84811015613e345780357fffffffff0000000000000000000000000000000000000000000000000000000081168114613ec05760008081fd5b8352918301918301613e87565b600080600060608486031215613ee257600080fd5b833567ffffffffffffffff80821115613efa57600080fd5b613f0687838801613d4a565b94506020860135915080821115613f1c57600080fd5b613f2887838801613dcc565b93506040860135915080821115613f3e57600080fd5b50613f4b86828701613e3f565b9150509250925092565b600080600060608486031215613f6a57600080fd5b833567ffffffffffffffff80821115613f8257600080fd5b818601915086601f830112613f9657600080fd5b81356020613fa66136fb83613b4d565b82815260059290921b8401810191818101908a841115613fc557600080fd5b8286015b84811015613ffd57803586811115613fe15760008081fd5b613fef8d86838b0101613d4a565b845250918301918301613fc9565b5097505087013592505080821115613f1c57600080fd5b61ffff815116825260ff60208201511660208301526000604082015160806040850152614044608085018261380b565b905060608301518482036060860152612b15828261380b565b6000602080835260ff8451168184015261ffff8185015116604084015263ffffffff6040850151166060840152606084015160a060808501526140a360c085018261380b565b90506080850151601f19808684030160a08701528282518085528585019150858160051b860101868501945060005b828110156140fe57848783030184526140ec828751614014565b958801959388019391506001016140d2565b509998505050505050505050565b60006020828403121561411e57600080fd5b813567ffffffffffffffff81111561413557600080fd5b614141848285016136dc565b949350505050565b6000806040838503121561415c57600080fd5b8235614167816135a1565b915060208381013567ffffffffffffffff81111561418457600080fd5b8401601f8101861361419557600080fd5b80356141a36136fb82613b4d565b81815260059190911b820183019083810190888311156141c257600080fd5b928401925b828410156141e95783356141da816135a1565b825292840192908401906141c7565b80955050505050509250929050565b6000806040838503121561420b57600080fd5b6142148361369e565b9150602083013561422481613d28565b809150509250929050565b602081526000825161014080602085015261424e61016085018361380b565b91506020850151601f198086850301604087015261426c848361380b565b93506040870151915061428b606087018367ffffffffffffffff169052565b606087015167ffffffffffffffff811660808801529150608087015167ffffffffffffffff811660a0880152915060a087015167ffffffffffffffff811660c0880152915060c087015160e087015260e087015191506101008281880152808801519250506101206143088188018467ffffffffffffffff169052565b870151868503909101838701529050613a2f8382613a39565b60208152600061061e602083018461380b565b60006020828403121561434657600080fd5b813561435181613d28565b9392505050565b600082825180855260208086019550808260051b84010181860160005b8481101561388457858303601f190189528151805184528481015167ffffffffffffffff90811686860152604080830151909116908501526060808201511515908501526080808201519085015260a09081015160c0918501829052906143de8186018361380b565b9a86019a9450505090830190600101614375565b602081526000825161010080602085015261441161012085018361380b565b915067ffffffffffffffff60208601511660408501526040850151614442606086018267ffffffffffffffff169052565b50606085015167ffffffffffffffff8116608086015250608085015167ffffffffffffffff811660a08601525060a085015167ffffffffffffffff811660c08601525060c085015160e085015260e0850151601f198584030182860152613a2f8382614358565b602081526000825160c060208401526144c560e084018261380b565b90506020840151601f19808584030160408601526144e3838361380b565b92506040860151915067ffffffffffffffff808316606087015280606088015116608087015250608086015160a086015260a08601519150808584030160c086015250612b158282613a39565b60006020828403121561454257600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600067ffffffffffffffff808416806145c2576145c2614549565b92169190910492915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b805163ffffffff811681146136af57600080fd5b60006020828403121561462357600080fd5b61061e826145fd565b6000602080838503121561463f57600080fd5b825167ffffffffffffffff8082111561465757600080fd5b908401906040828703121561466b57600080fd5b614673613627565b82518281111561468257600080fd5b83019150601f8201871361469557600080fd5b81516146a36136fb82613b4d565b81815260059190911b830185019085810190898311156146c257600080fd5b938601935b828510156146e95784516146da81613d28565b825293860193908601906146c7565b8352506146f990508385016145fd565b848201528094505050505092915050565b60006020828403121561471c57600080fd5b5051919050565b805160408084528151908401819052600091602091908201906060860190845b8181101561477557835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101614743565b505063ffffffff602086015116602087015280935050505092915050565b60006060808301868452602060606020860152818751808452608093506080870191506020890160005b828110156147fe57815180518552858101518686015260408082015160ff9081169187019190915290880151168785015292850192908401906001016147bd565b50505085810360408701526148138188614723565b9998505050505050505050565b6000806040838503121561483357600080fd5b8251801515811461484357600080fd5b602084015190925067ffffffffffffffff81111561486057600080fd5b8301601f8101851361487157600080fd5b805161487f6136fb826136b4565b81815286602083850101111561489457600080fd5b6148a58260208301602086016137e7565b8093505050509250929050565b8082018082111561062157610621614578565b600083516148d78184602088016137e7565b9190910191825250602001919050565b6040815260006148fa6040830185614014565b905073ffffffffffffffffffffffffffffffffffffffff831660208301529392505050565b600081830360c081121561493257600080fd5b61493a6135fe565b835181526020840151602082015260607fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08301121561497857600080fd5b61498061364a565b60408581015182526060860151602083015260808601518183015282015260a084015191506149ae826135a1565b60608101919091529392505050565b8181038181111561062157610621614578565b83815260ff8316602082015260806040820152603260808201527f726f6c6c65642d757020766f74652066726f6d20676f7665726e616e6365207360a08201527f706f6b6520746f6b656e20686f6c64657273000000000000000000000000000060c082015260e060608201526000612b1560e083018461380b565b600082614a5b57614a5b614549565b50049056fe71756572795f726573706f6e73655f303030303030303030303030303030303030307ca26469706673582212208e5001e941a0f8c21e6e1708fec3ac47c4848adc52895d118c94d23f830ab64c64736f6c6343000817003360c06040523480156200001157600080fd5b50604051620041d5380380620041d5833981016040819052620000349162000093565b816001600160a01b0381166200005d57604051638ef9698f60e01b815260040160405180910390fd5b6001600160a01b039081166080521660a05250620000cb565b80516001600160a01b03811681146200008e57600080fd5b919050565b60008060408385031215620000a757600080fd5b620000b28362000076565b9150620000c26020840162000076565b90509250929050565b60805160a0516140c162000114600039600081816101f5015261252101526000818161034901528181610e4901528181610f2501528181611043015261113201526140c16000f3fe608060405234801561001057600080fd5b50600436106101ae5760003560e01c806378cc4030116100ee578063c008e15611610097578063dc37e93e11610071578063dc37e93e1461043b578063e0b54d301461045b578063e6a3c0e814610463578063ffa1ad74146102cf57600080fd5b8063c008e156146103ae578063c895dec6146103c3578063da841d39146103e357600080fd5b8063a0f419fa116100c8578063a0f419fa14610373578063a8024ef11461037b578063bda269f21461038e57600080fd5b806378cc40301461033157806384acd1bb146103445780638a8f28681461036b57600080fd5b80633896fc121161015b5780634d63d473116101355780634d63d473146102cf5780634f098c0a146102d7578063571354e2146102ea57806371b632c81461030a57600080fd5b80633896fc121461029657806345ee36c5146102a957806347bdbbcf146102bc57600080fd5b80632b2077ad1161018c5780632b2077ad1461023c5780632b7e1cd81461025c5780632df2f9781461027657600080fd5b806301ffc9a7146101b357806316476dcc146101db57806318d13fd1146101f0575b600080fd5b6101c66101c1366004612d78565b61046b565b60405190151581526020015b60405180910390f35b6101ee6101e9366004612d9a565b610504565b005b6102177f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101d2565b61024f61024a366004612fb1565b61055e565b6040516101d2919061317f565b610264600281565b60405160ff90911681526020016101d2565b610289610284366004612fb1565b610b3d565b6040516101d291906132d2565b6101ee6102a4366004613366565b610e45565b6101ee6102b7366004612d9a565b611218565b6101ee6102ca366004613606565b611260565b610264600181565b6101ee6102e536600461368e565b611400565b6102fd6102f8366004613366565b611440565b6040516101d2919061374d565b610323610318366004613845565b805160209091012090565b6040519081526020016101d2565b6101ee61033f36600461387a565b6119ec565b6102177f000000000000000000000000000000000000000000000000000000000000000081565b610264600681565b610264600381565b610323610389366004613845565b611a72565b6103a161039c366004612fb1565b611ac2565b6040516101d29190613925565b6103b6611e91565b6040516101d29190613a17565b6103d66103d1366004612fb1565b611ead565b6040516101d29190613ac4565b6103f66103f1366004613b7b565b6122c7565b6040805182518152602080840151818301528383015180518385015290810151606080840191909152920151608082015291015161ffff1660a082015260c0016101d2565b61044e610449366004612fb1565b6126b8565b6040516101d29190613bcd565b610264600481565b610264600581565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167fda841d390000000000000000000000000000000000000000000000000000000014806104fe57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b6000610513620f424084613c54565b67ffffffffffffffff16905081811015610559576040517f3a04ceca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050565b60408051610100810182526060808252600060208084018290529383018190528183018190526080830181905260a0830181905260c083015260e08201529082015160ff166005146105f35760208201516040517f96b8e05b00000000000000000000000000000000000000000000000000000000815260ff9091166004820152600560248201526044015b60405180910390fd5b600080600061060f838660400151612a1c90919063ffffffff16565b604087015190945090915061062e908463ffffffff80851690612a2a16565b90855260408681018051830160089081015167ffffffffffffffff90811660208a0152825185016010908101518216948a0194909452825185016018015181166060808b019190915292518501601990810151938b018051890190930151821660808b01528251880185015190911660a08a0152905193019550930192906106b69084612abb565b60c0870191909152606087015160019082018101519101935060ff8281169082161461070e576040517f5e7bd6ec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8160ff1667ffffffffffffffff81111561072a5761072a612dd3565b6040519080825280602002602001820160405280156107be57816020015b60408051610120810182526000808252606060208084018290529383018290528083018290526080830182905260a0830182905260c0830182905260e083015261010082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019101816107485790505b5060e087015260005b8260ff16811015610b165760408801516107e19087612abb565b8860e0015183815181106107f7576107f7613ca2565b602090810291909101015191909152604089015160019082018101519101965060ff811667ffffffffffffffff81111561083357610833612dd3565b60405190808252806020026020018201604052801561086657816020015b60608152602001906001900390816108515790505b508860e00151838151811061087d5761087d613ca2565b60200260200101516020018190525060005b8160ff1681101561090b5760408a01516004898201810151990198906108bf908a63ffffffff80851690612a2a16565b8b60e0015186815181106108d5576108d5613ca2565b60200260200101516020015184815181106108f2576108f2613ca2565b602090810291909101019190915298505060010161088f565b50606089015161091b9087612abb565b8960e00151848151811061093157610931613ca2565b602002602001015160400181985082815250505061095c868a60600151612aad90919063ffffffff16565b8960e00151848151811061097257610972613ca2565b6020026020010151610100018198508260ff1660ff1681525050506109a4868a60600151612a9f90919063ffffffff16565b8960e0015184815181106109ba576109ba613ca2565b602090810291909101015167ffffffffffffffff92909216606092830152908a0151810160089081015191975087018960e0015184815181106109ff576109ff613ca2565b60200260200101516080018198508267ffffffffffffffff1667ffffffffffffffff168152505050610a3e868a60600151612ae190919063ffffffff16565b8960e001518481518110610a5457610a54613ca2565b602002602001015160a00181985082151515158152505050610a83868a60600151612abb90919063ffffffff16565b8960e001518481518110610a9957610a99613ca2565b602002602001015160c001819850828152505050610ac4868a60600151612a1c90919063ffffffff16565b60608b0151909750909550610ae3908763ffffffff80891690612a2a16565b8960e001518481518110610af957610af9613ca2565b602090810291909101015160e001919091529550506001016107c7565b50610b25876040015186612b4f565b610b33876060015185612b4f565b5050505050919050565b6040805160a0810182526060808252600060208084018290529383018190528183015260808201529082015160ff16600114610bb75760208201516040517f96b8e05b00000000000000000000000000000000000000000000000000000000815260ff9091166004820152600160248201526044016105ea565b6000806000610bd3838660400151612a1c90919063ffffffff16565b6040870151909450909150610bf2908463ffffffff80851690612a2a16565b90855260408601516001908201810151606088018051600890870181015167ffffffffffffffff1660208a015290519290930195509190930192610c369084612abb565b606087810192909252908701805182016008015167ffffffffffffffff1660408801525181016009908101519101935060ff80821690831614610ca5576040517f5e7bd6ec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8160ff1667ffffffffffffffff811115610cc157610cc1612dd3565b604051908082528060200260200182016040528015610d2c57816020015b610d196040518060600160405280600073ffffffffffffffffffffffffffffffffffffffff16815260200160608152602001606081525090565b815260200190600190039081610cdf5790505b50608087015260005b8260ff16811015610b16576040880151610d4f9087612b96565b88608001518381518110610d6557610d65613ca2565b602090810291909101015173ffffffffffffffffffffffffffffffffffffffff929092169091526040890151600481830181015192019750909450610db4908763ffffffff80881690612a2a16565b88608001518381518110610dca57610dca613ca2565b60200260200101516020018198508290525050610df4858960600151612a1c90919063ffffffff16565b60608a0151909650909450610e13908663ffffffff80881690612a2a16565b88608001518381518110610e2957610e29613ca2565b6020908102919091010151604001919091529450600101610d35565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16631cfe79516040518163ffffffff1660e01b8152600401602060405180830381865afa158015610eb2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ed69190613ce5565b6040517ff951975a00000000000000000000000000000000000000000000000000000000815263ffffffff8216600482015290915060009073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063f951975a90602401600060405180830381865afa158015610f6c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610f949190810190613d00565b90506000610fa185611a72565b825151909150600003611010576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f696e76616c696420677561726469616e2073657400000000000000000000000060448201526064016105ea565b8151516040517ff8ce560a00000000000000000000000000000000000000000000000000000000815260048101919091527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063f8ce560a90602401602060405180830381865afa15801561109f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110c39190613dde565b8451101561112d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f6e6f2071756f72756d000000000000000000000000000000000000000000000060448201526064016105ea565b6000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663a0cce1b38488876040518463ffffffff1660e01b815260040161118d93929190613e67565b600060405180830381865afa1580156111aa573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526111d29190810190613ef4565b915091508161120f57806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016105ea9190613a17565b50505050505050565b808267ffffffffffffffff16101561125c576040517fb10b0aec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050565b60008251600014611272576000611275565b60015b90506000825160001461128957600061128c565b60015b845190915060005b818110156112fd578581815181106112ae576112ae613ca2565b602002602001015173ffffffffffffffffffffffffffffffffffffffff16876000015173ffffffffffffffffffffffffffffffffffffffff16036112f557600193506112fd565b600101611294565b5082611335576040517fa710429d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b835160005b818110156113c85760208801516000906113549082612baf565b50905086828151811061136957611369613ca2565b60200260200101517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916036113bf5760019450506113c8565b5060010161133a565b508261120f576040517f8076dd8a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b825160005b818110156114395761143185828151811061142257611422613ca2565b60200260200101518585611260565b600101611405565b5050505050565b6040805160a08101825260008082526020820181905291810191909152606080820181905260808201526114748383610e45565b60018381015160ff1680835281146114b8576040517f1d9617a000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600284820181015161ffff16602084018190529101906000036114f0576114e184826041612a2a565b60608401919091529050611507565b6114fc84826020612a2a565b606084019190915290505b80840160048181015160059283015185519285019491939091019160ff90811690821614611561576040517f714f551300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50600486820181015163ffffffff908116604087015291019060009061158b9088908490612aad16565b9250905060ff81166000036115cc576040517fbb6b170d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006115de63ffffffff851686613f86565b90508060006115f68a83600191810182015192910190565b9350905060ff80821690851614611639576040517f84ae4a3000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8360ff1667ffffffffffffffff81111561165557611655612dd3565b6040519080825280602002602001820160405280156116a957816020015b60408051608081018252600080825260208201526060918101829052818101919091528152602001906001900390816116735790505b50608089015260005b8460ff168110156119915760028b87018101519087018a6080015183815181106116de576116de613ca2565b602090810291909101015161ffff909216909152955060006117098c86600291810182015192910190565b60808c015180519197509192508390811061172657611726613ca2565b60200260200101516000015161ffff168161ffff1614611772576040517fa179f8c900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60018c88018101519088018b60800151848151811061179357611793613ca2565b60209081029190910181015160ff909316920191909152965060006117c18d87600191810182015192910190565b60808d01518051919850919250849081106117de576117de613ca2565b60200260200101516020015160ff168160ff1614611828576040517f0216496100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600160ff168b60800151848151811061184357611843613ca2565b60200260200101516020015160ff1610806118865750600660ff168b60800151848151811061187457611874613ca2565b60200260200101516020015160ff1610155b156118e9578a6080015183815181106118a1576118a1613ca2565b6020026020010151602001516040517f51ee58530000000000000000000000000000000000000000000000000000000081526004016105ea919060ff91909116815260200190565b60048d8901810151908901909950975061190d8d8963ffffffff808d1690612a2a16565b8c60800151858151811061192357611923613ca2565b60209081029190910101516040019190915260048e88018101519199508701909950955061195b8d8763ffffffff808d1690612a2a16565b8c60800151858151811061197157611971613ca2565b6020026020010151606001819850829052505082600101925050506116b2565b508482146119d5576040517fc37906a000000000000000000000000000000000000000000000000000000000815260048101839052602481018690526044016105ea565b6119df8a84612b4f565b5050505050505092915050565b8051600090815b81811015611a3457838181518110611a0d57611a0d613ca2565b602002602001015161ffff168561ffff1603611a2c5760019250611a34565b6001016119f3565b5081611a6c576040517f7a47c9a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050565b60006040518060600160405280602381526020016140696023913982516020840120604051602001611aa5929190613fc0565b604051602081830303815290604052805190602001209050919050565b604080516101408101825260608082526020820181905260009282018390528082018390526080820183905260a0820183905260c0820183905260e08201839052610100820192909252610120810191909152602082015160ff16600214611b685760208201516040517f96b8e05b00000000000000000000000000000000000000000000000000000000815260ff9091166004820152600260248201526044016105ea565b6000806000611b84838660400151612a9f90919063ffffffff16565b67ffffffffffffffff91909116604086810191909152860151600481830181015192019450909150611bc0908463ffffffff80851690612a2a16565b9085526040860151600481830181015192019450909150611beb908463ffffffff80851690612a2a16565b60208601919091526040860151600190820181015160608089018051600890880181015167ffffffffffffffff16928a0192909252519290930195509190930192611c369084612abb565b60c087019190915260608701805182016008015167ffffffffffffffff90811660808901528151830160109081015190911660a0890152905191019350611c7d9084612abb565b60e087019190915260608701805182016008015167ffffffffffffffff166101008801525181016009908101519101935060ff80821690831614611ced576040517f5e7bd6ec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8160ff1667ffffffffffffffff811115611d0957611d09612dd3565b604051908082528060200260200182016040528015611d7457816020015b611d616040518060600160405280600073ffffffffffffffffffffffffffffffffffffffff16815260200160608152602001606081525090565b815260200190600190039081611d275790505b5061012087015260005b8260ff16811015610b16576040880151611d989087612b96565b8861012001518381518110611daf57611daf613ca2565b602090810291909101015173ffffffffffffffffffffffffffffffffffffffff929092169091526040890151600481830181015192019750909450611dfe908763ffffffff80881690612a2a16565b8861012001518381518110611e1557611e15613ca2565b60200260200101516020018198508290525050611e3f858960600151612a1c90919063ffffffff16565b60608a0151909650909450611e5e908663ffffffff80881690612a2a16565b8861012001518381518110611e7557611e75613ca2565b6020908102919091010151604001919091529450600101611d7e565b6040518060600160405280602381526020016140696023913981565b60408051610100810182526060808252600060208084018290529383018190528183018190526080830181905260a0830181905260c083015260e08201529082015160ff16600414611f3f5760208201516040517f96b8e05b00000000000000000000000000000000000000000000000000000000815260ff90911660048281019190915260248201526044016105ea565b6000806000611f5b838660400151612a1c90919063ffffffff16565b6040870151909450909150611f7a908463ffffffff80851690612a2a16565b90855260408681018051830160089081015167ffffffffffffffff90811660208a0152825185016010908101518216948a0194909452825185016018015181166060808b019190915292518501601990810151938b018051890190930151821660808b01528251880185015190911660a08a0152905193019550930192906120029084612abb565b60c0870191909152606087015160019082018101519101935060ff8281169082161461205a576040517f5e7bd6ec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8160ff1667ffffffffffffffff81111561207657612076612dd3565b6040519080825280602002602001820160405280156120f657816020015b6040805160c081018252600080825260208083018290529282018190526060808301829052608083019190915260a082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019101816120945790505b5060e087015260005b8260ff16811015610b165760408801516121199087612abb565b8860e00151838151811061212f5761212f613ca2565b6020908102919091010151919091526060890151860160089081015191975086018860e00151838151811061216657612166613ca2565b60200260200101516020018197508267ffffffffffffffff1667ffffffffffffffff1681525050506121a5858960600151612a9f90919063ffffffff16565b8860e0015183815181106121bb576121bb613ca2565b60200260200101516040018197508267ffffffffffffffff1667ffffffffffffffff1681525050506121fa858960600151612ae190919063ffffffff16565b8860e00151838151811061221057612210613ca2565b6020908102919091010151911515606092830152908901519095506122359086612abb565b8860e00151838151811061224b5761224b613ca2565b6020026020010151608001819750828152505050612276858960600151612a1c90919063ffffffff16565b60608a0151909650909450612295908663ffffffff80881690612a2a16565b8860e0015183815181106122ab576122ab613ca2565b602090810291909101015160a0019190915294506001016120ff565b6122cf612cf6565b60006122da846126b8565b90508060a0015151600114612324578060a00151516040517f79c5a4f00000000000000000000000000000000000000000000000000000000081526004016105ea91815260200190565b61234b8160a0015160008151811061233e5761233e613ca2565b6020026020010151612bda565b602081015161235b906009612c6a565b60208101517f66696e616c697a656400000000000000000000000000000000000000000000009061238b90613fe2565b7fffffffffffffffffff000000000000000000000000000000000000000000000016146123e75780516040517f0d18869e0000000000000000000000000000000000000000000000000000000081526105ea9190600401613a17565b61241d60808260a0015160008151811061240357612403613ca2565b602002602001015160400151612c6a90919063ffffffff16565b6000806000808460a0015160008151811061243a5761243a613ca2565b6020026020010151604001518060200190518101906124599190614032565b935093509350935060008773ffffffffffffffffffffffffffffffffffffffff16632d63f693866040518263ffffffff1660e01b815260040161249e91815260200190565b602060405180830381865afa1580156124bb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124df9190613dde565b89516040517f2ac96ea100000000000000000000000000000000000000000000000000000000815261ffff9091166004820152602481018290529091506000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690632ac96ea190604401602060405180830381865afa15801561257d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125a19190613dde565b905080158061260657506125b481612cb1565b73ffffffffffffffffffffffffffffffffffffffff168760a001516000815181106125e1576125e1613ca2565b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff1614155b1561263d576040517fa710429d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b89516040805161ffff9092166020830152810187905260009060600160408051601f19818403018152828252805160209182012060808401835299835282810199909952805160608082018352988152988901969096528786019490945250505090810192909252855161ffff169082015291505092915050565b6127086040518060c001604052806060815260200160608152602001600067ffffffffffffffff168152602001600067ffffffffffffffff16815260200160008019168152602001606081525090565b602082015160ff1660031461275b5760208201516040517f96b8e05b00000000000000000000000000000000000000000000000000000000815260ff9091166004820152600360248201526044016105ea565b6000806000612777838660400151612a1c90919063ffffffff16565b6040870151909450909150612796908463ffffffff80851690612a2a16565b90855260408601516004818301810151920194509091506127c1908463ffffffff80851690612a2a16565b60208601919091526040868101516001908301810151606089018051600890880181015167ffffffffffffffff16948a01949094525191909301955093019261280a9084612abb565b60808701919091526060878101805183016008015167ffffffffffffffff16918801919091525181016009908101519101935060ff8082169083161461287c576040517f5e7bd6ec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8160ff1667ffffffffffffffff81111561289857612898612dd3565b60405190808252806020026020018201604052801561290357816020015b6128f06040518060600160405280600073ffffffffffffffffffffffffffffffffffffffff16815260200160608152602001606081525090565b8152602001906001900390816128b65790505b5060a087015260005b8260ff16811015610b165760408801516129269087612b96565b8860a00151838151811061293c5761293c613ca2565b602090810291909101015173ffffffffffffffffffffffffffffffffffffffff92909216909152604089015160048183018101519201975090945061298b908763ffffffff80881690612a2a16565b8860a0015183815181106129a1576129a1613ca2565b602002602001015160200181985082905250506129cb858960600151612a1c90919063ffffffff16565b60608a01519096509094506129ea908663ffffffff80881690612a2a16565b8860a001518381518110612a0057612a00613ca2565b602090810291909101015160400191909152945060010161290c565b600491810182015192910190565b6060600082600003612a4d57505060408051600081526020810190915282612a97565b5050604051828201601f831680612a62575060205b80830184810186838901015b81831015612a86578051835260209283019201612a6e565b5050848452601f01601f1916604052505b935093915050565b600891810182015192910190565b600191810182015192910190565b600080600080612ad48686602091810182015192910190565b9097909650945050505050565b600080600080612afa8686600191810182015192910190565b909250905060fe821615612b3f576040517ff7a37b0700000000000000000000000000000000000000000000000000000000815260ff831660048201526024016105ea565b60ff909116925090509250929050565b8082511461125c5781516040517fc37906a00000000000000000000000000000000000000000000000000000000081526004810191909152602481018290526044016105ea565b600080600080612ad48686601491810182015192910190565b600080600080612bc88686600491810182015192910190565b60e09190911b97909650945050505050565b6020810151600090612bec9082612baf565b5090507fffffffff0000000000000000000000000000000000000000000000000000000081167f544ffc9c000000000000000000000000000000000000000000000000000000001461125c576040517f8076dd8a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8082511461125c5781516040517fab8b67c60000000000000000000000000000000000000000000000000000000081526004810191909152602481018290526044016105ea565b600060a082901c15612cf2576040517f33b960d0000000000000000000000000000000000000000000000000000000008152600481018390526024016105ea565b5090565b60405180608001604052806000815260200160008019168152602001612d3660405180606001604052806000815260200160008152602001600081525090565b8152600060209091015290565b80357fffffffff0000000000000000000000000000000000000000000000000000000081168114612d7357600080fd5b919050565b600060208284031215612d8a57600080fd5b612d9382612d43565b9392505050565b60008060408385031215612dad57600080fd5b823567ffffffffffffffff81168114612dc557600080fd5b946020939093013593505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516080810167ffffffffffffffff81118282101715612e2557612e25612dd3565b60405290565b6040805190810167ffffffffffffffff81118282101715612e2557612e25612dd3565b604051601f8201601f1916810167ffffffffffffffff81118282101715612e7757612e77612dd3565b604052919050565b803561ffff81168114612d7357600080fd5b803560ff81168114612d7357600080fd5b600067ffffffffffffffff821115612ebc57612ebc612dd3565b50601f01601f191660200190565b600082601f830112612edb57600080fd5b8135612eee612ee982612ea2565b612e4e565b818152846020838601011115612f0357600080fd5b816020850160208301376000918101602001919091529392505050565b600060808284031215612f3257600080fd5b612f3a612e02565b9050612f4582612e7f565b8152612f5360208301612e91565b6020820152604082013567ffffffffffffffff80821115612f7357600080fd5b612f7f85838601612eca565b60408401526060840135915080821115612f9857600080fd5b50612fa584828501612eca565b60608301525092915050565b600060208284031215612fc357600080fd5b813567ffffffffffffffff811115612fda57600080fd5b612fe684828501612f20565b949350505050565b60005b83811015613009578181015183820152602001612ff1565b50506000910152565b6000815180845261302a816020860160208601612fee565b601f01601f19169290920160200192915050565b60008282518085526020808601955060208260051b8401016020860160005b8481101561308b57601f19868403018952613079838351613012565b9884019892509083019060010161305d565b5090979650505050505050565b600082825180855260208086019550808260051b84010181860160005b8481101561308b57601f198684030189528151610120815185528582015181878701526130e48287018261303e565b915050604080830151818701525060608083015161310d8288018267ffffffffffffffff169052565b505060808281015167ffffffffffffffff169086015260a08083015115159086015260c0808301519086015260e080830151868303828801526131508382613012565b9250505061010080830151925061316b8187018460ff169052565b5099850199935050908301906001016130b5565b602081526000825161010080602085015261319e610120850183613012565b915067ffffffffffffffff602086015116604085015260408501516131cf606086018267ffffffffffffffff169052565b50606085015167ffffffffffffffff8116608086015250608085015167ffffffffffffffff811660a08601525060a085015167ffffffffffffffff811660c08601525060c085015160e085015260e0850151601f1985840301828601526132368382613098565b9695505050505050565b600082825180855260208086019550808260051b84010181860160005b8481101561308b57601f198684030189528151606073ffffffffffffffffffffffffffffffffffffffff82511685528582015181878701526132a182870182613012565b915050604080830151925085820381870152506132be8183613012565b9a86019a945050509083019060010161325d565b602081526000825160a060208401526132ee60c0840182613012565b9050602084015167ffffffffffffffff80821660408601528060408701511660608601525050606084015160808401526080840151601f198483030160a08501526133398282613240565b95945050505050565b600067ffffffffffffffff82111561335c5761335c612dd3565b5060051b60200190565b600080604080848603121561337a57600080fd5b833567ffffffffffffffff8082111561339257600080fd5b61339e87838801612eca565b94506020915081860135818111156133b557600080fd5b86019050601f810187136133c857600080fd5b80356133d6612ee982613342565b81815260079190911b820183019083810190898311156133f557600080fd5b928401925b82841015613459576080848b0312156134135760008081fd5b61341b612e02565b843581528585013586820152613432878601612e91565b878201526060613443818701612e91565b90820152825260809390930192908401906133fa565b8096505050505050509250929050565b73ffffffffffffffffffffffffffffffffffffffff8116811461348b57600080fd5b50565b6000606082840312156134a057600080fd5b6040516060810167ffffffffffffffff82821081831117156134c4576134c4612dd3565b81604052829350843591506134d882613469565b908252602084013590808211156134ee57600080fd5b6134fa86838701612eca565b6020840152604085013591508082111561351357600080fd5b5061352085828601612eca565b6040830152505092915050565b600082601f83011261353e57600080fd5b8135602061354e612ee983613342565b8083825260208201915060208460051b87010193508684111561357057600080fd5b602086015b8481101561359557803561358881613469565b8352918301918301613575565b509695505050505050565b600082601f8301126135b157600080fd5b813560206135c1612ee983613342565b8083825260208201915060208460051b8701019350868411156135e357600080fd5b602086015b84811015613595576135f981612d43565b83529183019183016135e8565b60008060006060848603121561361b57600080fd5b833567ffffffffffffffff8082111561363357600080fd5b61363f8783880161348e565b9450602086013591508082111561365557600080fd5b6136618783880161352d565b9350604086013591508082111561367757600080fd5b50613684868287016135a0565b9150509250925092565b6000806000606084860312156136a357600080fd5b833567ffffffffffffffff808211156136bb57600080fd5b818601915086601f8301126136cf57600080fd5b813560206136df612ee983613342565b82815260059290921b8401810191818101908a8411156136fe57600080fd5b8286015b848110156137365780358681111561371a5760008081fd5b6137288d86838b010161348e565b845250918301918301613702565b509750508701359250508082111561365557600080fd5b6000602080835260ff808551168285015281850151604061ffff808316604088015260408801519250606063ffffffff8416606089015260608901519350608060a060808a01526137a160c08a0186613012565b945060808a0151601f19808b88030160a08c01528682518089528a890191508a8160051b8a01018b8501945060005b8281101561383257848b830301845285518981511683528c8e820151168e8401528a810151888c85015261380689850182613012565b918a0151848303858c015291905061381e8183613012565b978f0197958f0195935050506001016137d0565b509e9d5050505050505050505050505050565b60006020828403121561385757600080fd5b813567ffffffffffffffff81111561386e57600080fd5b612fe684828501612eca565b6000806040838503121561388d57600080fd5b61389683612e7f565b915060208084013567ffffffffffffffff8111156138b357600080fd5b8401601f810186136138c457600080fd5b80356138d2612ee982613342565b81815260059190911b820183019083810190888311156138f157600080fd5b928401925b828410156139165761390784612e7f565b825292840192908401906138f6565b80955050505050509250929050565b6020815260008251610140806020850152613944610160850183613012565b91506020850151601f19808685030160408701526139628483613012565b935060408701519150613981606087018367ffffffffffffffff169052565b606087015167ffffffffffffffff811660808801529150608087015167ffffffffffffffff811660a0880152915060a087015167ffffffffffffffff811660c0880152915060c087015160e087015260e087015191506101008281880152808801519250506101206139fe8188018467ffffffffffffffff169052565b8701518685039091018387015290506132368382613240565b602081526000612d936020830184613012565b600082825180855260208086019550808260051b84010181860160005b8481101561308b57858303601f190189528151805184528481015167ffffffffffffffff90811686860152604080830151909116908501526060808201511515908501526080808201519085015260a09081015160c091850182905290613ab081860183613012565b9a86019a9450505090830190600101613a47565b6020815260008251610100806020850152613ae3610120850183613012565b915067ffffffffffffffff60208601511660408501526040850151613b14606086018267ffffffffffffffff169052565b50606085015167ffffffffffffffff8116608086015250608085015167ffffffffffffffff811660a08601525060a085015167ffffffffffffffff811660c08601525060c085015160e085015260e0850151601f1985840301828601526132368382613a2a565b60008060408385031215613b8e57600080fd5b823567ffffffffffffffff811115613ba557600080fd5b613bb185828601612f20565b9250506020830135613bc281613469565b809150509250929050565b602081526000825160c06020840152613be960e0840182613012565b90506020840151601f1980858403016040860152613c078383613012565b92506040860151915067ffffffffffffffff808316606087015280606088015116608087015250608086015160a086015260a08601519150808584030160c0860152506133398282613240565b600067ffffffffffffffff80841680613c96577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b92169190910492915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b805163ffffffff81168114612d7357600080fd5b600060208284031215613cf757600080fd5b612d9382613cd1565b60006020808385031215613d1357600080fd5b825167ffffffffffffffff80821115613d2b57600080fd5b9084019060408287031215613d3f57600080fd5b613d47612e2b565b825182811115613d5657600080fd5b83019150601f82018713613d6957600080fd5b8151613d77612ee982613342565b81815260059190911b83018501908581019089831115613d9657600080fd5b938601935b82851015613dbd578451613dae81613469565b82529386019390860190613d9b565b835250613dcd9050838501613cd1565b848201528094505050505092915050565b600060208284031215613df057600080fd5b5051919050565b805160408084528151908401819052600091602091908201906060860190845b81811015613e4957835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101613e17565b505063ffffffff602086015116602087015280935050505092915050565b60006060808301868452602060606020860152818751808452608093506080870191506020890160005b82811015613ed257815180518552858101518686015260408082015160ff908116918701919091529088015116878501529285019290840190600101613e91565b5050508581036040870152613ee78188613df7565b9998505050505050505050565b60008060408385031215613f0757600080fd5b82518015158114613f1757600080fd5b602084015190925067ffffffffffffffff811115613f3457600080fd5b8301601f81018513613f4557600080fd5b8051613f53612ee982612ea2565b818152866020838501011115613f6857600080fd5b613f79826020830160208601612fee565b8093505050509250929050565b808201808211156104fe577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008351613fd2818460208801612fee565b9190910191825250602001919050565b6000815160208301517fffffffffffffffffff00000000000000000000000000000000000000000000008082169350600983101561402a5780818460090360031b1b83161693505b505050919050565b6000806000806080858703121561404857600080fd5b50508251602084015160408501516060909501519196909550909250905056fe71756572795f726573706f6e73655f303030303030303030303030303030303030307ca26469706673582212208bf41d43fde67e1261e860ad5a30668915f99f39ef2c7e89a2294b27f192b03464736f6c6343000817003300000000000000000000000098f3c9e6e3face36baad05fe09d375ef1464288b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000004135270d8bcf6b654e1169efefc317afa8778a83
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106102415760003560e01c806384acd1bb11610145578063c42cf535116100bd578063e6a3c0e81161008c578063f2fde38b11610071578063f2fde38b1461054a578063fa2ae3601461055d578063ffa1ad741461038257600080fd5b8063e6a3c0e81461052f578063eb1d6b961461053757600080fd5b8063c42cf535146104d4578063c895dec6146104e7578063dc37e93e14610507578063e0b54d301461052757600080fd5b8063a8024ef111610114578063ba89369e116100f9578063ba89369e1461048c578063bda269f21461049f578063c008e156146104bf57600080fd5b8063a8024ef114610466578063b0bf66381461047957600080fd5b806384acd1bb146104115780638a8f2868146104385780638da5cb5b14610440578063a0f419fa1461045e57600080fd5b806345ee36c5116101d8578063571354e2116101a757806371b632c81161018c57806371b632c8146103c5578063767b9daa146103de57806378cc4030146103fe57600080fd5b8063571354e21461039d578063715018a6146103bd57600080fd5b806345ee36c51461035c57806347bdbbcf1461036f5780634d63d473146103825780634f098c0a1461038a57600080fd5b80632df2f978116102145780632df2f978146102bb57806331e0ff7a146102db5780633896fc121461033657806345e16cd31461034957600080fd5b806316476dcc146102465780632ac96ea11461025b5780632b2077ad146102815780632b7e1cd8146102a1575b600080fd5b610259610254366004613568565b6105a7565b005b61026e6102693660046135b1565b610601565b6040519081526020015b60405180910390f35b61029461028f366004613732565b610627565b6040516102789190613978565b6102a9600281565b60405160ff9091168152602001610278565b6102ce6102c9366004613732565b610c06565b6040516102789190613acb565b6103116102e9366004613b32565b60046020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610278565b610259610344366004613b71565b610f0e565b610259610357366004613c74565b6112e1565b61025961036a366004613568565b611332565b61025961037d366004613ecd565b611376565b6102a9600181565b610259610398366004613f55565b611516565b6103b06103ab366004613b71565b611556565b604051610278919061405d565b610259611b02565b61026e6103d336600461410c565b805160209091012090565b6001546103119073ffffffffffffffffffffffffffffffffffffffff1681565b61025961040c366004614149565b611b16565b6103117f00000000000000000000000098f3c9e6e3face36baad05fe09d375ef1464288b81565b6102a9600681565b60005473ffffffffffffffffffffffffffffffffffffffff16610311565b6102a9600381565b61026e61047436600461410c565b611b9c565b610259610487366004613b71565b611bec565b61025961049a3660046141f8565b611ec3565b6104b26104ad366004613732565b611ed5565b604051610278919061422f565b6104c76122a4565b6040516102789190614321565b6102596104e2366004614334565b6122c0565b6104fa6104f5366004613732565b6122d4565b60405161027891906143f2565b61051a610515366004613732565b6126ee565b60405161027891906144a9565b6102a9600481565b6102a9600581565b6102596105453660046135b1565b612a52565b610259610558366004614334565b612a64565b61058c61056b366004614530565b60036020526000908152604090208054600182015460029092015490919083565b60408051938452602084019290925290820152606001610278565b60006105b6620f4240846145a7565b67ffffffffffffffff169050818110156105fc576040517f3a04ceca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050565b61ffff8216600090815260026020526040812061061e9083612ac5565b90505b92915050565b60408051610100810182526060808252600060208084018290529383018190528183018190526080830181905260a0830181905260c083015260e08201529082015160ff166005146106bc5760208201516040517f96b8e05b00000000000000000000000000000000000000000000000000000000815260ff9091166004820152600560248201526044015b60405180910390fd5b60008060006106d8838660400151612b1e90919063ffffffff16565b60408701519094509091506106f7908463ffffffff80851690612b2c16565b90855260408681018051830160089081015167ffffffffffffffff90811660208a0152825185016010908101518216948a0194909452825185016018015181166060808b019190915292518501601990810151938b018051890190930151821660808b01528251880185015190911660a08a01529051930195509301929061077f9084612bbd565b60c0870191909152606087015160019082018101519101935060ff828116908216146107d7576040517f5e7bd6ec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8160ff1667ffffffffffffffff8111156107f3576107f36135cf565b60405190808252806020026020018201604052801561088757816020015b60408051610120810182526000808252606060208084018290529383018290528083018290526080830182905260a0830182905260c0830182905260e083015261010082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019101816108115790505b5060e087015260005b8260ff16811015610bdf5760408801516108aa9087612bbd565b8860e0015183815181106108c0576108c06145ce565b602090810291909101015191909152604089015160019082018101519101965060ff811667ffffffffffffffff8111156108fc576108fc6135cf565b60405190808252806020026020018201604052801561092f57816020015b606081526020019060019003908161091a5790505b508860e001518381518110610946576109466145ce565b60200260200101516020018190525060005b8160ff168110156109d45760408a0151600489820181015199019890610988908a63ffffffff80851690612b2c16565b8b60e00151868151811061099e5761099e6145ce565b60200260200101516020015184815181106109bb576109bb6145ce565b6020908102919091010191909152985050600101610958565b5060608901516109e49087612bbd565b8960e0015184815181106109fa576109fa6145ce565b6020026020010151604001819850828152505050610a25868a60600151612baf90919063ffffffff16565b8960e001518481518110610a3b57610a3b6145ce565b6020026020010151610100018198508260ff1660ff168152505050610a6d868a60600151612ba190919063ffffffff16565b8960e001518481518110610a8357610a836145ce565b602090810291909101015167ffffffffffffffff92909216606092830152908a0151810160089081015191975087018960e001518481518110610ac857610ac86145ce565b60200260200101516080018198508267ffffffffffffffff1667ffffffffffffffff168152505050610b07868a60600151612be390919063ffffffff16565b8960e001518481518110610b1d57610b1d6145ce565b602002602001015160a00181985082151515158152505050610b4c868a60600151612bbd90919063ffffffff16565b8960e001518481518110610b6257610b626145ce565b602002602001015160c001819850828152505050610b8d868a60600151612b1e90919063ffffffff16565b60608b0151909750909550610bac908763ffffffff80891690612b2c16565b8960e001518481518110610bc257610bc26145ce565b602090810291909101015160e00191909152955050600101610890565b50610bee876040015186612c51565b610bfc876060015185612c51565b5050505050919050565b6040805160a0810182526060808252600060208084018290529383018190528183015260808201529082015160ff16600114610c805760208201516040517f96b8e05b00000000000000000000000000000000000000000000000000000000815260ff9091166004820152600160248201526044016106b3565b6000806000610c9c838660400151612b1e90919063ffffffff16565b6040870151909450909150610cbb908463ffffffff80851690612b2c16565b90855260408601516001908201810151606088018051600890870181015167ffffffffffffffff1660208a015290519290930195509190930192610cff9084612bbd565b606087810192909252908701805182016008015167ffffffffffffffff1660408801525181016009908101519101935060ff80821690831614610d6e576040517f5e7bd6ec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8160ff1667ffffffffffffffff811115610d8a57610d8a6135cf565b604051908082528060200260200182016040528015610df557816020015b610de26040518060600160405280600073ffffffffffffffffffffffffffffffffffffffff16815260200160608152602001606081525090565b815260200190600190039081610da85790505b50608087015260005b8260ff16811015610bdf576040880151610e189087612c98565b88608001518381518110610e2e57610e2e6145ce565b602090810291909101015173ffffffffffffffffffffffffffffffffffffffff929092169091526040890151600481830181015192019750909450610e7d908763ffffffff80881690612b2c16565b88608001518381518110610e9357610e936145ce565b60200260200101516020018198508290525050610ebd858960600151612b1e90919063ffffffff16565b60608a0151909650909450610edc908663ffffffff80881690612b2c16565b88608001518381518110610ef257610ef26145ce565b6020908102919091010151604001919091529450600101610dfe565b60007f00000000000000000000000098f3c9e6e3face36baad05fe09d375ef1464288b73ffffffffffffffffffffffffffffffffffffffff16631cfe79516040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f7b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f9f9190614611565b6040517ff951975a00000000000000000000000000000000000000000000000000000000815263ffffffff8216600482015290915060009073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000098f3c9e6e3face36baad05fe09d375ef1464288b169063f951975a90602401600060405180830381865afa158015611035573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261105d919081019061462c565b9050600061106a85611b9c565b8251519091506000036110d9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f696e76616c696420677561726469616e2073657400000000000000000000000060448201526064016106b3565b8151516040517ff8ce560a00000000000000000000000000000000000000000000000000000000815260048101919091527f00000000000000000000000098f3c9e6e3face36baad05fe09d375ef1464288b73ffffffffffffffffffffffffffffffffffffffff169063f8ce560a90602401602060405180830381865afa158015611168573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061118c919061470a565b845110156111f6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f6e6f2071756f72756d000000000000000000000000000000000000000000000060448201526064016106b3565b6000807f00000000000000000000000098f3c9e6e3face36baad05fe09d375ef1464288b73ffffffffffffffffffffffffffffffffffffffff1663a0cce1b38488876040518463ffffffff1660e01b815260040161125693929190614793565b600060405180830381865afa158015611273573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261129b9190810190614820565b91509150816112d857806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106b39190614321565b50505050505050565b6112e9612cb1565b60005b815181101561132e576000828281518110611309576113096145ce565b6020026020010151905061132581600001518260200151612d04565b506001016112ec565b5050565b808267ffffffffffffffff16101561132e576040517fb10b0aec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000825160001461138857600061138b565b60015b90506000825160001461139f5760006113a2565b60015b845190915060005b81811015611413578581815181106113c4576113c46145ce565b602002602001015173ffffffffffffffffffffffffffffffffffffffff16876000015173ffffffffffffffffffffffffffffffffffffffff160361140b5760019350611413565b6001016113aa565b508261144b576040517fa710429d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b835160005b818110156114de57602088015160009061146a9082612d65565b50905086828151811061147f5761147f6145ce565b60200260200101517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916036114d55760019450506114de565b50600101611450565b50826112d8576040517f8076dd8a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b825160005b8181101561154f57611547858281518110611538576115386145ce565b60200260200101518585611376565b60010161151b565b5050505050565b6040805160a081018252600080825260208201819052918101919091526060808201819052608082015261158a8383610f0e565b60018381015160ff1680835281146115ce576040517f1d9617a000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600284820181015161ffff1660208401819052910190600003611606576115f784826041612b2c565b6060840191909152905061161d565b61161284826020612b2c565b606084019190915290505b80840160048181015160059283015185519285019491939091019160ff90811690821614611677576040517f714f551300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50600486820181015163ffffffff90811660408701529101906000906116a19088908490612baf16565b9250905060ff81166000036116e2576040517fbb6b170d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006116f463ffffffff8516866148b2565b905080600061170c8a83600191810182015192910190565b9350905060ff8082169085161461174f576040517f84ae4a3000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8360ff1667ffffffffffffffff81111561176b5761176b6135cf565b6040519080825280602002602001820160405280156117bf57816020015b60408051608081018252600080825260208201526060918101829052818101919091528152602001906001900390816117895790505b50608089015260005b8460ff16811015611aa75760028b87018101519087018a6080015183815181106117f4576117f46145ce565b602090810291909101015161ffff9092169091529550600061181f8c86600291810182015192910190565b60808c015180519197509192508390811061183c5761183c6145ce565b60200260200101516000015161ffff168161ffff1614611888576040517fa179f8c900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60018c88018101519088018b6080015184815181106118a9576118a96145ce565b60209081029190910181015160ff909316920191909152965060006118d78d87600191810182015192910190565b60808d01518051919850919250849081106118f4576118f46145ce565b60200260200101516020015160ff168160ff161461193e576040517f0216496100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600160ff168b608001518481518110611959576119596145ce565b60200260200101516020015160ff16108061199c5750600660ff168b60800151848151811061198a5761198a6145ce565b60200260200101516020015160ff1610155b156119ff578a6080015183815181106119b7576119b76145ce565b6020026020010151602001516040517f51ee58530000000000000000000000000000000000000000000000000000000081526004016106b3919060ff91909116815260200190565b60048d89018101519089019099509750611a238d8963ffffffff808d1690612b2c16565b8c608001518581518110611a3957611a396145ce565b60209081029190910101516040019190915260048e880181015191995087019099509550611a718d8763ffffffff808d1690612b2c16565b8c608001518581518110611a8757611a876145ce565b6020026020010151606001819850829052505082600101925050506117c8565b50848214611aeb576040517fc37906a000000000000000000000000000000000000000000000000000000000815260048101839052602481018690526044016106b3565b611af58a84612c51565b5050505050505092915050565b611b0a612cb1565b611b146000612d90565b565b8051600090815b81811015611b5e57838181518110611b3757611b376145ce565b602002602001015161ffff168561ffff1603611b565760019250611b5e565b600101611b1d565b5081611b96576040517f7a47c9a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050565b6000604051806060016040528060238152602001614a616023913982516020840120604051602001611bcf9291906148c5565b604051602081830303815290604052805190602001209050919050565b6000611bf88383611556565b905060005b816080015151811015611b965760006004600084608001518481518110611c2657611c266145ce565b60209081029190910181015181015160ff1682528101919091526040016000205473ffffffffffffffffffffffffffffffffffffffff16905080611c96576040517fae67532100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008173ffffffffffffffffffffffffffffffffffffffff1663da841d3985608001518581518110611cca57611cca6145ce565b60209081029190910101516001546040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b168152611d28929173ffffffffffffffffffffffffffffffffffffffff16906004016148e7565b60c060405180830381865afa158015611d45573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d69919061491f565b6040808201516020808401516000908152600382528390208351606081018552815480825260018301549382019390935260029091015493810193909352815193945090921080611dc1575081602001518160200151115b80611dd3575081604001518160400151115b15611e0a576040517f4efc1f9100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805160608082018352845182526020808601518184019081528685015184860190815288830151600090815260039093529185902093518455516001840155516002909201919091558451825191820190925282518451611eb39392918291611e7591906149bd565b815260200184602001518660200151611e8e91906149bd565b815260200184604001518660400151611ea791906149bd565b90526060860151612e05565b505060019092019150611bfd9050565b611ecb612cb1565b61132e8183612f91565b604080516101408101825260608082526020820181905260009282018390528082018390526080820183905260a0820183905260c0820183905260e08201839052610100820192909252610120810191909152602082015160ff16600214611f7b5760208201516040517f96b8e05b00000000000000000000000000000000000000000000000000000000815260ff9091166004820152600260248201526044016106b3565b6000806000611f97838660400151612ba190919063ffffffff16565b67ffffffffffffffff91909116604086810191909152860151600481830181015192019450909150611fd3908463ffffffff80851690612b2c16565b9085526040860151600481830181015192019450909150611ffe908463ffffffff80851690612b2c16565b60208601919091526040860151600190820181015160608089018051600890880181015167ffffffffffffffff16928a01929092525192909301955091909301926120499084612bbd565b60c087019190915260608701805182016008015167ffffffffffffffff90811660808901528151830160109081015190911660a08901529051910193506120909084612bbd565b60e087019190915260608701805182016008015167ffffffffffffffff166101008801525181016009908101519101935060ff80821690831614612100576040517f5e7bd6ec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8160ff1667ffffffffffffffff81111561211c5761211c6135cf565b60405190808252806020026020018201604052801561218757816020015b6121746040518060600160405280600073ffffffffffffffffffffffffffffffffffffffff16815260200160608152602001606081525090565b81526020019060019003908161213a5790505b5061012087015260005b8260ff16811015610bdf5760408801516121ab9087612c98565b88610120015183815181106121c2576121c26145ce565b602090810291909101015173ffffffffffffffffffffffffffffffffffffffff929092169091526040890151600481830181015192019750909450612211908763ffffffff80881690612b2c16565b8861012001518381518110612228576122286145ce565b60200260200101516020018198508290525050612252858960600151612b1e90919063ffffffff16565b60608a0151909650909450612271908663ffffffff80881690612b2c16565b8861012001518381518110612288576122886145ce565b6020908102919091010151604001919091529450600101612191565b604051806060016040528060238152602001614a616023913981565b6122c8612cb1565b6122d181613120565b50565b60408051610100810182526060808252600060208084018290529383018190528183018190526080830181905260a0830181905260c083015260e08201529082015160ff166004146123665760208201516040517f96b8e05b00000000000000000000000000000000000000000000000000000000815260ff90911660048281019190915260248201526044016106b3565b6000806000612382838660400151612b1e90919063ffffffff16565b60408701519094509091506123a1908463ffffffff80851690612b2c16565b90855260408681018051830160089081015167ffffffffffffffff90811660208a0152825185016010908101518216948a0194909452825185016018015181166060808b019190915292518501601990810151938b018051890190930151821660808b01528251880185015190911660a08a0152905193019550930192906124299084612bbd565b60c0870191909152606087015160019082018101519101935060ff82811690821614612481576040517f5e7bd6ec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8160ff1667ffffffffffffffff81111561249d5761249d6135cf565b60405190808252806020026020018201604052801561251d57816020015b6040805160c081018252600080825260208083018290529282018190526060808301829052608083019190915260a082015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092019101816124bb5790505b5060e087015260005b8260ff16811015610bdf5760408801516125409087612bbd565b8860e001518381518110612556576125566145ce565b6020908102919091010151919091526060890151860160089081015191975086018860e00151838151811061258d5761258d6145ce565b60200260200101516020018197508267ffffffffffffffff1667ffffffffffffffff1681525050506125cc858960600151612ba190919063ffffffff16565b8860e0015183815181106125e2576125e26145ce565b60200260200101516040018197508267ffffffffffffffff1667ffffffffffffffff168152505050612621858960600151612be390919063ffffffff16565b8860e001518381518110612637576126376145ce565b60209081029190910101519115156060928301529089015190955061265c9086612bbd565b8860e001518381518110612672576126726145ce565b602002602001015160800181975082815250505061269d858960600151612b1e90919063ffffffff16565b60608a01519096509094506126bc908663ffffffff80881690612b2c16565b8860e0015183815181106126d2576126d26145ce565b602090810291909101015160a001919091529450600101612526565b61273e6040518060c001604052806060815260200160608152602001600067ffffffffffffffff168152602001600067ffffffffffffffff16815260200160008019168152602001606081525090565b602082015160ff166003146127915760208201516040517f96b8e05b00000000000000000000000000000000000000000000000000000000815260ff9091166004820152600360248201526044016106b3565b60008060006127ad838660400151612b1e90919063ffffffff16565b60408701519094509091506127cc908463ffffffff80851690612b2c16565b90855260408601516004818301810151920194509091506127f7908463ffffffff80851690612b2c16565b60208601919091526040868101516001908301810151606089018051600890880181015167ffffffffffffffff16948a0194909452519190930195509301926128409084612bbd565b60808701919091526060878101805183016008015167ffffffffffffffff16918801919091525181016009908101519101935060ff808216908316146128b2576040517f5e7bd6ec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8160ff1667ffffffffffffffff8111156128ce576128ce6135cf565b60405190808252806020026020018201604052801561293957816020015b6129266040518060600160405280600073ffffffffffffffffffffffffffffffffffffffff16815260200160608152602001606081525090565b8152602001906001900390816128ec5790505b5060a087015260005b8260ff16811015610bdf57604088015161295c9087612c98565b8860a001518381518110612972576129726145ce565b602090810291909101015173ffffffffffffffffffffffffffffffffffffffff9290921690915260408901516004818301810151920197509094506129c1908763ffffffff80881690612b2c16565b8860a0015183815181106129d7576129d76145ce565b60200260200101516020018198508290525050612a01858960600151612b1e90919063ffffffff16565b60608a0151909650909450612a20908663ffffffff80881690612b2c16565b8860a001518381518110612a3657612a366145ce565b6020908102919091010151604001919091529450600101612942565b612a5a612cb1565b61132e8282612d04565b612a6c612cb1565b73ffffffffffffffffffffffffffffffffffffffff8116612abc576040517f1e4fbdf7000000000000000000000000000000000000000000000000000000008152600060048201526024016106b3565b6122d181612d90565b815460009081612ad7858583856131bb565b90508015612b125784612aeb6001836149bd565b81548110612afb57612afb6145ce565b906000526020600020906002020160010154612b15565b60005b95945050505050565b600491810182015192910190565b6060600082600003612b4f57505060408051600081526020810190915282612b99565b5050604051828201601f831680612b64575060205b80830184810186838901015b81831015612b88578051835260209283019201612b70565b5050848452601f01601f1916604052505b935093915050565b600891810182015192910190565b600191810182015192910190565b600080600080612bd68686602091810182015192910190565b9097909650945050505050565b600080600080612bfc8686600191810182015192910190565b909250905060fe821615612c41576040517ff7a37b0700000000000000000000000000000000000000000000000000000000815260ff831660048201526024016106b3565b60ff909116925090509250929050565b8082511461132e5781516040517fc37906a00000000000000000000000000000000000000000000000000000000081526004810191909152602481018290526044016106b3565b600080600080612bd68686601491810182015192910190565b60005473ffffffffffffffffffffffffffffffffffffffff163314611b14576040517f118cdaa70000000000000000000000000000000000000000000000000000000081523360048201526024016106b3565b61ffff82166000818152600260205260409020907fcb4fd51bf3a0766e39ffe0f81893291c14a84be4b8da0d352df1fee57f19609f612d438342612ac5565b60408051918252602082018690520160405180910390a261154f814284613223565b600080600080612d7e8686600491810182015192910190565b60e09190911b97909650945050505050565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000612e14836000015161323d565b612e21846020015161323d565b612e2e856040015161323d565b604051602001612e7e93929190608093841b7fffffffffffffffffffffffffffffffff00000000000000000000000000000000908116825292841b83166010820152921b16602082015260300190565b60408051601f1981840301815290829052600180547f5f398a1400000000000000000000000000000000000000000000000000000000845291935073ffffffffffffffffffffffffffffffffffffffff90911691635f398a1491612ee99188919086906004016149d0565b6020604051808303816000875af1158015612f08573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f2c919061470a565b5082516020840151604080860151905161ffff8616937f6afc719c5986033c8ee04237de6ef98d6eacf19eb6daa60939de50d0618ce95f93612f83938a845260208401929092526040830152606082015260800190565b60405180910390a250505050565b60ff811660008181526004602090815260409182902054825173ffffffffffffffffffffffffffffffffffffffff9182168152908616918101919091527f605377a362d179f8f97f433900dc88f457846f29a6a43430b454a11f4995c385910160405180910390a273ffffffffffffffffffffffffffffffffffffffff821661304e5760ff16600090815260046020526040902080547fffffffffffffffffffffffff000000000000000000000000000000000000000016905550565b600061309073ffffffffffffffffffffffffffffffffffffffff84167fda841d3900000000000000000000000000000000000000000000000000000000613297565b9050806130c9576040517fd62f4a2700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5060ff16600090815260046020526040902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b6001546040805173ffffffffffffffffffffffffffffffffffffffff928316815291831660208301527f1deb63b37f154ad5b5f92db0edea9bccf74dc0c235e80a86242dfddb2e33a0ec910160405180910390a1600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60005b8183101561321b5760006131d284846132b3565b9050848682815481106131e7576131e76145ce565b906000526020600020906002020160000154111561320757809250613215565b6132128160016148b2565b93505b506131be565b509392505050565b6000806132318585856132ce565b91509150935093915050565b60006fffffffffffffffffffffffffffffffff821115613293576040517f6dfcc65000000000000000000000000000000000000000000000000000000000815260806004820152602481018390526044016106b3565b5090565b60006132a283613434565b801561061e575061061e8383613498565b60006132c26002848418614a4c565b61061e908484166148b2565b8254600090819080156133ef576000866132e96001846149bd565b815481106132f9576132f96145ce565b90600052602060002090600202016040518060400160405290816000820154815260200160018201548152505090508581600001511115613366576040517f2520601d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80518690036133a657848761337c6001856149bd565b8154811061338c5761338c6145ce565b9060005260206000209060020201600101819055506133df565b604080518082019091528681526020808201878152895460018181018c5560008c81529390932093516002909102909301928355519101555b602001519250839150612b999050565b50506040805180820190915283815260208082018481528654600181810189556000898152938420945160029092029094019081559051920191909155905081612b99565b6000613460827f01ffc9a700000000000000000000000000000000000000000000000000000000613498565b80156106215750613491827fffffffff00000000000000000000000000000000000000000000000000000000613498565b1592915050565b6040517fffffffff0000000000000000000000000000000000000000000000000000000082166024820152600090819060440160408051601f19818403018152919052602080820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f01ffc9a700000000000000000000000000000000000000000000000000000000178152825192935060009283928392909183918a617530fa92503d91506000519050828015613551575060208210155b801561355d5750600081115b979650505050505050565b6000806040838503121561357b57600080fd5b823567ffffffffffffffff8116811461359357600080fd5b946020939093013593505050565b61ffff811681146122d157600080fd5b600080604083850312156135c457600080fd5b8235613593816135a1565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516080810167ffffffffffffffff81118282101715613621576136216135cf565b60405290565b6040805190810167ffffffffffffffff81118282101715613621576136216135cf565b6040516060810167ffffffffffffffff81118282101715613621576136216135cf565b604051601f8201601f1916810167ffffffffffffffff81118282101715613696576136966135cf565b604052919050565b803560ff811681146136af57600080fd5b919050565b600067ffffffffffffffff8211156136ce576136ce6135cf565b50601f01601f191660200190565b600082601f8301126136ed57600080fd5b81356137006136fb826136b4565b61366d565b81815284602083860101111561371557600080fd5b816020850160208301376000918101602001919091529392505050565b60006020828403121561374457600080fd5b813567ffffffffffffffff8082111561375c57600080fd5b908301906080828603121561377057600080fd5b6137786135fe565b8235613783816135a1565b81526137916020840161369e565b60208201526040830135828111156137a857600080fd5b6137b4878286016136dc565b6040830152506060830135828111156137cc57600080fd5b6137d8878286016136dc565b60608301525095945050505050565b60005b838110156138025781810151838201526020016137ea565b50506000910152565b600081518084526138238160208601602086016137e7565b601f01601f19169290920160200192915050565b60008282518085526020808601955060208260051b8401016020860160005b8481101561388457601f1986840301895261387283835161380b565b98840198925090830190600101613856565b5090979650505050505050565b600082825180855260208086019550808260051b84010181860160005b8481101561388457601f198684030189528151610120815185528582015181878701526138dd82870182613837565b91505060408083015181870152506060808301516139068288018267ffffffffffffffff169052565b505060808281015167ffffffffffffffff169086015260a08083015115159086015260c0808301519086015260e08083015186830382880152613949838261380b565b925050506101008083015192506139648187018460ff169052565b5099850199935050908301906001016138ae565b602081526000825161010080602085015261399761012085018361380b565b915067ffffffffffffffff602086015116604085015260408501516139c8606086018267ffffffffffffffff169052565b50606085015167ffffffffffffffff8116608086015250608085015167ffffffffffffffff811660a08601525060a085015167ffffffffffffffff811660c08601525060c085015160e085015260e0850151601f198584030182860152613a2f8382613891565b9695505050505050565b600082825180855260208086019550808260051b84010181860160005b8481101561388457601f198684030189528151606073ffffffffffffffffffffffffffffffffffffffff8251168552858201518187870152613a9a8287018261380b565b91505060408083015192508582038187015250613ab7818361380b565b9a86019a9450505090830190600101613a56565b602081526000825160a06020840152613ae760c084018261380b565b9050602084015167ffffffffffffffff80821660408601528060408701511660608601525050606084015160808401526080840151601f198483030160a0850152612b158282613a39565b600060208284031215613b4457600080fd5b61061e8261369e565b600067ffffffffffffffff821115613b6757613b676135cf565b5060051b60200190565b6000806040808486031215613b8557600080fd5b833567ffffffffffffffff80821115613b9d57600080fd5b613ba9878388016136dc565b9450602091508186013581811115613bc057600080fd5b86019050601f81018713613bd357600080fd5b8035613be16136fb82613b4d565b81815260079190911b82018301908381019089831115613c0057600080fd5b928401925b82841015613c64576080848b031215613c1e5760008081fd5b613c266135fe565b843581528585013586820152613c3d87860161369e565b878201526060613c4e81870161369e565b9082015282526080939093019290840190613c05565b8096505050505050509250929050565b60006020808385031215613c8757600080fd5b823567ffffffffffffffff811115613c9e57600080fd5b8301601f81018513613caf57600080fd5b8035613cbd6136fb82613b4d565b81815260069190911b82018301908381019087831115613cdc57600080fd5b928401925b8284101561355d5760408489031215613cfa5760008081fd5b613d02613627565b8435613d0d816135a1565b81528486013586820152825260409093019290840190613ce1565b73ffffffffffffffffffffffffffffffffffffffff811681146122d157600080fd5b600060608284031215613d5c57600080fd5b613d6461364a565b90508135613d7181613d28565b8152602082013567ffffffffffffffff80821115613d8e57600080fd5b613d9a858386016136dc565b60208401526040840135915080821115613db357600080fd5b50613dc0848285016136dc565b60408301525092915050565b600082601f830112613ddd57600080fd5b81356020613ded6136fb83613b4d565b8083825260208201915060208460051b870101935086841115613e0f57600080fd5b602086015b84811015613e34578035613e2781613d28565b8352918301918301613e14565b509695505050505050565b600082601f830112613e5057600080fd5b81356020613e606136fb83613b4d565b8083825260208201915060208460051b870101935086841115613e8257600080fd5b602086015b84811015613e345780357fffffffff0000000000000000000000000000000000000000000000000000000081168114613ec05760008081fd5b8352918301918301613e87565b600080600060608486031215613ee257600080fd5b833567ffffffffffffffff80821115613efa57600080fd5b613f0687838801613d4a565b94506020860135915080821115613f1c57600080fd5b613f2887838801613dcc565b93506040860135915080821115613f3e57600080fd5b50613f4b86828701613e3f565b9150509250925092565b600080600060608486031215613f6a57600080fd5b833567ffffffffffffffff80821115613f8257600080fd5b818601915086601f830112613f9657600080fd5b81356020613fa66136fb83613b4d565b82815260059290921b8401810191818101908a841115613fc557600080fd5b8286015b84811015613ffd57803586811115613fe15760008081fd5b613fef8d86838b0101613d4a565b845250918301918301613fc9565b5097505087013592505080821115613f1c57600080fd5b61ffff815116825260ff60208201511660208301526000604082015160806040850152614044608085018261380b565b905060608301518482036060860152612b15828261380b565b6000602080835260ff8451168184015261ffff8185015116604084015263ffffffff6040850151166060840152606084015160a060808501526140a360c085018261380b565b90506080850151601f19808684030160a08701528282518085528585019150858160051b860101868501945060005b828110156140fe57848783030184526140ec828751614014565b958801959388019391506001016140d2565b509998505050505050505050565b60006020828403121561411e57600080fd5b813567ffffffffffffffff81111561413557600080fd5b614141848285016136dc565b949350505050565b6000806040838503121561415c57600080fd5b8235614167816135a1565b915060208381013567ffffffffffffffff81111561418457600080fd5b8401601f8101861361419557600080fd5b80356141a36136fb82613b4d565b81815260059190911b820183019083810190888311156141c257600080fd5b928401925b828410156141e95783356141da816135a1565b825292840192908401906141c7565b80955050505050509250929050565b6000806040838503121561420b57600080fd5b6142148361369e565b9150602083013561422481613d28565b809150509250929050565b602081526000825161014080602085015261424e61016085018361380b565b91506020850151601f198086850301604087015261426c848361380b565b93506040870151915061428b606087018367ffffffffffffffff169052565b606087015167ffffffffffffffff811660808801529150608087015167ffffffffffffffff811660a0880152915060a087015167ffffffffffffffff811660c0880152915060c087015160e087015260e087015191506101008281880152808801519250506101206143088188018467ffffffffffffffff169052565b870151868503909101838701529050613a2f8382613a39565b60208152600061061e602083018461380b565b60006020828403121561434657600080fd5b813561435181613d28565b9392505050565b600082825180855260208086019550808260051b84010181860160005b8481101561388457858303601f190189528151805184528481015167ffffffffffffffff90811686860152604080830151909116908501526060808201511515908501526080808201519085015260a09081015160c0918501829052906143de8186018361380b565b9a86019a9450505090830190600101614375565b602081526000825161010080602085015261441161012085018361380b565b915067ffffffffffffffff60208601511660408501526040850151614442606086018267ffffffffffffffff169052565b50606085015167ffffffffffffffff8116608086015250608085015167ffffffffffffffff811660a08601525060a085015167ffffffffffffffff811660c08601525060c085015160e085015260e0850151601f198584030182860152613a2f8382614358565b602081526000825160c060208401526144c560e084018261380b565b90506020840151601f19808584030160408601526144e3838361380b565b92506040860151915067ffffffffffffffff808316606087015280606088015116608087015250608086015160a086015260a08601519150808584030160c086015250612b158282613a39565b60006020828403121561454257600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600067ffffffffffffffff808416806145c2576145c2614549565b92169190910492915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b805163ffffffff811681146136af57600080fd5b60006020828403121561462357600080fd5b61061e826145fd565b6000602080838503121561463f57600080fd5b825167ffffffffffffffff8082111561465757600080fd5b908401906040828703121561466b57600080fd5b614673613627565b82518281111561468257600080fd5b83019150601f8201871361469557600080fd5b81516146a36136fb82613b4d565b81815260059190911b830185019085810190898311156146c257600080fd5b938601935b828510156146e95784516146da81613d28565b825293860193908601906146c7565b8352506146f990508385016145fd565b848201528094505050505092915050565b60006020828403121561471c57600080fd5b5051919050565b805160408084528151908401819052600091602091908201906060860190845b8181101561477557835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101614743565b505063ffffffff602086015116602087015280935050505092915050565b60006060808301868452602060606020860152818751808452608093506080870191506020890160005b828110156147fe57815180518552858101518686015260408082015160ff9081169187019190915290880151168785015292850192908401906001016147bd565b50505085810360408701526148138188614723565b9998505050505050505050565b6000806040838503121561483357600080fd5b8251801515811461484357600080fd5b602084015190925067ffffffffffffffff81111561486057600080fd5b8301601f8101851361487157600080fd5b805161487f6136fb826136b4565b81815286602083850101111561489457600080fd5b6148a58260208301602086016137e7565b8093505050509250929050565b8082018082111561062157610621614578565b600083516148d78184602088016137e7565b9190910191825250602001919050565b6040815260006148fa6040830185614014565b905073ffffffffffffffffffffffffffffffffffffffff831660208301529392505050565b600081830360c081121561493257600080fd5b61493a6135fe565b835181526020840151602082015260607fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08301121561497857600080fd5b61498061364a565b60408581015182526060860151602083015260808601518183015282015260a084015191506149ae826135a1565b60608101919091529392505050565b8181038181111561062157610621614578565b83815260ff8316602082015260806040820152603260808201527f726f6c6c65642d757020766f74652066726f6d20676f7665726e616e6365207360a08201527f706f6b6520746f6b656e20686f6c64657273000000000000000000000000000060c082015260e060608201526000612b1560e083018461380b565b600082614a5b57614a5b614549565b50049056fe71756572795f726573706f6e73655f303030303030303030303030303030303030307ca26469706673582212208e5001e941a0f8c21e6e1708fec3ac47c4848adc52895d118c94d23f830ab64c64736f6c63430008170033
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 33 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.