Source Code
Latest 25 from a total of 159 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Add Round Data S... | 17635429 | 315 days ago | IN | 0 FRAX | 0.00000289 | ||||
| Add Round Data S... | 17624999 | 316 days ago | IN | 0 FRAX | 0.00000322 | ||||
| Add Round Data S... | 17592529 | 316 days ago | IN | 0 FRAX | 0.00000367 | ||||
| Add Round Data S... | 17549629 | 317 days ago | IN | 0 FRAX | 0.00000331 | ||||
| Add Round Data S... | 17506799 | 318 days ago | IN | 0 FRAX | 0.0000034 | ||||
| Add Round Data S... | 17506729 | 318 days ago | IN | 0 FRAX | 0.00000348 | ||||
| Add Round Data S... | 17495854 | 319 days ago | IN | 0 FRAX | 0.00000425 | ||||
| Add Max Distribu... | 17495699 | 319 days ago | IN | 0 FRAX | 0.00000277 | ||||
| Add Round Data S... | 17495667 | 319 days ago | IN | 0 FRAX | 0.00000417 | ||||
| Add Max Distribu... | 17495629 | 319 days ago | IN | 0 FRAX | 0.00000308 | ||||
| Add Max Distribu... | 17495553 | 319 days ago | IN | 0 FRAX | 0.00000281 | ||||
| Add Max Distribu... | 17495550 | 319 days ago | IN | 0 FRAX | 0.00000281 | ||||
| Add Round Data S... | 17461729 | 319 days ago | IN | 0 FRAX | 0.00000374 | ||||
| Add Round Data S... | 17418829 | 320 days ago | IN | 0 FRAX | 0.00000506 | ||||
| Add Round Data S... | 17412298 | 321 days ago | IN | 0 FRAX | 0.00007834 | ||||
| Add Round Data S... | 17375929 | 321 days ago | IN | 0 FRAX | 0.00000634 | ||||
| Add Round Data S... | 17333029 | 322 days ago | IN | 0 FRAX | 0.00000355 | ||||
| Add Round Data S... | 17308498 | 323 days ago | IN | 0 FRAX | 0.00000355 | ||||
| Add Round Data S... | 17290129 | 323 days ago | IN | 0 FRAX | 0.00000377 | ||||
| Add Round Data S... | 17247230 | 324 days ago | IN | 0 FRAX | 0.00000366 | ||||
| Add Round Data S... | 17204399 | 325 days ago | IN | 0 FRAX | 0.00000347 | ||||
| Add Round Data S... | 17204329 | 325 days ago | IN | 0 FRAX | 0.000004 | ||||
| Add Round Data S... | 17200805 | 325 days ago | IN | 0 FRAX | 0.00000396 | ||||
| Add Max Distribu... | 17200801 | 325 days ago | IN | 0 FRAX | 0.00000285 | ||||
| Add Round Data S... | 17200766 | 325 days ago | IN | 0 FRAX | 0.00000404 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Cross-Chain Transactions
Loading...
Loading
Contract Name:
MerkleProofPriceSourceSfrxUsd
Compiler Version
v0.8.20+commit.a1b79de6
Optimization Enabled:
Yes with 1000000 runs
Other Settings:
shanghai EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: ISC
pragma solidity ^0.8.19;
// ====================================================================
// | ______ _______ |
// | / _____________ __ __ / ____(_____ ____ _____ ________ |
// | / /_ / ___/ __ `| |/_/ / /_ / / __ \/ __ `/ __ \/ ___/ _ \ |
// | / __/ / / / /_/ _> < / __/ / / / / / /_/ / / / / /__/ __/ |
// | /_/ /_/ \__,_/_/|_| /_/ /_/_/ /_/\__,_/_/ /_/\___/\___/ |
// | |
// ====================================================================
// ===================== MerkleProofSfrxUsd ===========================
// ====================================================================
// Frax Finance: https://github.com/FraxFinance
// ====================================================================
import { ERC165Storage } from "src/contracts/utils/ERC165Storage.sol";
import { Timelock2Step } from "frax-std/access-control/v1/Timelock2Step.sol";
import { ITimelock2Step } from "frax-std/access-control/v1/interfaces/ITimelock2Step.sol";
import { MerkleTreeProver } from "./lib/MerkleTreeProver.sol";
import { StateProofVerifier as Verifier } from "./lib/StateProofVerifier.sol";
import { IERC4626Receiver } from "src/contracts/interfaces/IERC4626Receiver.sol";
import { IStateRootOracle } from "./interfaces/IStateRootOracle.sol";
import { FixedPointMathLib } from "@solmate/utils/FixedPointMathLib.sol";
/// @title MerkleProofPriceSource
/// @notice Proves price round data from an L1 Frax Oracle and pushes the price data to an L2 Frax Oracle
contract MerkleProofPriceSourceSfrxUsd is ERC165Storage, Timelock2Step {
/// @notice The address of the StateRootOracle on Layer 2
IStateRootOracle public immutable STATE_ROOT_ORACLE;
using FixedPointMathLib for uint256;
struct OracleConfig {
address layer1Oracle;
uint96 lastBlockProofed;
}
struct ProofPackedSfrxUsd {
bytes[] _accountProofsfrxUsd;
bytes[] _storageProofTotalSupply;
bytes[] _storageProofTotalAssets;
bytes[] _storageProofLastDist;
bytes[] _storageProofRewardsPacked;
bytes[] _storageProofRewardsCycleAmount;
}
/// @notice Information about the current rewards cycle
struct RewardsCycleData {
uint40 cycleEnd; // Timestamp of the end of the current rewards cycle
uint40 lastSync; // Timestamp of the last time the rewards cycle was synced
uint216 rewardCycleAmount; // Amount of rewards to be distributed in the current cycle
}
/// @notice Configuration linking Frax Oracles for the same asset on L1 / L2
mapping(address layer2FraxOracle => OracleConfig layer1Config) public oracleLookup;
/// @notice The ```constructor``` function
/// @param _stateRootOracle Address of the L2 StateRootOracle
/// @param _timelockAddress Address of Timelock contract on L2
constructor(address _stateRootOracle, address _timelockAddress) Timelock2Step() {
_setTimelock({ _newTimelock: _timelockAddress });
_registerInterface({ interfaceId: type(ITimelock2Step).interfaceId });
STATE_ROOT_ORACLE = IStateRootOracle(_stateRootOracle);
}
// ====================================================================
// Events
// ====================================================================
/// @notice The ```OraclePairAdded``` event is emitted when a new Frax Oracle pair is added
/// @param fraxOracleLayer1 The address of the layer 1 Frax Oracle
/// @param fraxOracleLayer2 The address of the layer 2 Frax Oracle
event OraclePairAdded(address indexed fraxOracleLayer1, address indexed fraxOracleLayer2);
// ====================================================================
// Configuration Setters
// ====================================================================
/// @dev A pair of addresses that are the Frax Oracles for the same asset on layer 1 and layer 2
struct OraclePair {
address layer1FraxOracle;
address layer2FraxOracle;
}
/// @notice The ```addOraclePairs``` function sets an L1/L2 pair if they haven't been set already
/// @param _oraclePairs List of OraclePairs representing the same oracle on L1 and L2
function addOraclePairs(OraclePair[] calldata _oraclePairs) external {
_requireTimelock();
for (uint256 i = 0; i < _oraclePairs.length; ++i) {
OraclePair memory _oraclePair = _oraclePairs[i];
if (oracleLookup[_oraclePair.layer2FraxOracle].layer1Oracle != address(0)) {
revert OraclePairAlreadySet({
fraxOracleLayer1: oracleLookup[_oraclePair.layer2FraxOracle].layer1Oracle,
fraxOracleLayer2: _oraclePair.layer2FraxOracle
});
}
oracleLookup[_oraclePair.layer2FraxOracle].layer1Oracle = _oraclePair.layer1FraxOracle;
emit OraclePairAdded({
fraxOracleLayer1: _oraclePair.layer1FraxOracle,
fraxOracleLayer2: _oraclePair.layer2FraxOracle
});
}
}
// ====================================================================
// Proof / Add Price Function
// ====================================================================
function _fetchAndProofMaxRewards(
address _sfrxUsdAddress,
uint96 _blockNumber,
bytes[] memory _accountProofSfrxUsd,
bytes[] memory _storageProofMaxDistPerSecond
) public view returns (uint256 maxDistributionPerSecond) {
IStateRootOracle.BlockInfo memory _blockInfo = STATE_ROOT_ORACLE.getBlockInfo(_blockNumber);
Verifier.Account memory accountProofsfrxUsd = MerkleTreeProver.proveStorageRoot({
stateRootHash: _blockInfo.stateRootHash,
proofAddress: _sfrxUsdAddress,
accountProof: _accountProofSfrxUsd
});
maxDistributionPerSecond = uint256(
MerkleTreeProver
.proveStorageSlotValue({
storageRootHash: accountProofsfrxUsd.storageRoot,
slot: bytes32(uint256(12)),
storageProof: _storageProofMaxDistPerSecond
})
.value
);
if (maxDistributionPerSecond == 0) revert MustBeGtZero();
}
function _fetchAndProofsfrxUsd(
address _sfrxUsdEthAddress,
uint96 _blockNumber,
ProofPackedSfrxUsd memory proofPacked
)
internal
view
returns (
uint256 totalSupply,
uint256 totalAssets,
uint256 lastRewardsDistribution,
IERC4626Receiver.RewardsCycleData memory data
)
{
data = IERC4626Receiver.RewardsCycleData(0, 0, 0);
IStateRootOracle.BlockInfo memory _blockInfo = STATE_ROOT_ORACLE.getBlockInfo(_blockNumber);
Verifier.Account memory _accountProofSfrxUsd = MerkleTreeProver.proveStorageRoot({
stateRootHash: _blockInfo.stateRootHash,
proofAddress: _sfrxUsdEthAddress,
accountProof: proofPacked._accountProofsfrxUsd
});
totalSupply = uint256(
MerkleTreeProver
.proveStorageSlotValue({
storageRootHash: _accountProofSfrxUsd.storageRoot,
slot: bytes32(uint256(2)),
storageProof: proofPacked._storageProofTotalSupply
})
.value
);
totalAssets = uint256(
MerkleTreeProver
.proveStorageSlotValue({
storageRootHash: _accountProofSfrxUsd.storageRoot,
slot: bytes32(uint256(9)),
storageProof: proofPacked._storageProofTotalAssets
})
.value
);
lastRewardsDistribution = uint256(
MerkleTreeProver
.proveStorageSlotValue({
storageRootHash: _accountProofSfrxUsd.storageRoot,
slot: bytes32(uint256(8)),
storageProof: proofPacked._storageProofLastDist
})
.value
);
{
uint256 rewardsPacked = uint256(
MerkleTreeProver
.proveStorageSlotValue({
storageRootHash: _accountProofSfrxUsd.storageRoot,
slot: bytes32(uint256(6)),
storageProof: proofPacked._storageProofRewardsPacked
})
.value
);
uint256 rewardCycleAmount = uint256(
MerkleTreeProver
.proveStorageSlotValue({
storageRootHash: _accountProofSfrxUsd.storageRoot,
slot: bytes32(uint256(7)),
storageProof: proofPacked._storageProofRewardsCycleAmount
})
.value
);
data.lastSync = uint40(bytes5(bytes32(rewardsPacked) << 176));
data.cycleEnd = uint40(bytes5(bytes32(rewardsPacked) << 216));
data.rewardCycleAmount = uint216(bytes27(bytes32(rewardCycleAmount) << 40));
}
if (totalSupply == 0) revert MustBeGtZero();
if (data.lastSync == 0) revert MustBeGtZero();
if (totalAssets == 0) revert MustBeGtZero();
}
function addMaxDistributionPerSecond(
IERC4626Receiver _sfrxUsdOracle,
uint96 _blockNumber,
bytes[] memory _accountProofsfrxUsd,
bytes[] memory _storageProofMaxDistPerSecond
) external {
uint96 lastBlockProofed = oracleLookup[address(_sfrxUsdOracle)].lastBlockProofed;
if (lastBlockProofed != 0) {
if (_blockNumber < lastBlockProofed) revert StalePush();
}
// Address of the L1 oracle
address _proofAddress = oracleLookup[address(_sfrxUsdOracle)].layer1Oracle;
if (_proofAddress == address(0)) revert WrongOracleAddress();
uint256 maxPerSecond = _fetchAndProofMaxRewards(
_proofAddress,
_blockNumber,
_accountProofsfrxUsd,
_storageProofMaxDistPerSecond
);
_sfrxUsdOracle.updateMaxDistributionPerSecond(_blockNumber, maxPerSecond);
}
function addRoundDataSfrxUsd(
IERC4626Receiver _sfrxUsdOracle,
uint96 _blockNumber,
ProofPackedSfrxUsd memory proof
) external {
uint96 lastBlockProofed = oracleLookup[address(_sfrxUsdOracle)].lastBlockProofed;
address _proofAddress;
{
if (lastBlockProofed != 0) {
if (_blockNumber < lastBlockProofed) revert StalePush();
}
// Address of the L1 oracle
_proofAddress = oracleLookup[address(_sfrxUsdOracle)].layer1Oracle;
if (_proofAddress == address(0)) revert WrongOracleAddress();
}
(
uint256 totalSupply,
uint256 totalStoredAssets,
uint256 lastRewardsDistribution,
IERC4626Receiver.RewardsCycleData memory data
) = _fetchAndProofsfrxUsd(_proofAddress, _blockNumber, proof);
_sfrxUsdOracle.updatesFRAXData(_blockNumber, totalSupply, totalStoredAssets, lastRewardsDistribution, data);
oracleLookup[address(_sfrxUsdOracle)].lastBlockProofed = _blockNumber;
}
// ====================================================================
// Errors
// ====================================================================
error OraclePairAlreadySet(address fraxOracleLayer1, address fraxOracleLayer2);
error WrongOracleAddress();
error StalePush();
error MustBeGtZero();
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165Storage.sol)
pragma solidity ^0.8.0;
import { ERC165 } from "@openzeppelin/contracts/utils/introspection/ERC165.sol";
/**
* @dev Storage based implementation of the {IERC165} interface.
*
* Contracts may inherit from this and call {_registerInterface} to declare
* their support of an interface.
*/
abstract contract ERC165Storage is ERC165 {
/**
* @dev Mapping of interface ids to whether or not it's supported.
*/
mapping(bytes4 => bool) private _supportedInterfaces;
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return super.supportsInterface(interfaceId) || _supportedInterfaces[interfaceId];
}
/**
* @dev Registers the contract as an implementer of the interface defined by
* `interfaceId`. Support of the actual ERC165 interface is automatic and
* registering its interface id is not required.
*
* See {IERC165-supportsInterface}.
*
* Requirements:
*
* - `interfaceId` cannot be the ERC165 invalid interface (`0xffffffff`).
*/
function _registerInterface(bytes4 interfaceId) internal virtual {
require(interfaceId != 0xffffffff, "ERC165: invalid interface id");
_supportedInterfaces[interfaceId] = true;
}
}// SPDX-License-Identifier: ISC
pragma solidity >=0.8.0;
// ====================================================================
// | ______ _______ |
// | / _____________ __ __ / ____(_____ ____ _____ ________ |
// | / /_ / ___/ __ `| |/_/ / /_ / / __ \/ __ `/ __ \/ ___/ _ \ |
// | / __/ / / / /_/ _> < / __/ / / / / / /_/ / / / / /__/ __/ |
// | /_/ /_/ \__,_/_/|_| /_/ /_/_/ /_/\__,_/_/ /_/\___/\___/ |
// | |
// ====================================================================
// ========================== Timelock2Step ===========================
// ====================================================================
// Frax Finance: https://github.com/FraxFinance
// Primary Author
// Drake Evans: https://github.com/DrakeEvans
// Reviewers
// Dennis: https://github.com/denett
// ====================================================================
/// @title Timelock2Step
/// @author Drake Evans (Frax Finance) https://github.com/drakeevans
/// @dev Inspired by the OpenZeppelin's Ownable2Step contract
/// @notice An abstract contract which contains 2-step transfer and renounce logic for a timelock address
abstract contract Timelock2Step {
/// @notice The pending timelock address
address public pendingTimelockAddress;
/// @notice The current timelock address
address public timelockAddress;
constructor() {
timelockAddress = msg.sender;
}
/// @notice Emitted when timelock is transferred
error OnlyTimelock();
/// @notice Emitted when pending timelock is transferred
error OnlyPendingTimelock();
/// @notice The ```TimelockTransferStarted``` event is emitted when the timelock transfer is initiated
/// @param previousTimelock The address of the previous timelock
/// @param newTimelock The address of the new timelock
event TimelockTransferStarted(address indexed previousTimelock, address indexed newTimelock);
/// @notice The ```TimelockTransferred``` event is emitted when the timelock transfer is completed
/// @param previousTimelock The address of the previous timelock
/// @param newTimelock The address of the new timelock
event TimelockTransferred(address indexed previousTimelock, address indexed newTimelock);
/// @notice The ```_isSenderTimelock``` function checks if msg.sender is current timelock address
/// @return Whether or not msg.sender is current timelock address
function _isSenderTimelock() internal view returns (bool) {
return msg.sender == timelockAddress;
}
/// @notice The ```_requireTimelock``` function reverts if msg.sender is not current timelock address
function _requireTimelock() internal view {
if (msg.sender != timelockAddress) revert OnlyTimelock();
}
/// @notice The ```_isSenderPendingTimelock``` function checks if msg.sender is pending timelock address
/// @return Whether or not msg.sender is pending timelock address
function _isSenderPendingTimelock() internal view returns (bool) {
return msg.sender == pendingTimelockAddress;
}
/// @notice The ```_requirePendingTimelock``` function reverts if msg.sender is not pending timelock address
function _requirePendingTimelock() internal view {
if (msg.sender != pendingTimelockAddress) revert OnlyPendingTimelock();
}
/// @notice The ```_transferTimelock``` function initiates the timelock transfer
/// @dev This function is to be implemented by a public function
/// @param _newTimelock The address of the nominated (pending) timelock
function _transferTimelock(address _newTimelock) internal {
pendingTimelockAddress = _newTimelock;
emit TimelockTransferStarted(timelockAddress, _newTimelock);
}
/// @notice The ```_acceptTransferTimelock``` function completes the timelock transfer
/// @dev This function is to be implemented by a public function
function _acceptTransferTimelock() internal {
pendingTimelockAddress = address(0);
_setTimelock(msg.sender);
}
/// @notice The ```_setTimelock``` function sets the timelock address
/// @dev This function is to be implemented by a public function
/// @param _newTimelock The address of the new timelock
function _setTimelock(address _newTimelock) internal {
emit TimelockTransferred(timelockAddress, _newTimelock);
timelockAddress = _newTimelock;
}
/// @notice The ```transferTimelock``` function initiates the timelock transfer
/// @dev Must be called by the current timelock
/// @param _newTimelock The address of the nominated (pending) timelock
function transferTimelock(address _newTimelock) external virtual {
_requireTimelock();
_transferTimelock(_newTimelock);
}
/// @notice The ```acceptTransferTimelock``` function completes the timelock transfer
/// @dev Must be called by the pending timelock
function acceptTransferTimelock() external virtual {
_requirePendingTimelock();
_acceptTransferTimelock();
}
/// @notice The ```renounceTimelock``` function renounces the timelock after setting pending timelock to current timelock
/// @dev Pending timelock must be set to current timelock before renouncing, creating a 2-step renounce process
function renounceTimelock() external virtual {
_requireTimelock();
_requirePendingTimelock();
_transferTimelock(address(0));
_setTimelock(address(0));
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.0;
interface ITimelock2Step {
event TimelockTransferStarted(address indexed previousTimelock, address indexed newTimelock);
event TimelockTransferred(address indexed previousTimelock, address indexed newTimelock);
function acceptTransferTimelock() external;
function pendingTimelockAddress() external view returns (address);
function renounceTimelock() external;
function timelockAddress() external view returns (address);
function transferTimelock(address _newTimelock) external;
}//SPDX-License-Identifier: ISC
pragma solidity ^0.8.20;
// ====================================================================
// | ______ _______ |
// | / _____________ __ __ / ____(_____ ____ _____ ________ |
// | / /_ / ___/ __ `| |/_/ / /_ / / __ \/ __ `/ __ \/ ___/ _ \ |
// | / __/ / / / /_/ _> < / __/ / / / / / /_/ / / / / /__/ __/ |
// | /_/ /_/ \__,_/_/|_| /_/ /_/_/ /_/\__,_/_/ /_/\___/\___/ |
// | |
// ====================================================================
// ========================= MerkleTreeProver =========================
// ====================================================================
// Frax Finance: https://github.com/FraxFinance
// Authors
// Jon Walch: https://github.com/jonwalch
// Dennis: https://github.com/denett
// Reviewers
// Drake Evans: https://github.com/DrakeEvans
// ====================================================================
import { RLPReader } from "rlp/RLPReader.sol";
import { StateProofVerifier as Verifier } from "./StateProofVerifier.sol";
/// @title MerkleTreeProver
/// @author Jon Walch (Frax Finance) https://github.com/jonwalch
/// @notice Helper function library for interacting with StateProofVerifier and RLPReader
library MerkleTreeProver {
using RLPReader for bytes;
using RLPReader for RLPReader.RLPItem;
/// @notice The ```proveStorageRoot``` function is a helper function for StateProofVerifier.extractAccountFromProof()
/// @param stateRootHash The hash of the state root
/// @param proofAddress The address of the contract we're proving
/// @param accountProof The accountProof retrieved from eth_getProof
function proveStorageRoot(
bytes32 stateRootHash,
address proofAddress,
bytes[] memory accountProof
) internal view returns (Verifier.Account memory accountPool) {
RLPReader.RLPItem[] memory accountProofRlp = new RLPReader.RLPItem[](accountProof.length);
for (uint256 i = 0; i < accountProof.length; ++i) {
accountProofRlp[i] = accountProof[i].toRlpItem();
}
accountPool = Verifier.extractAccountFromProof({
_addressHash: keccak256(abi.encodePacked(proofAddress)),
_stateRootHash: stateRootHash,
_proof: accountProofRlp
});
}
/// @notice The ```proveStorageSlotValue``` function is a helper function for StateProofVerifier.extractSlotValueFromProof()
/// @param storageRootHash The hash of the storage root
/// @param slot The slot we want to prove for the contract
/// @param storageProof The storageProof.proof retrieved from eth_getProof
function proveStorageSlotValue(
bytes32 storageRootHash,
bytes32 slot,
bytes[] memory storageProof
) internal view returns (Verifier.SlotValue memory slotValue) {
RLPReader.RLPItem[] memory storageProofRlp = new RLPReader.RLPItem[](storageProof.length);
for (uint256 i = 0; i < storageProof.length; ++i) {
storageProofRlp[i] = storageProof[i].toRlpItem();
}
slotValue = Verifier.extractSlotValueFromProof({
_slotHash: keccak256(abi.encodePacked(slot)),
_storageRootHash: storageRootHash,
_proof: storageProofRlp
});
}
}// SPDX-License-Identifier: MIT
// Copied from https://github.com/lidofinance/curve-merkle-oracle/blob/1033b3e84142317ffd8f366b52e489d5eb49c73f/contracts/StateProofVerifier.sol
pragma solidity ^0.8.20;
import { RLPReader } from "rlp/RLPReader.sol";
import { MerklePatriciaProofVerifier } from "./MerklePatriciaProofVerifier.sol";
/**
* @title A helper library for verification of Merkle Patricia account and state proofs.
*/
library StateProofVerifier {
using RLPReader for RLPReader.RLPItem;
using RLPReader for bytes;
uint256 constant HEADER_STATE_ROOT_INDEX = 3;
uint256 constant HEADER_NUMBER_INDEX = 8;
uint256 constant HEADER_TIMESTAMP_INDEX = 11;
struct BlockHeader {
bytes32 hash;
bytes32 stateRootHash;
uint256 number;
uint256 timestamp;
}
struct Account {
bool exists;
uint256 nonce;
uint256 balance;
bytes32 storageRoot;
bytes32 codeHash;
}
struct SlotValue {
bool exists;
uint256 value;
}
/**
* @notice Parses block header and verifies its presence onchain within the latest 256 blocks.
* @param _headerRlpBytes RLP-encoded block header.
*/
function verifyBlockHeader(bytes memory _headerRlpBytes) internal view returns (BlockHeader memory) {
BlockHeader memory header = parseBlockHeader(_headerRlpBytes);
// ensure that the block is actually in the blockchain
require(header.hash == blockhash(header.number), "blockhash mismatch");
return header;
}
/**
* @notice Parses RLP-encoded block header.
* @param _headerRlpBytes RLP-encoded block header.
*/
function parseBlockHeader(bytes memory _headerRlpBytes) internal pure returns (BlockHeader memory) {
BlockHeader memory result;
RLPReader.RLPItem[] memory headerFields = _headerRlpBytes.toRlpItem().toList();
require(headerFields.length > HEADER_TIMESTAMP_INDEX);
result.stateRootHash = bytes32(headerFields[HEADER_STATE_ROOT_INDEX].toUint());
result.number = headerFields[HEADER_NUMBER_INDEX].toUint();
result.timestamp = headerFields[HEADER_TIMESTAMP_INDEX].toUint();
result.hash = keccak256(_headerRlpBytes);
return result;
}
/**
* @notice Verifies Merkle Patricia proof of an account and extracts the account fields.
*
* @param _addressHash Keccak256 hash of the address corresponding to the account.
* @param _stateRootHash MPT root hash of the Ethereum state trie.
*/
function extractAccountFromProof(
bytes32 _addressHash, // keccak256(abi.encodePacked(address))
bytes32 _stateRootHash,
RLPReader.RLPItem[] memory _proof
) internal pure returns (Account memory) {
bytes memory acctRlpBytes = MerklePatriciaProofVerifier.extractProofValue(
_stateRootHash,
abi.encodePacked(_addressHash),
_proof
);
Account memory account;
if (acctRlpBytes.length == 0) {
return account;
}
RLPReader.RLPItem[] memory acctFields = acctRlpBytes.toRlpItem().toList();
require(acctFields.length == 4);
account.exists = true;
account.nonce = acctFields[0].toUint();
account.balance = acctFields[1].toUint();
account.storageRoot = bytes32(acctFields[2].toUint());
account.codeHash = bytes32(acctFields[3].toUint());
return account;
}
/**
* @notice Verifies Merkle Patricia proof of a slot and extracts the slot's value.
*
* @param _slotHash Keccak256 hash of the slot position.
* @param _storageRootHash MPT root hash of the account's storage trie.
*/
function extractSlotValueFromProof(
bytes32 _slotHash,
bytes32 _storageRootHash,
RLPReader.RLPItem[] memory _proof
) internal pure returns (SlotValue memory) {
bytes memory valueRlpBytes = MerklePatriciaProofVerifier.extractProofValue(
_storageRootHash,
abi.encodePacked(_slotHash),
_proof
);
SlotValue memory value;
if (valueRlpBytes.length != 0) {
value.exists = true;
value.value = valueRlpBytes.toRlpItem().toUint();
}
return value;
}
}// SPDX-License-Identifier: ISC
pragma solidity ^0.8.19;
interface IERC4626Receiver {
function updateErc4262VaultData(
uint96 _l1BlockNumber,
uint256 _totalSupply,
uint256 _totalAssets,
uint192 _lastRewardsAmount,
uint32 _lastSync,
uint32 _rewardsCycleEnd
) external;
/// @notice Information about the current rewards cycle
struct RewardsCycleData {
uint40 cycleEnd; // Timestamp of the end of the current rewards cycle
uint40 lastSync; // Timestamp of the last time the rewards cycle was synced
uint216 rewardCycleAmount; // Amount of rewards to be distributed in the current cycle
}
function updatesFRAXData(
uint96 _l1BlockNumber,
uint256 _totalSupply,
uint256 _totalAssets,
uint256 _lastDistributionAmount,
RewardsCycleData memory data
) external;
function updateMaxDistributionPerSecond(uint96 _l1BlockNumber, uint256 maxPerSecond) external;
function updateDaiVaultData(uint96 _l1BlockNumber, uint256 _dsr, uint256 _rho, uint256 _chi) external;
function getPrices() external view returns (bool, uint256, uint256);
function dsr() external view returns (uint256);
function chi() external view returns (uint256);
function rho() external view returns (uint256);
function updateSUSDeVaultData(
uint96 _l1BlockNumber,
uint256 _totalSupply,
uint256 _totalAssets,
uint256 _vestingAmount,
uint256 _lastDistributionTimestamp
) external;
function updateEzEthRateData(uint96 _l1BlockNumber, uint256 _l1Timestamp, uint256 _ezEthRate) external;
function updateFpiOracleData(
uint96 _l1BlockNumber,
uint256 _rampPeriod,
uint256 _lastUpdateTime,
uint256 _pegPriceTarget,
uint256 _pegpriceLast
) external;
function updateRsEthOracle(uint96 _l1blockNumber, uint256 _l1Timestamp, uint256 _rsEthPrice) external;
function pricePerShare() external view returns (uint256);
function updateWstEthRateData(uint96 _l1BlockNumber, uint256 _l1Timestamp, uint256 _wstEthRate) external;
}// SPDX-License-Identifier: ISC
pragma solidity ^0.8.20;
interface IStateRootOracle {
struct BlockInfo {
bytes32 stateRootHash;
uint40 timestamp;
}
function getBlockInfo(uint256 blockNumber) external view returns (BlockInfo memory _blockInfo);
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
/// @notice Arithmetic library with operations for fixed-point numbers.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/utils/FixedPointMathLib.sol)
/// @author Inspired by USM (https://github.com/usmfum/USM/blob/master/contracts/WadMath.sol)
library FixedPointMathLib {
/*//////////////////////////////////////////////////////////////
SIMPLIFIED FIXED POINT OPERATIONS
//////////////////////////////////////////////////////////////*/
uint256 internal constant WAD = 1e18; // The scalar of ETH and most ERC20s.
function mulWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivDown(x, y, WAD); // Equivalent to (x * y) / WAD rounded down.
}
function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivUp(x, y, WAD); // Equivalent to (x * y) / WAD rounded up.
}
function divWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivDown(x, WAD, y); // Equivalent to (x * WAD) / y rounded down.
}
function divWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivUp(x, WAD, y); // Equivalent to (x * WAD) / y rounded up.
}
/*//////////////////////////////////////////////////////////////
LOW LEVEL FIXED POINT OPERATIONS
//////////////////////////////////////////////////////////////*/
function mulDivDown(
uint256 x,
uint256 y,
uint256 denominator
) internal pure returns (uint256 z) {
assembly {
// Store x * y in z for now.
z := mul(x, y)
// Equivalent to require(denominator != 0 && (x == 0 || (x * y) / x == y))
if iszero(and(iszero(iszero(denominator)), or(iszero(x), eq(div(z, x), y)))) {
revert(0, 0)
}
// Divide z by the denominator.
z := div(z, denominator)
}
}
function mulDivUp(
uint256 x,
uint256 y,
uint256 denominator
) internal pure returns (uint256 z) {
assembly {
// Store x * y in z for now.
z := mul(x, y)
// Equivalent to require(denominator != 0 && (x == 0 || (x * y) / x == y))
if iszero(and(iszero(iszero(denominator)), or(iszero(x), eq(div(z, x), y)))) {
revert(0, 0)
}
// First, divide z - 1 by the denominator and add 1.
// We allow z - 1 to underflow if z is 0, because we multiply the
// end result by 0 if z is zero, ensuring we return 0 if z is zero.
z := mul(iszero(iszero(z)), add(div(sub(z, 1), denominator), 1))
}
}
function rpow(
uint256 x,
uint256 n,
uint256 scalar
) internal pure returns (uint256 z) {
assembly {
switch x
case 0 {
switch n
case 0 {
// 0 ** 0 = 1
z := scalar
}
default {
// 0 ** n = 0
z := 0
}
}
default {
switch mod(n, 2)
case 0 {
// If n is even, store scalar in z for now.
z := scalar
}
default {
// If n is odd, store x in z for now.
z := x
}
// Shifting right by 1 is like dividing by 2.
let half := shr(1, scalar)
for {
// Shift n right by 1 before looping to halve it.
n := shr(1, n)
} n {
// Shift n right by 1 each iteration to halve it.
n := shr(1, n)
} {
// Revert immediately if x ** 2 would overflow.
// Equivalent to iszero(eq(div(xx, x), x)) here.
if shr(128, x) {
revert(0, 0)
}
// Store x squared.
let xx := mul(x, x)
// Round to the nearest number.
let xxRound := add(xx, half)
// Revert if xx + half overflowed.
if lt(xxRound, xx) {
revert(0, 0)
}
// Set x to scaled xxRound.
x := div(xxRound, scalar)
// If n is even:
if mod(n, 2) {
// Compute z * x.
let zx := mul(z, x)
// If z * x overflowed:
if iszero(eq(div(zx, x), z)) {
// Revert if x is non-zero.
if iszero(iszero(x)) {
revert(0, 0)
}
}
// Round to the nearest number.
let zxRound := add(zx, half)
// Revert if zx + half overflowed.
if lt(zxRound, zx) {
revert(0, 0)
}
// Return properly scaled zxRound.
z := div(zxRound, scalar)
}
}
}
}
}
/*//////////////////////////////////////////////////////////////
GENERAL NUMBER UTILITIES
//////////////////////////////////////////////////////////////*/
function sqrt(uint256 x) internal pure returns (uint256 z) {
assembly {
// Start off with z at 1.
z := 1
// Used below to help find a nearby power of 2.
let y := x
// Find the lowest power of 2 that is at least sqrt(x).
if iszero(lt(y, 0x100000000000000000000000000000000)) {
y := shr(128, y) // Like dividing by 2 ** 128.
z := shl(64, z) // Like multiplying by 2 ** 64.
}
if iszero(lt(y, 0x10000000000000000)) {
y := shr(64, y) // Like dividing by 2 ** 64.
z := shl(32, z) // Like multiplying by 2 ** 32.
}
if iszero(lt(y, 0x100000000)) {
y := shr(32, y) // Like dividing by 2 ** 32.
z := shl(16, z) // Like multiplying by 2 ** 16.
}
if iszero(lt(y, 0x10000)) {
y := shr(16, y) // Like dividing by 2 ** 16.
z := shl(8, z) // Like multiplying by 2 ** 8.
}
if iszero(lt(y, 0x100)) {
y := shr(8, y) // Like dividing by 2 ** 8.
z := shl(4, z) // Like multiplying by 2 ** 4.
}
if iszero(lt(y, 0x10)) {
y := shr(4, y) // Like dividing by 2 ** 4.
z := shl(2, z) // Like multiplying by 2 ** 2.
}
if iszero(lt(y, 0x8)) {
// Equivalent to 2 ** z.
z := shl(1, z)
}
// Shifting right by 1 is like dividing by 2.
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
// Compute a rounded down version of z.
let zRoundDown := div(x, z)
// If zRoundDown is smaller, use it.
if lt(zRoundDown, z) {
z := zRoundDown
}
}
}
}// 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.0 /* * @author Hamdi Allam [email protected] * Please reach out with any questions or concerns */ pragma solidity >=0.5.10 <0.9.0; library RLPReader { uint8 constant STRING_SHORT_START = 0x80; uint8 constant STRING_LONG_START = 0xb8; uint8 constant LIST_SHORT_START = 0xc0; uint8 constant LIST_LONG_START = 0xf8; uint8 constant WORD_SIZE = 32; struct RLPItem { uint256 len; uint256 memPtr; } struct Iterator { RLPItem item; // Item that's being iterated over. uint256 nextPtr; // Position of the next item in the list. } /* * @dev Returns the next element in the iteration. Reverts if it has not next element. * @param self The iterator. * @return The next element in the iteration. */ function next(Iterator memory self) internal pure returns (RLPItem memory) { require(hasNext(self)); uint256 ptr = self.nextPtr; uint256 itemLength = _itemLength(ptr); self.nextPtr = ptr + itemLength; return RLPItem(itemLength, ptr); } /* * @dev Returns true if the iteration has more elements. * @param self The iterator. * @return true if the iteration has more elements. */ function hasNext(Iterator memory self) internal pure returns (bool) { RLPItem memory item = self.item; return self.nextPtr < item.memPtr + item.len; } /* * @param item RLP encoded bytes */ function toRlpItem(bytes memory item) internal pure returns (RLPItem memory) { uint256 memPtr; assembly { memPtr := add(item, 0x20) } return RLPItem(item.length, memPtr); } /* * @dev Create an iterator. Reverts if item is not a list. * @param self The RLP item. * @return An 'Iterator' over the item. */ function iterator(RLPItem memory self) internal pure returns (Iterator memory) { require(isList(self)); uint256 ptr = self.memPtr + _payloadOffset(self.memPtr); return Iterator(self, ptr); } /* * @param the RLP item. */ function rlpLen(RLPItem memory item) internal pure returns (uint256) { return item.len; } /* * @param the RLP item. * @return (memPtr, len) pair: location of the item's payload in memory. */ function payloadLocation(RLPItem memory item) internal pure returns (uint256, uint256) { uint256 offset = _payloadOffset(item.memPtr); uint256 memPtr = item.memPtr + offset; uint256 len = item.len - offset; // data length return (memPtr, len); } /* * @param the RLP item. */ function payloadLen(RLPItem memory item) internal pure returns (uint256) { (, uint256 len) = payloadLocation(item); return len; } /* * @param the RLP item containing the encoded list. */ function toList(RLPItem memory item) internal pure returns (RLPItem[] memory) { require(isList(item)); uint256 items = numItems(item); RLPItem[] memory result = new RLPItem[](items); uint256 memPtr = item.memPtr + _payloadOffset(item.memPtr); uint256 dataLen; for (uint256 i = 0; i < items; i++) { dataLen = _itemLength(memPtr); result[i] = RLPItem(dataLen, memPtr); memPtr = memPtr + dataLen; } return result; } // @return indicator whether encoded payload is a list. negate this function call for isData. function isList(RLPItem memory item) internal pure returns (bool) { if (item.len == 0) return false; uint8 byte0; uint256 memPtr = item.memPtr; assembly { byte0 := byte(0, mload(memPtr)) } if (byte0 < LIST_SHORT_START) return false; return true; } /* * @dev A cheaper version of keccak256(toRlpBytes(item)) that avoids copying memory. * @return keccak256 hash of RLP encoded bytes. */ function rlpBytesKeccak256(RLPItem memory item) internal pure returns (bytes32) { uint256 ptr = item.memPtr; uint256 len = item.len; bytes32 result; assembly { result := keccak256(ptr, len) } return result; } /* * @dev A cheaper version of keccak256(toBytes(item)) that avoids copying memory. * @return keccak256 hash of the item payload. */ function payloadKeccak256(RLPItem memory item) internal pure returns (bytes32) { (uint256 memPtr, uint256 len) = payloadLocation(item); bytes32 result; assembly { result := keccak256(memPtr, len) } return result; } /** RLPItem conversions into data types **/ // @returns raw rlp encoding in bytes function toRlpBytes(RLPItem memory item) internal pure returns (bytes memory) { bytes memory result = new bytes(item.len); if (result.length == 0) return result; uint256 ptr; assembly { ptr := add(0x20, result) } copy(item.memPtr, ptr, item.len); return result; } // any non-zero byte except "0x80" is considered true function toBoolean(RLPItem memory item) internal pure returns (bool) { require(item.len == 1); uint256 result; uint256 memPtr = item.memPtr; assembly { result := byte(0, mload(memPtr)) } // SEE Github Issue #5. // Summary: Most commonly used RLP libraries (i.e Geth) will encode // "0" as "0x80" instead of as "0". We handle this edge case explicitly // here. if (result == 0 || result == STRING_SHORT_START) { return false; } else { return true; } } function toAddress(RLPItem memory item) internal pure returns (address) { // 1 byte for the length prefix require(item.len == 21); return address(uint160(toUint(item))); } function toUint(RLPItem memory item) internal pure returns (uint256) { require(item.len > 0 && item.len <= 33); (uint256 memPtr, uint256 len) = payloadLocation(item); uint256 result; assembly { result := mload(memPtr) // shift to the correct location if neccesary if lt(len, 32) { result := div(result, exp(256, sub(32, len))) } } return result; } // enforces 32 byte length function toUintStrict(RLPItem memory item) internal pure returns (uint256) { // one byte prefix require(item.len == 33); uint256 result; uint256 memPtr = item.memPtr + 1; assembly { result := mload(memPtr) } return result; } function toBytes(RLPItem memory item) internal pure returns (bytes memory) { require(item.len > 0); (uint256 memPtr, uint256 len) = payloadLocation(item); bytes memory result = new bytes(len); uint256 destPtr; assembly { destPtr := add(0x20, result) } copy(memPtr, destPtr, len); return result; } /* * Private Helpers */ // @return number of payload items inside an encoded list. function numItems(RLPItem memory item) private pure returns (uint256) { if (item.len == 0) return 0; uint256 count = 0; uint256 currPtr = item.memPtr + _payloadOffset(item.memPtr); uint256 endPtr = item.memPtr + item.len; while (currPtr < endPtr) { currPtr = currPtr + _itemLength(currPtr); // skip over an item count++; } return count; } // @return entire rlp item byte length function _itemLength(uint256 memPtr) private pure returns (uint256) { uint256 itemLen; uint256 byte0; assembly { byte0 := byte(0, mload(memPtr)) } if (byte0 < STRING_SHORT_START) { itemLen = 1; } else if (byte0 < STRING_LONG_START) { itemLen = byte0 - STRING_SHORT_START + 1; } else if (byte0 < LIST_SHORT_START) { assembly { let byteLen := sub(byte0, 0xb7) // # of bytes the actual length is memPtr := add(memPtr, 1) // skip over the first byte /* 32 byte word size */ let dataLen := div(mload(memPtr), exp(256, sub(32, byteLen))) // right shifting to get the len itemLen := add(dataLen, add(byteLen, 1)) } } else if (byte0 < LIST_LONG_START) { itemLen = byte0 - LIST_SHORT_START + 1; } else { assembly { let byteLen := sub(byte0, 0xf7) memPtr := add(memPtr, 1) let dataLen := div(mload(memPtr), exp(256, sub(32, byteLen))) // right shifting to the correct length itemLen := add(dataLen, add(byteLen, 1)) } } return itemLen; } // @return number of bytes until the data function _payloadOffset(uint256 memPtr) private pure returns (uint256) { uint256 byte0; assembly { byte0 := byte(0, mload(memPtr)) } if (byte0 < STRING_SHORT_START) { return 0; } else if (byte0 < STRING_LONG_START || (byte0 >= LIST_SHORT_START && byte0 < LIST_LONG_START)) { return 1; } else if (byte0 < LIST_SHORT_START) { // being explicit return byte0 - (STRING_LONG_START - 1) + 1; } else { return byte0 - (LIST_LONG_START - 1) + 1; } } /* * @param src Pointer to source * @param dest Pointer to destination * @param len Amount of memory to copy from the source */ function copy(uint256 src, uint256 dest, uint256 len) private pure { if (len == 0) return; // copy as many word sizes as possible for (; len >= WORD_SIZE; len -= WORD_SIZE) { assembly { mstore(dest, mload(src)) } src += WORD_SIZE; dest += WORD_SIZE; } if (len > 0) { // left over bytes. Mask is used to remove unwanted bytes from the word uint256 mask = 256**(WORD_SIZE - len) - 1; assembly { let srcpart := and(mload(src), not(mask)) // zero out src let destpart := and(mload(dest), mask) // retrieve the bytes mstore(dest, or(destpart, srcpart)) } } } }
// SPDX-License-Identifier: MIT
// Copied from https://github.com/lidofinance/curve-merkle-oracle/blob/1033b3e84142317ffd8f366b52e489d5eb49c73f/contracts/MerklePatriciaProofVerifier.sol
/**
* Copied from https://github.com/lorenzb/proveth/blob/c74b20e/onchain/ProvethVerifier.sol
* with minor performance and code style-related modifications.
*/
pragma solidity ^0.8.20;
import { RLPReader } from "rlp/RLPReader.sol";
library MerklePatriciaProofVerifier {
using RLPReader for RLPReader.RLPItem;
using RLPReader for bytes;
/// @dev Validates a Merkle-Patricia-Trie proof.
/// If the proof proves the inclusion of some key-value pair in the
/// trie, the value is returned. Otherwise, i.e. if the proof proves
/// the exclusion of a key from the trie, an empty byte array is
/// returned.
/// @param rootHash is the Keccak-256 hash of the root node of the MPT.
/// @param path is the key of the node whose inclusion/exclusion we are
/// proving.
/// @param stack is the stack of MPT nodes (starting with the root) that
/// need to be traversed during verification.
/// @return value whose inclusion is proved or an empty byte array for
/// a proof of exclusion
function extractProofValue(
bytes32 rootHash,
bytes memory path,
RLPReader.RLPItem[] memory stack
) internal pure returns (bytes memory value) {
bytes memory mptKey = _decodeNibbles(path, 0);
uint256 mptKeyOffset = 0;
bytes32 nodeHashHash;
RLPReader.RLPItem[] memory node;
RLPReader.RLPItem memory rlpValue;
if (stack.length == 0) {
// Root hash of empty Merkle-Patricia-Trie
require(rootHash == 0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421);
return new bytes(0);
}
// Traverse stack of nodes starting at root.
for (uint256 i = 0; i < stack.length; i++) {
// We use the fact that an rlp encoded list consists of some
// encoding of its length plus the concatenation of its
// *rlp-encoded* items.
// The root node is hashed with Keccak-256 ...
if (i == 0 && rootHash != stack[i].rlpBytesKeccak256()) {
revert();
}
// ... whereas all other nodes are hashed with the MPT
// hash function.
if (i != 0 && nodeHashHash != _mptHashHash(stack[i])) {
revert();
}
// We verified that stack[i] has the correct hash, so we
// may safely decode it.
node = stack[i].toList();
if (node.length == 2) {
// Extension or Leaf node
bool isLeaf;
bytes memory nodeKey;
(isLeaf, nodeKey) = _merklePatriciaCompactDecode(node[0].toBytes());
uint256 prefixLength = _sharedPrefixLength(mptKeyOffset, mptKey, nodeKey);
mptKeyOffset += prefixLength;
if (prefixLength < nodeKey.length) {
// Proof claims divergent extension or leaf. (Only
// relevant for proofs of exclusion.)
// An Extension/Leaf node is divergent iff it "skips" over
// the point at which a Branch node should have been had the
// excluded key been included in the trie.
// Example: Imagine a proof of exclusion for path [1, 4],
// where the current node is a Leaf node with
// path [1, 3, 3, 7]. For [1, 4] to be included, there
// should have been a Branch node at [1] with a child
// at 3 and a child at 4.
// Sanity check
if (i < stack.length - 1) {
// divergent node must come last in proof
revert();
}
return new bytes(0);
}
if (isLeaf) {
// Sanity check
if (i < stack.length - 1) {
// leaf node must come last in proof
revert();
}
if (mptKeyOffset < mptKey.length) {
return new bytes(0);
}
rlpValue = node[1];
return rlpValue.toBytes();
} else {
// extension
// Sanity check
if (i == stack.length - 1) {
// shouldn't be at last level
revert();
}
if (!node[1].isList()) {
// rlp(child) was at least 32 bytes. node[1] contains
// Keccak256(rlp(child)).
nodeHashHash = node[1].payloadKeccak256();
} else {
// rlp(child) was less than 32 bytes. node[1] contains
// rlp(child).
nodeHashHash = node[1].rlpBytesKeccak256();
}
}
} else if (node.length == 17) {
// Branch node
if (mptKeyOffset != mptKey.length) {
// we haven't consumed the entire path, so we need to look at a child
uint8 nibble = uint8(mptKey[mptKeyOffset]);
mptKeyOffset += 1;
if (nibble >= 16) {
// each element of the path has to be a nibble
revert();
}
if (_isEmptyBytesequence(node[nibble])) {
// Sanity
if (i != stack.length - 1) {
// leaf node should be at last level
revert();
}
return new bytes(0);
} else if (!node[nibble].isList()) {
nodeHashHash = node[nibble].payloadKeccak256();
} else {
nodeHashHash = node[nibble].rlpBytesKeccak256();
}
} else {
// we have consumed the entire mptKey, so we need to look at what's contained in this node.
// Sanity
if (i != stack.length - 1) {
// should be at last level
revert();
}
return node[16].toBytes();
}
}
}
}
/// @dev Computes the hash of the Merkle-Patricia-Trie hash of the RLP item.
/// Merkle-Patricia-Tries use a weird "hash function" that outputs
/// *variable-length* hashes: If the item is shorter than 32 bytes,
/// the MPT hash is the item. Otherwise, the MPT hash is the
/// Keccak-256 hash of the item.
/// The easiest way to compare variable-length byte sequences is
/// to compare their Keccak-256 hashes.
/// @param item The RLP item to be hashed.
/// @return Keccak-256(MPT-hash(item))
function _mptHashHash(RLPReader.RLPItem memory item) private pure returns (bytes32) {
if (item.len < 32) {
return item.rlpBytesKeccak256();
} else {
return keccak256(abi.encodePacked(item.rlpBytesKeccak256()));
}
}
function _isEmptyBytesequence(RLPReader.RLPItem memory item) private pure returns (bool) {
if (item.len != 1) {
return false;
}
uint8 b;
uint256 memPtr = item.memPtr;
assembly {
b := byte(0, mload(memPtr))
}
return b == 0x80; /* empty byte string */
}
function _merklePatriciaCompactDecode(
bytes memory compact
) private pure returns (bool isLeaf, bytes memory nibbles) {
require(compact.length > 0);
uint256 first_nibble = (uint8(compact[0]) >> 4) & 0xF;
uint256 skipNibbles;
if (first_nibble == 0) {
skipNibbles = 2;
isLeaf = false;
} else if (first_nibble == 1) {
skipNibbles = 1;
isLeaf = false;
} else if (first_nibble == 2) {
skipNibbles = 2;
isLeaf = true;
} else if (first_nibble == 3) {
skipNibbles = 1;
isLeaf = true;
} else {
// Not supposed to happen!
revert();
}
return (isLeaf, _decodeNibbles(compact, skipNibbles));
}
function _decodeNibbles(bytes memory compact, uint256 skipNibbles) private pure returns (bytes memory nibbles) {
require(compact.length > 0);
uint256 length = compact.length * 2;
require(skipNibbles <= length);
length -= skipNibbles;
nibbles = new bytes(length);
uint256 nibblesLength = 0;
for (uint256 i = skipNibbles; i < skipNibbles + length; i += 1) {
if (i % 2 == 0) {
nibbles[nibblesLength] = bytes1((uint8(compact[i / 2]) >> 4) & 0xF);
} else {
nibbles[nibblesLength] = bytes1((uint8(compact[i / 2]) >> 0) & 0xF);
}
nibblesLength += 1;
}
assert(nibblesLength == nibbles.length);
}
function _sharedPrefixLength(uint256 xsOffset, bytes memory xs, bytes memory ys) private pure returns (uint256) {
uint256 i;
for (i = 0; i + xsOffset < xs.length && i < ys.length; i++) {
if (xs[i + xsOffset] != ys[i]) {
return i;
}
}
return i;
}
}// 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);
}{
"remappings": [
"ds-test/=node_modules/ds-test/src/",
"forge-std/=node_modules/forge-std/src/",
"frax-std/=node_modules/frax-standard-solidity/src/",
"script/=src/script/",
"src/=src/",
"test/=src/test/",
"interfaces/=src/contracts/interfaces/",
"arbitrum/=node_modules/@arbitrum/",
"rlp/=node_modules/solidity-rlp/contracts/",
"@solmate/=node_modules/@rari-capital/solmate/src/",
"@arbitrum/=node_modules/@arbitrum/",
"@chainlink/=node_modules/@chainlink/",
"@mean-finance/=node_modules/@mean-finance/",
"@openzeppelin/=node_modules/@openzeppelin/",
"@rari-capital/=node_modules/@rari-capital/",
"@uniswap/=node_modules/@uniswap/",
"dev-fraxswap/=node_modules/dev-fraxswap/",
"frax-standard-solidity/=node_modules/frax-standard-solidity/",
"prb-math/=node_modules/prb-math/",
"solidity-bytes-utils/=node_modules/solidity-bytes-utils/",
"solidity-rlp/=node_modules/solidity-rlp/"
],
"optimizer": {
"enabled": true,
"runs": 1000000
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "none",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "shanghai",
"viaIR": false,
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_stateRootOracle","type":"address"},{"internalType":"address","name":"_timelockAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"MustBeGtZero","type":"error"},{"inputs":[],"name":"OnlyPendingTimelock","type":"error"},{"inputs":[],"name":"OnlyTimelock","type":"error"},{"inputs":[{"internalType":"address","name":"fraxOracleLayer1","type":"address"},{"internalType":"address","name":"fraxOracleLayer2","type":"address"}],"name":"OraclePairAlreadySet","type":"error"},{"inputs":[],"name":"StalePush","type":"error"},{"inputs":[],"name":"WrongOracleAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"fraxOracleLayer1","type":"address"},{"indexed":true,"internalType":"address","name":"fraxOracleLayer2","type":"address"}],"name":"OraclePairAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousTimelock","type":"address"},{"indexed":true,"internalType":"address","name":"newTimelock","type":"address"}],"name":"TimelockTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousTimelock","type":"address"},{"indexed":true,"internalType":"address","name":"newTimelock","type":"address"}],"name":"TimelockTransferred","type":"event"},{"inputs":[],"name":"STATE_ROOT_ORACLE","outputs":[{"internalType":"contract IStateRootOracle","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_sfrxUsdAddress","type":"address"},{"internalType":"uint96","name":"_blockNumber","type":"uint96"},{"internalType":"bytes[]","name":"_accountProofSfrxUsd","type":"bytes[]"},{"internalType":"bytes[]","name":"_storageProofMaxDistPerSecond","type":"bytes[]"}],"name":"_fetchAndProofMaxRewards","outputs":[{"internalType":"uint256","name":"maxDistributionPerSecond","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptTransferTimelock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC4626Receiver","name":"_sfrxUsdOracle","type":"address"},{"internalType":"uint96","name":"_blockNumber","type":"uint96"},{"internalType":"bytes[]","name":"_accountProofsfrxUsd","type":"bytes[]"},{"internalType":"bytes[]","name":"_storageProofMaxDistPerSecond","type":"bytes[]"}],"name":"addMaxDistributionPerSecond","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"layer1FraxOracle","type":"address"},{"internalType":"address","name":"layer2FraxOracle","type":"address"}],"internalType":"struct MerkleProofPriceSourceSfrxUsd.OraclePair[]","name":"_oraclePairs","type":"tuple[]"}],"name":"addOraclePairs","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC4626Receiver","name":"_sfrxUsdOracle","type":"address"},{"internalType":"uint96","name":"_blockNumber","type":"uint96"},{"components":[{"internalType":"bytes[]","name":"_accountProofsfrxUsd","type":"bytes[]"},{"internalType":"bytes[]","name":"_storageProofTotalSupply","type":"bytes[]"},{"internalType":"bytes[]","name":"_storageProofTotalAssets","type":"bytes[]"},{"internalType":"bytes[]","name":"_storageProofLastDist","type":"bytes[]"},{"internalType":"bytes[]","name":"_storageProofRewardsPacked","type":"bytes[]"},{"internalType":"bytes[]","name":"_storageProofRewardsCycleAmount","type":"bytes[]"}],"internalType":"struct MerkleProofPriceSourceSfrxUsd.ProofPackedSfrxUsd","name":"proof","type":"tuple"}],"name":"addRoundDataSfrxUsd","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"layer2FraxOracle","type":"address"}],"name":"oracleLookup","outputs":[{"internalType":"address","name":"layer1Oracle","type":"address"},{"internalType":"uint96","name":"lastBlockProofed","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingTimelockAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceTimelock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"timelockAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_newTimelock","type":"address"}],"name":"transferTimelock","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
60a060405234801562000010575f80fd5b506040516200289d3803806200289d83398101604081905262000033916200016f565b600280546001600160a01b03191633179055620000508162000075565b62000062632fa3fc3160e21b620000d0565b506001600160a01b0316608052620001a5565b6002546040516001600160a01b038084169216907f31b6c5a04b069b6ec1b3cef44c4e7c1eadd721349cda9823d0b1877b3551cdc6905f90a3600280546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160e01b031980821690036200012f5760405162461bcd60e51b815260206004820152601c60248201527f4552433136353a20696e76616c696420696e7465726661636520696400000000604482015260640160405180910390fd5b6001600160e01b0319165f908152602081905260409020805460ff19166001179055565b80516001600160a01b03811681146200016a575f80fd5b919050565b5f806040838503121562000181575f80fd5b6200018c8362000153565b91506200019c6020840162000153565b90509250929050565b6080516126d1620001cc5f395f81816101b60152818161038c0152610ea901526126d15ff3fe608060405234801561000f575f80fd5b50600436106100cf575f3560e01c80638c16b3ba1161007d578063edb219c011610058578063edb219c0146101eb578063f430500a14610281578063f6ccaad414610294575f80fd5b80638c16b3ba1461019e5780639378ca56146101b1578063a6d7fdf2146101d8575f80fd5b80634bc66f32116100ad5780634bc66f32146101555780634dd4ee5f146101755780634f8b4ae714610196575f80fd5b806301ffc9a7146100d3578063090f3f50146100fb5780634501409514610140575b5f80fd5b6100e66100e1366004611f2c565b61029c565b60405190151581526020015b60405180910390f35b60015461011b9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100f2565b61015361014e366004611f8c565b610323565b005b60025461011b9073ffffffffffffffffffffffffffffffffffffffff1681565b610188610183366004612196565b610337565b6040519081526020016100f2565b610153610462565b6101536101ac366004612196565b610486565b61011b7f000000000000000000000000000000000000000000000000000000000000000081565b6101536101e6366004612218565b610633565b6102486101f9366004611f8c565b60036020525f908152604090205473ffffffffffffffffffffffffffffffffffffffff8116907401000000000000000000000000000000000000000090046bffffffffffffffffffffffff1682565b6040805173ffffffffffffffffffffffffffffffffffffffff90931683526bffffffffffffffffffffffff9091166020830152016100f2565b61015361028f366004612287565b6107b8565b610153610a19565b5f7f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316148061031d57507fffffffff0000000000000000000000000000000000000000000000000000000082165f9081526020819052604090205460ff165b92915050565b61032b610a29565b61033481610a7a565b50565b6040517fbb141cf40000000000000000000000000000000000000000000000000000000081526bffffffffffffffffffffffff841660048201525f90819073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063bb141cf4906024016040805180830381865afa1580156103d0573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103f491906123c2565b90505f610405825f01518887610af0565b90506104198160600151600c5f1b86610c5b565b602001519250825f03610458576040517fac34915700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050949350505050565b61046a610a29565b610472610d52565b61047b5f610a7a565b6104845f610da3565b565b73ffffffffffffffffffffffffffffffffffffffff84165f908152600360205260409020547401000000000000000000000000000000000000000090046bffffffffffffffffffffffff16801561052d57806bffffffffffffffffffffffff16846bffffffffffffffffffffffff16101561052d576040517f011d308100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8086165f90815260036020526040902054168061058b576040517f17e740e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f61059882878787610337565b6040517f330a73550000000000000000000000000000000000000000000000000000000081526bffffffffffffffffffffffff881660048201526024810182905290915073ffffffffffffffffffffffffffffffffffffffff88169063330a7355906044015f604051808303815f87803b158015610614575f80fd5b505af1158015610626573d5f803e3d5ffd5b5050505050505050505050565b61063b610a29565b5f5b818110156107b3575f83838381811061065857610658612401565b90506040020180360381019061066e919061242e565b60208082015173ffffffffffffffffffffffffffffffffffffffff9081165f90815260039092526040909120549192501615610714576020818101805173ffffffffffffffffffffffffffffffffffffffff9081165f908152600390935260409283902054915183517f729d6d9c000000000000000000000000000000000000000000000000000000008152928216600484015216602482015290519081900360440190fd5b80516020808301805173ffffffffffffffffffffffffffffffffffffffff9081165f9081526003909352604080842080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169583169590951790945590518451935190821693909116917fc662d74d8469d456352095edb1ed6a69f64c66ace9fa3598de77edfccfad12a291a3506107ac8161248e565b905061063d565b505050565b73ffffffffffffffffffffffffffffffffffffffff83165f908152600360205260408120547401000000000000000000000000000000000000000090046bffffffffffffffffffffffff1690811561086057816bffffffffffffffffffffffff16846bffffffffffffffffffffffff161015610860576040517f011d308100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5073ffffffffffffffffffffffffffffffffffffffff8085165f9081526003602052604090205416806108bf576040517f17e740e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f805f806108ce858989610e30565b604080517fc473071e0000000000000000000000000000000000000000000000000000000081526bffffffffffffffffffffffff8e166004820152602481018690526044810185905260648101849052825164ffffffffff908116608483015260208401511660a4820152908201517affffffffffffffffffffffffffffffffffffffffffffffffffffff1660c48201529397509195509350915073ffffffffffffffffffffffffffffffffffffffff8a169063c473071e9060e4015f604051808303815f87803b1580156109a1575f80fd5b505af11580156109b3573d5f803e3d5ffd5b50505073ffffffffffffffffffffffffffffffffffffffff998a165f90815260036020526040902080546bffffffffffffffffffffffff909a16740100000000000000000000000000000000000000000299909a16989098179098555050505050505050565b610a21610d52565b6104846110c7565b60025473ffffffffffffffffffffffffffffffffffffffff163314610484576040517f1c0be90a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff838116918217909255600254604051919216907f162998b90abc2507f3953aa797827b03a14c42dbd9a35f09feaf02e0d592773a905f90a350565b6040805160a0810182525f808252602082018190529181018290526060810182905260808101919091525f825167ffffffffffffffff811115610b3557610b35611fc2565b604051908082528060200260200182016040528015610b7957816020015b604080518082019091525f8082526020820152815260200190600190039081610b535790505b5090505f5b8351811015610bfe57610bd0848281518110610b9c57610b9c612401565b60200260200101516040805180820182525f8082526020918201528151808301909252825182529182019181019190915290565b828281518110610be257610be2612401565b602002602001018190525080610bf79061248e565b9050610b7e565b506040517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606086901b166020820152610c52906034016040516020818303038152906040528051906020012086836110f8565b95945050505050565b604080518082019091525f80825260208201525f825167ffffffffffffffff811115610c8957610c89611fc2565b604051908082528060200260200182016040528015610ccd57816020015b604080518082019091525f8082526020820152815260200190600190039081610ca75790505b5090505f5b8351811015610d1e57610cf0848281518110610b9c57610b9c612401565b828281518110610d0257610d02612401565b602002602001018190525080610d179061248e565b9050610cd2565b50610c5284604051602001610d3591815260200190565b604051602081830303815290604052805190602001208683611267565b60015473ffffffffffffffffffffffffffffffffffffffff163314610484576040517ff5c49e6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60025460405173ffffffffffffffffffffffffffffffffffffffff8084169216907f31b6c5a04b069b6ec1b3cef44c4e7c1eadd721349cda9823d0b1877b3551cdc6905f90a3600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b604080516060810182525f808252602082018190529181018290528190819050604080516060810182525f8082526020820181905281830181905291517fbb141cf40000000000000000000000000000000000000000000000000000000081526bffffffffffffffffffffffff881660048201529091907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063bb141cf4906024016040805180830381865afa158015610f02573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f2691906123c2565b90505f610f3a825f01518a895f0151610af0565b9050610f52816060015160025f1b8960200151610c5b565b602001519550610f6e816060015160095f1b8960400151610c5b565b602001519450610f8a816060015160085f1b8960600151610c5b565b6020015193505f610fa7826060015160065f1b8a60800151610c5b565b6020015190505f610fc4836060015160075f1b8b60a00151610c5b565b60209081015164ffffffffff602885901c81169288019290925292168552507affffffffffffffffffffffffffffffffffffffffffffffffffffff1660408401525f86900361103f576040517fac34915700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826020015164ffffffffff165f03611083576040517fac34915700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b845f036110bc576040517fac34915700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505093509350935093565b600180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905561048433610da3565b6040805160a0810182525f808252602082018190529181018290526060810182905260808101919091525f61114f848660405160200161113a91815260200190565b604051602081830303815290604052856112f0565b6040805160a0810182525f8082526020820181905291810182905260608101829052608081019190915290915081515f0361118d5791506112609050565b5f6111c66111c1846040805180820182525f8082526020918201528151808301909252825182529182019181019190915290565b611714565b905080516004146111d5575f80fd5b6001825280516111fc9082905f906111ef576111ef612401565b6020026020010151611824565b6020830152805161121a90829060019081106111ef576111ef612401565b6040830152805161123890829060029081106111ef576111ef612401565b6060830152805161125690829060039081106111ef576111ef612401565b6080830152509150505b9392505050565b604080518082019091525f80825260208201525f611292848660405160200161113a91815260200190565b604080518082019091525f8082526020820152909150815115610c5257600181526040805180820182525f808252602091820152815180830190925283518252808401908201526112e290611824565b602082015295945050505050565b60605f6112fd845f61186f565b90505f80606061131e60405180604001604052805f81526020015f81525090565b86515f0361136c577f56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b4218914611351575f80fd5b5050604080515f815260208101909152935061126092505050565b5f5b875181101561170757801580156113ad57506113a988828151811061139557611395612401565b602002602001015160208101519051902090565b8a14155b156113b6575f80fd5b80158015906113e657506113e28882815181106113d5576113d5612401565b6020026020010151611a3c565b8414155b156113ef575f80fd5b61141188828151811061140457611404612401565b6020026020010151611714565b925082516002036115b5575f6060611449611444865f8151811061143757611437612401565b6020026020010151611a94565b611b0f565b90925090505f61145a888a84611ba2565b905061146681896124c5565b975081518110156114c75760018b5161147f91906124d8565b84101561148a575f80fd5b5f5b6040519080825280601f01601f1916602001820160405280156114b6576020820181803683370190505b509950505050505050505050611260565b821561152b5760018b516114db91906124d8565b8410156114e6575f80fd5b88518810156114f5575f61148c565b8560018151811061150857611508612401565b6020026020010151945061151b85611a94565b9950505050505050505050611260565b60018b5161153991906124d8565b8403611543575f80fd5b6115668660018151811061155957611559612401565b6020026020010151611c5c565b6115945761158d8660018151811061158057611580612401565b6020026020010151611c93565b96506115ad565b6115aa8660018151811061139557611395612401565b96505b5050506116f5565b82516011036116f557855185146116ba575f8686815181106115d9576115d9612401565b016020015160f81c90506115ee6001876124c5565b955060108160ff16106115ff575f80fd5b611624848260ff168151811061161757611617612401565b6020026020010151611ca9565b1561165e576001895161163791906124d8565b8214611641575f80fd5b5050604080515f8152602081019091529550611260945050505050565b611676848260ff168151811061155957611559612401565b61169957611692848260ff168151811061158057611580612401565b94506116b4565b6116b1848260ff168151811061139557611395612401565b94505b506116f5565b600188516116c891906124d8565b81146116d2575f80fd5b6116e88360108151811061143757611437612401565b9650505050505050611260565b806116ff8161248e565b91505061136e565b5050505050509392505050565b606061171f82611c5c565b611727575f80fd5b5f61173183611cc9565b90505f8167ffffffffffffffff81111561174d5761174d611fc2565b60405190808252806020026020018201604052801561179157816020015b604080518082019091525f808252602082015281526020019060019003908161176b5790505b5090505f6117a28560200151611d49565b85602001516117b191906124c5565b90505f805b84811015611819576117c783611dc2565b91506040518060400160405280838152602001848152508482815181106117f0576117f0612401565b602090810291909101015261180582846124c5565b9250806118118161248e565b9150506117b6565b509195945050505050565b80515f901580159061183857508151602110155b611840575f80fd5b5f8061184b84611e6a565b8151919350915060208210156118675760208290036101000a90045b949350505050565b60605f83511161187d575f80fd5b5f8351600261188c91906124eb565b90508083111561189a575f80fd5b6118a483826124d8565b90508067ffffffffffffffff8111156118bf576118bf611fc2565b6040519080825280601f01601f1916602001820160405280156118e9576020820181803683370190505b5091505f835b6118f983866124c5565b811015611a235761190b60028261252f565b5f0361198d5760048661191f600284612542565b8151811061192f5761192f612401565b602001015160f81c60f81b60f81c60ff16901c600f1660f81b84838151811061195a5761195a612401565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a905350611a04565b5f8661199a600284612542565b815181106119aa576119aa612401565b602001015160f81c60f81b60f81c60ff16901c600f1660f81b8483815181106119d5576119d5612401565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505b611a0f6001836124c5565b9150611a1c6001826124c5565b90506118ef565b5082518114611a3457611a34612555565b505092915050565b5f6020825f01511015611a575760208201518251902061031d565b602082015182519020604051602001611a7291815260200190565b604051602081830303815290604052805190602001209050919050565b919050565b8051606090611aa1575f80fd5b5f80611aac84611e6a565b915091505f8167ffffffffffffffff811115611aca57611aca611fc2565b6040519080825280601f01601f191660200182016040528015611af4576020820181803683370190505b50905060208101611b06848285611eac565b50949350505050565b5f60605f835111611b1e575f80fd5b5f6004845f81518110611b3357611b33612401565b60209101015160f81c901c600f1690505f818103611b5657505f92506002611b8c565b81600103611b6957505f92506001611b8c565b81600203611b7d5750600192506002611b8c565b816003036100cf575060019250825b83611b97868361186f565b935093505050915091565b5f805b8351611bb186836124c5565b108015611bbe5750825181105b1561186757828181518110611bd557611bd5612401565b01602001517fff000000000000000000000000000000000000000000000000000000000000001684611c0787846124c5565b81518110611c1757611c17612401565b01602001517fff000000000000000000000000000000000000000000000000000000000000001614611c4a579050611260565b80611c548161248e565b915050611ba5565b80515f908103611c6d57505f919050565b602082015180515f1a9060c0821015611c8957505f9392505050565b5060019392505050565b5f805f611c9f84611e6a565b9020949350505050565b80515f90600114611cbb57505f919050565b5060200151515f1a60801490565b80515f908103611cda57505f919050565b5f80611ce98460200151611d49565b8460200151611cf891906124c5565b90505f845f01518560200151611d0e91906124c5565b90505b80821015611d4057611d2282611dc2565b611d2c90836124c5565b915082611d388161248e565b935050611d11565b50909392505050565b80515f90811a6080811015611d6057505f92915050565b60b8811080611d7b575060c08110801590611d7b575060f881105b15611d895750600192915050565b60c0811015611db657611d9e600160b8612582565b611dab9060ff16826124d8565b6112609060016124c5565b611d9e600160f8612582565b80515f908190811a6080811015611ddc5760019150611e63565b60b8811015611e0257611df06080826124d8565b611dfb9060016124c5565b9150611e63565b60c0811015611e2f5760b78103600185019450806020036101000a85510460018201810193505050611e63565b60f8811015611e4357611df060c0826124d8565b60f78103600185019450806020036101000a855104600182018101935050505b5092915050565b5f805f611e7a8460200151611d49565b90505f818560200151611e8d91906124c5565b90505f82865f0151611e9f91906124d8565b9196919550909350505050565b805f03611eb857505050565b60208110611ef05782518252611ecf6020846124c5565b9250611edc6020836124c5565b9150611ee96020826124d8565b9050611eb8565b80156107b3575f6001611f048360206124d8565b611f10906101006126b9565b611f1a91906124d8565b84518451821691191617835250505050565b5f60208284031215611f3c575f80fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114611260575f80fd5b73ffffffffffffffffffffffffffffffffffffffff81168114610334575f80fd5b5f60208284031215611f9c575f80fd5b813561126081611f6b565b80356bffffffffffffffffffffffff81168114611a8f575f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b60405160c0810167ffffffffffffffff8111828210171561201257612012611fc2565b60405290565b6040805190810167ffffffffffffffff8111828210171561201257612012611fc2565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561208257612082611fc2565b604052919050565b5f601f838184011261209a575f80fd5b8235602067ffffffffffffffff808311156120b7576120b7611fc2565b8260051b6120c683820161203b565b93845286810183019383810190898611156120df575f80fd5b84890192505b85831015612189578235848111156120fc575f8081fd5b8901603f81018b1361210d575f8081fd5b8581013560408682111561212357612123611fc2565b612152887fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08c8501160161203b565b8281528d82848601011115612166575f8081fd5b828285018a8301375f9281018901929092525083525091840191908401906120e5565b9998505050505050505050565b5f805f80608085870312156121a9575f80fd5b84356121b481611f6b565b93506121c260208601611fa7565b9250604085013567ffffffffffffffff808211156121de575f80fd5b6121ea8883890161208a565b935060608701359150808211156121ff575f80fd5b5061220c8782880161208a565b91505092959194509250565b5f8060208385031215612229575f80fd5b823567ffffffffffffffff80821115612240575f80fd5b818501915085601f830112612253575f80fd5b813581811115612261575f80fd5b8660208260061b8501011115612275575f80fd5b60209290920196919550909350505050565b5f805f60608486031215612299575f80fd5b83356122a481611f6b565b92506122b260208501611fa7565b9150604084013567ffffffffffffffff808211156122ce575f80fd5b9085019060c082880312156122e1575f80fd5b6122e9611fef565b8235828111156122f7575f80fd5b6123038982860161208a565b825250602083013582811115612317575f80fd5b6123238982860161208a565b60208301525060408301358281111561233a575f80fd5b6123468982860161208a565b60408301525060608301358281111561235d575f80fd5b6123698982860161208a565b606083015250608083013582811115612380575f80fd5b61238c8982860161208a565b60808301525060a0830135828111156123a3575f80fd5b6123af8982860161208a565b60a0830152508093505050509250925092565b5f604082840312156123d2575f80fd5b6123da612018565b82518152602083015164ffffffffff811681146123f5575f80fd5b60208201529392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f6040828403121561243e575f80fd5b612446612018565b823561245181611f6b565b815260208301356123f581611f6b565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036124be576124be612461565b5060010190565b8082018082111561031d5761031d612461565b8181038181111561031d5761031d612461565b808202811582820484141761031d5761031d612461565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f8261253d5761253d612502565b500690565b5f8261255057612550612502565b500490565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52600160045260245ffd5b60ff828116828216039081111561031d5761031d612461565b600181815b808511156125f457817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048211156125da576125da612461565b808516156125e757918102915b93841c93908002906125a0565b509250929050565b5f8261260a5750600161031d565b8161261657505f61031d565b816001811461262c576002811461263657612652565b600191505061031d565b60ff84111561264757612647612461565b50506001821b61031d565b5060208310610133831016604e8410600b8410161715612675575081810a61031d565b61267f838361259b565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048211156126b1576126b1612461565b029392505050565b5f61126083836125fc56fea164736f6c6343000814000a000000000000000000000000ed403d48e2bc946438b5686aa1ad65056ccf951200000000000000000000000031562ae726afebe25417df01bedc72ef489f45b3
Deployed Bytecode
0x608060405234801561000f575f80fd5b50600436106100cf575f3560e01c80638c16b3ba1161007d578063edb219c011610058578063edb219c0146101eb578063f430500a14610281578063f6ccaad414610294575f80fd5b80638c16b3ba1461019e5780639378ca56146101b1578063a6d7fdf2146101d8575f80fd5b80634bc66f32116100ad5780634bc66f32146101555780634dd4ee5f146101755780634f8b4ae714610196575f80fd5b806301ffc9a7146100d3578063090f3f50146100fb5780634501409514610140575b5f80fd5b6100e66100e1366004611f2c565b61029c565b60405190151581526020015b60405180910390f35b60015461011b9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100f2565b61015361014e366004611f8c565b610323565b005b60025461011b9073ffffffffffffffffffffffffffffffffffffffff1681565b610188610183366004612196565b610337565b6040519081526020016100f2565b610153610462565b6101536101ac366004612196565b610486565b61011b7f000000000000000000000000ed403d48e2bc946438b5686aa1ad65056ccf951281565b6101536101e6366004612218565b610633565b6102486101f9366004611f8c565b60036020525f908152604090205473ffffffffffffffffffffffffffffffffffffffff8116907401000000000000000000000000000000000000000090046bffffffffffffffffffffffff1682565b6040805173ffffffffffffffffffffffffffffffffffffffff90931683526bffffffffffffffffffffffff9091166020830152016100f2565b61015361028f366004612287565b6107b8565b610153610a19565b5f7f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316148061031d57507fffffffff0000000000000000000000000000000000000000000000000000000082165f9081526020819052604090205460ff165b92915050565b61032b610a29565b61033481610a7a565b50565b6040517fbb141cf40000000000000000000000000000000000000000000000000000000081526bffffffffffffffffffffffff841660048201525f90819073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000ed403d48e2bc946438b5686aa1ad65056ccf9512169063bb141cf4906024016040805180830381865afa1580156103d0573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103f491906123c2565b90505f610405825f01518887610af0565b90506104198160600151600c5f1b86610c5b565b602001519250825f03610458576040517fac34915700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050949350505050565b61046a610a29565b610472610d52565b61047b5f610a7a565b6104845f610da3565b565b73ffffffffffffffffffffffffffffffffffffffff84165f908152600360205260409020547401000000000000000000000000000000000000000090046bffffffffffffffffffffffff16801561052d57806bffffffffffffffffffffffff16846bffffffffffffffffffffffff16101561052d576040517f011d308100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8086165f90815260036020526040902054168061058b576040517f17e740e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f61059882878787610337565b6040517f330a73550000000000000000000000000000000000000000000000000000000081526bffffffffffffffffffffffff881660048201526024810182905290915073ffffffffffffffffffffffffffffffffffffffff88169063330a7355906044015f604051808303815f87803b158015610614575f80fd5b505af1158015610626573d5f803e3d5ffd5b5050505050505050505050565b61063b610a29565b5f5b818110156107b3575f83838381811061065857610658612401565b90506040020180360381019061066e919061242e565b60208082015173ffffffffffffffffffffffffffffffffffffffff9081165f90815260039092526040909120549192501615610714576020818101805173ffffffffffffffffffffffffffffffffffffffff9081165f908152600390935260409283902054915183517f729d6d9c000000000000000000000000000000000000000000000000000000008152928216600484015216602482015290519081900360440190fd5b80516020808301805173ffffffffffffffffffffffffffffffffffffffff9081165f9081526003909352604080842080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169583169590951790945590518451935190821693909116917fc662d74d8469d456352095edb1ed6a69f64c66ace9fa3598de77edfccfad12a291a3506107ac8161248e565b905061063d565b505050565b73ffffffffffffffffffffffffffffffffffffffff83165f908152600360205260408120547401000000000000000000000000000000000000000090046bffffffffffffffffffffffff1690811561086057816bffffffffffffffffffffffff16846bffffffffffffffffffffffff161015610860576040517f011d308100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5073ffffffffffffffffffffffffffffffffffffffff8085165f9081526003602052604090205416806108bf576040517f17e740e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f805f806108ce858989610e30565b604080517fc473071e0000000000000000000000000000000000000000000000000000000081526bffffffffffffffffffffffff8e166004820152602481018690526044810185905260648101849052825164ffffffffff908116608483015260208401511660a4820152908201517affffffffffffffffffffffffffffffffffffffffffffffffffffff1660c48201529397509195509350915073ffffffffffffffffffffffffffffffffffffffff8a169063c473071e9060e4015f604051808303815f87803b1580156109a1575f80fd5b505af11580156109b3573d5f803e3d5ffd5b50505073ffffffffffffffffffffffffffffffffffffffff998a165f90815260036020526040902080546bffffffffffffffffffffffff909a16740100000000000000000000000000000000000000000299909a16989098179098555050505050505050565b610a21610d52565b6104846110c7565b60025473ffffffffffffffffffffffffffffffffffffffff163314610484576040517f1c0be90a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff838116918217909255600254604051919216907f162998b90abc2507f3953aa797827b03a14c42dbd9a35f09feaf02e0d592773a905f90a350565b6040805160a0810182525f808252602082018190529181018290526060810182905260808101919091525f825167ffffffffffffffff811115610b3557610b35611fc2565b604051908082528060200260200182016040528015610b7957816020015b604080518082019091525f8082526020820152815260200190600190039081610b535790505b5090505f5b8351811015610bfe57610bd0848281518110610b9c57610b9c612401565b60200260200101516040805180820182525f8082526020918201528151808301909252825182529182019181019190915290565b828281518110610be257610be2612401565b602002602001018190525080610bf79061248e565b9050610b7e565b506040517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606086901b166020820152610c52906034016040516020818303038152906040528051906020012086836110f8565b95945050505050565b604080518082019091525f80825260208201525f825167ffffffffffffffff811115610c8957610c89611fc2565b604051908082528060200260200182016040528015610ccd57816020015b604080518082019091525f8082526020820152815260200190600190039081610ca75790505b5090505f5b8351811015610d1e57610cf0848281518110610b9c57610b9c612401565b828281518110610d0257610d02612401565b602002602001018190525080610d179061248e565b9050610cd2565b50610c5284604051602001610d3591815260200190565b604051602081830303815290604052805190602001208683611267565b60015473ffffffffffffffffffffffffffffffffffffffff163314610484576040517ff5c49e6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60025460405173ffffffffffffffffffffffffffffffffffffffff8084169216907f31b6c5a04b069b6ec1b3cef44c4e7c1eadd721349cda9823d0b1877b3551cdc6905f90a3600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b604080516060810182525f808252602082018190529181018290528190819050604080516060810182525f8082526020820181905281830181905291517fbb141cf40000000000000000000000000000000000000000000000000000000081526bffffffffffffffffffffffff881660048201529091907f000000000000000000000000ed403d48e2bc946438b5686aa1ad65056ccf951273ffffffffffffffffffffffffffffffffffffffff169063bb141cf4906024016040805180830381865afa158015610f02573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f2691906123c2565b90505f610f3a825f01518a895f0151610af0565b9050610f52816060015160025f1b8960200151610c5b565b602001519550610f6e816060015160095f1b8960400151610c5b565b602001519450610f8a816060015160085f1b8960600151610c5b565b6020015193505f610fa7826060015160065f1b8a60800151610c5b565b6020015190505f610fc4836060015160075f1b8b60a00151610c5b565b60209081015164ffffffffff602885901c81169288019290925292168552507affffffffffffffffffffffffffffffffffffffffffffffffffffff1660408401525f86900361103f576040517fac34915700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826020015164ffffffffff165f03611083576040517fac34915700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b845f036110bc576040517fac34915700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505093509350935093565b600180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905561048433610da3565b6040805160a0810182525f808252602082018190529181018290526060810182905260808101919091525f61114f848660405160200161113a91815260200190565b604051602081830303815290604052856112f0565b6040805160a0810182525f8082526020820181905291810182905260608101829052608081019190915290915081515f0361118d5791506112609050565b5f6111c66111c1846040805180820182525f8082526020918201528151808301909252825182529182019181019190915290565b611714565b905080516004146111d5575f80fd5b6001825280516111fc9082905f906111ef576111ef612401565b6020026020010151611824565b6020830152805161121a90829060019081106111ef576111ef612401565b6040830152805161123890829060029081106111ef576111ef612401565b6060830152805161125690829060039081106111ef576111ef612401565b6080830152509150505b9392505050565b604080518082019091525f80825260208201525f611292848660405160200161113a91815260200190565b604080518082019091525f8082526020820152909150815115610c5257600181526040805180820182525f808252602091820152815180830190925283518252808401908201526112e290611824565b602082015295945050505050565b60605f6112fd845f61186f565b90505f80606061131e60405180604001604052805f81526020015f81525090565b86515f0361136c577f56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b4218914611351575f80fd5b5050604080515f815260208101909152935061126092505050565b5f5b875181101561170757801580156113ad57506113a988828151811061139557611395612401565b602002602001015160208101519051902090565b8a14155b156113b6575f80fd5b80158015906113e657506113e28882815181106113d5576113d5612401565b6020026020010151611a3c565b8414155b156113ef575f80fd5b61141188828151811061140457611404612401565b6020026020010151611714565b925082516002036115b5575f6060611449611444865f8151811061143757611437612401565b6020026020010151611a94565b611b0f565b90925090505f61145a888a84611ba2565b905061146681896124c5565b975081518110156114c75760018b5161147f91906124d8565b84101561148a575f80fd5b5f5b6040519080825280601f01601f1916602001820160405280156114b6576020820181803683370190505b509950505050505050505050611260565b821561152b5760018b516114db91906124d8565b8410156114e6575f80fd5b88518810156114f5575f61148c565b8560018151811061150857611508612401565b6020026020010151945061151b85611a94565b9950505050505050505050611260565b60018b5161153991906124d8565b8403611543575f80fd5b6115668660018151811061155957611559612401565b6020026020010151611c5c565b6115945761158d8660018151811061158057611580612401565b6020026020010151611c93565b96506115ad565b6115aa8660018151811061139557611395612401565b96505b5050506116f5565b82516011036116f557855185146116ba575f8686815181106115d9576115d9612401565b016020015160f81c90506115ee6001876124c5565b955060108160ff16106115ff575f80fd5b611624848260ff168151811061161757611617612401565b6020026020010151611ca9565b1561165e576001895161163791906124d8565b8214611641575f80fd5b5050604080515f8152602081019091529550611260945050505050565b611676848260ff168151811061155957611559612401565b61169957611692848260ff168151811061158057611580612401565b94506116b4565b6116b1848260ff168151811061139557611395612401565b94505b506116f5565b600188516116c891906124d8565b81146116d2575f80fd5b6116e88360108151811061143757611437612401565b9650505050505050611260565b806116ff8161248e565b91505061136e565b5050505050509392505050565b606061171f82611c5c565b611727575f80fd5b5f61173183611cc9565b90505f8167ffffffffffffffff81111561174d5761174d611fc2565b60405190808252806020026020018201604052801561179157816020015b604080518082019091525f808252602082015281526020019060019003908161176b5790505b5090505f6117a28560200151611d49565b85602001516117b191906124c5565b90505f805b84811015611819576117c783611dc2565b91506040518060400160405280838152602001848152508482815181106117f0576117f0612401565b602090810291909101015261180582846124c5565b9250806118118161248e565b9150506117b6565b509195945050505050565b80515f901580159061183857508151602110155b611840575f80fd5b5f8061184b84611e6a565b8151919350915060208210156118675760208290036101000a90045b949350505050565b60605f83511161187d575f80fd5b5f8351600261188c91906124eb565b90508083111561189a575f80fd5b6118a483826124d8565b90508067ffffffffffffffff8111156118bf576118bf611fc2565b6040519080825280601f01601f1916602001820160405280156118e9576020820181803683370190505b5091505f835b6118f983866124c5565b811015611a235761190b60028261252f565b5f0361198d5760048661191f600284612542565b8151811061192f5761192f612401565b602001015160f81c60f81b60f81c60ff16901c600f1660f81b84838151811061195a5761195a612401565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a905350611a04565b5f8661199a600284612542565b815181106119aa576119aa612401565b602001015160f81c60f81b60f81c60ff16901c600f1660f81b8483815181106119d5576119d5612401565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505b611a0f6001836124c5565b9150611a1c6001826124c5565b90506118ef565b5082518114611a3457611a34612555565b505092915050565b5f6020825f01511015611a575760208201518251902061031d565b602082015182519020604051602001611a7291815260200190565b604051602081830303815290604052805190602001209050919050565b919050565b8051606090611aa1575f80fd5b5f80611aac84611e6a565b915091505f8167ffffffffffffffff811115611aca57611aca611fc2565b6040519080825280601f01601f191660200182016040528015611af4576020820181803683370190505b50905060208101611b06848285611eac565b50949350505050565b5f60605f835111611b1e575f80fd5b5f6004845f81518110611b3357611b33612401565b60209101015160f81c901c600f1690505f818103611b5657505f92506002611b8c565b81600103611b6957505f92506001611b8c565b81600203611b7d5750600192506002611b8c565b816003036100cf575060019250825b83611b97868361186f565b935093505050915091565b5f805b8351611bb186836124c5565b108015611bbe5750825181105b1561186757828181518110611bd557611bd5612401565b01602001517fff000000000000000000000000000000000000000000000000000000000000001684611c0787846124c5565b81518110611c1757611c17612401565b01602001517fff000000000000000000000000000000000000000000000000000000000000001614611c4a579050611260565b80611c548161248e565b915050611ba5565b80515f908103611c6d57505f919050565b602082015180515f1a9060c0821015611c8957505f9392505050565b5060019392505050565b5f805f611c9f84611e6a565b9020949350505050565b80515f90600114611cbb57505f919050565b5060200151515f1a60801490565b80515f908103611cda57505f919050565b5f80611ce98460200151611d49565b8460200151611cf891906124c5565b90505f845f01518560200151611d0e91906124c5565b90505b80821015611d4057611d2282611dc2565b611d2c90836124c5565b915082611d388161248e565b935050611d11565b50909392505050565b80515f90811a6080811015611d6057505f92915050565b60b8811080611d7b575060c08110801590611d7b575060f881105b15611d895750600192915050565b60c0811015611db657611d9e600160b8612582565b611dab9060ff16826124d8565b6112609060016124c5565b611d9e600160f8612582565b80515f908190811a6080811015611ddc5760019150611e63565b60b8811015611e0257611df06080826124d8565b611dfb9060016124c5565b9150611e63565b60c0811015611e2f5760b78103600185019450806020036101000a85510460018201810193505050611e63565b60f8811015611e4357611df060c0826124d8565b60f78103600185019450806020036101000a855104600182018101935050505b5092915050565b5f805f611e7a8460200151611d49565b90505f818560200151611e8d91906124c5565b90505f82865f0151611e9f91906124d8565b9196919550909350505050565b805f03611eb857505050565b60208110611ef05782518252611ecf6020846124c5565b9250611edc6020836124c5565b9150611ee96020826124d8565b9050611eb8565b80156107b3575f6001611f048360206124d8565b611f10906101006126b9565b611f1a91906124d8565b84518451821691191617835250505050565b5f60208284031215611f3c575f80fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114611260575f80fd5b73ffffffffffffffffffffffffffffffffffffffff81168114610334575f80fd5b5f60208284031215611f9c575f80fd5b813561126081611f6b565b80356bffffffffffffffffffffffff81168114611a8f575f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b60405160c0810167ffffffffffffffff8111828210171561201257612012611fc2565b60405290565b6040805190810167ffffffffffffffff8111828210171561201257612012611fc2565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561208257612082611fc2565b604052919050565b5f601f838184011261209a575f80fd5b8235602067ffffffffffffffff808311156120b7576120b7611fc2565b8260051b6120c683820161203b565b93845286810183019383810190898611156120df575f80fd5b84890192505b85831015612189578235848111156120fc575f8081fd5b8901603f81018b1361210d575f8081fd5b8581013560408682111561212357612123611fc2565b612152887fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08c8501160161203b565b8281528d82848601011115612166575f8081fd5b828285018a8301375f9281018901929092525083525091840191908401906120e5565b9998505050505050505050565b5f805f80608085870312156121a9575f80fd5b84356121b481611f6b565b93506121c260208601611fa7565b9250604085013567ffffffffffffffff808211156121de575f80fd5b6121ea8883890161208a565b935060608701359150808211156121ff575f80fd5b5061220c8782880161208a565b91505092959194509250565b5f8060208385031215612229575f80fd5b823567ffffffffffffffff80821115612240575f80fd5b818501915085601f830112612253575f80fd5b813581811115612261575f80fd5b8660208260061b8501011115612275575f80fd5b60209290920196919550909350505050565b5f805f60608486031215612299575f80fd5b83356122a481611f6b565b92506122b260208501611fa7565b9150604084013567ffffffffffffffff808211156122ce575f80fd5b9085019060c082880312156122e1575f80fd5b6122e9611fef565b8235828111156122f7575f80fd5b6123038982860161208a565b825250602083013582811115612317575f80fd5b6123238982860161208a565b60208301525060408301358281111561233a575f80fd5b6123468982860161208a565b60408301525060608301358281111561235d575f80fd5b6123698982860161208a565b606083015250608083013582811115612380575f80fd5b61238c8982860161208a565b60808301525060a0830135828111156123a3575f80fd5b6123af8982860161208a565b60a0830152508093505050509250925092565b5f604082840312156123d2575f80fd5b6123da612018565b82518152602083015164ffffffffff811681146123f5575f80fd5b60208201529392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f6040828403121561243e575f80fd5b612446612018565b823561245181611f6b565b815260208301356123f581611f6b565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036124be576124be612461565b5060010190565b8082018082111561031d5761031d612461565b8181038181111561031d5761031d612461565b808202811582820484141761031d5761031d612461565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f8261253d5761253d612502565b500690565b5f8261255057612550612502565b500490565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52600160045260245ffd5b60ff828116828216039081111561031d5761031d612461565b600181815b808511156125f457817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048211156125da576125da612461565b808516156125e757918102915b93841c93908002906125a0565b509250929050565b5f8261260a5750600161031d565b8161261657505f61031d565b816001811461262c576002811461263657612652565b600191505061031d565b60ff84111561264757612647612461565b50506001821b61031d565b5060208310610133831016604e8410600b8410161715612675575081810a61031d565b61267f838361259b565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048211156126b1576126b1612461565b029392505050565b5f61126083836125fc56fea164736f6c6343000814000a
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000ed403d48e2bc946438b5686aa1ad65056ccf951200000000000000000000000031562ae726afebe25417df01bedc72ef489f45b3
-----Decoded View---------------
Arg [0] : _stateRootOracle (address): 0xeD403d48e2bC946438B5686AA1AD65056Ccf9512
Arg [1] : _timelockAddress (address): 0x31562ae726AFEBe25417df01bEdC72EF489F45b3
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000ed403d48e2bc946438b5686aa1ad65056ccf9512
Arg [1] : 00000000000000000000000031562ae726afebe25417df01bedc72ef489f45b3
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in FRAX
0
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.