Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
SystemConfig
Compiler Version
v0.8.15+commit.e14f2714
Optimization Enabled:
Yes with 999999 runs
Other Settings:
london EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
// Contracts
import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
// Libraries
import { Storage } from "src/libraries/Storage.sol";
import { Constants } from "src/libraries/Constants.sol";
import { GasPayingToken, IGasToken } from "src/libraries/GasPayingToken.sol";
// Interfaces
import { ISemver } from "src/universal/interfaces/ISemver.sol";
import { IOptimismPortal } from "src/L1/interfaces/IOptimismPortal.sol";
import { IResourceMetering } from "src/L1/interfaces/IResourceMetering.sol";
/// @custom:proxied true
/// @title SystemConfig
/// @notice The SystemConfig contract is used to manage configuration of an Optimism network.
/// All configuration is stored on L1 and picked up by L2 as part of the derviation of
/// the L2 chain.
contract SystemConfig is OwnableUpgradeable, ISemver, IGasToken {
/// @notice Enum representing different types of updates.
/// @custom:value BATCHER Represents an update to the batcher hash.
/// @custom:value FEE_SCALARS Represents an update to l1 data fee scalars.
/// @custom:value GAS_LIMIT Represents an update to gas limit on L2.
/// @custom:value UNSAFE_BLOCK_SIGNER Represents an update to the signer key for unsafe
/// block distrubution.
enum UpdateType {
BATCHER,
FEE_SCALARS,
GAS_LIMIT,
UNSAFE_BLOCK_SIGNER,
EIP_1559_PARAMS
}
/// @notice Struct representing the addresses of L1 system contracts. These should be the
/// contracts that users interact with (not implementations for proxied contracts)
/// and are network specific.
struct Addresses {
address l1CrossDomainMessenger;
address l1ERC721Bridge;
address l1StandardBridge;
address disputeGameFactory;
address optimismPortal;
address optimismMintableERC20Factory;
address gasPayingToken;
}
/// @notice Version identifier, used for upgrades.
uint256 public constant VERSION = 0;
/// @notice Storage slot that the unsafe block signer is stored at.
/// Storing it at this deterministic storage slot allows for decoupling the storage
/// layout from the way that `solc` lays out storage. The `op-node` uses a storage
/// proof to fetch this value.
/// @dev NOTE: this value will be migrated to another storage slot in a future version.
/// User input should not be placed in storage in this contract until this migration
/// happens. It is unlikely that keccak second preimage resistance will be broken,
/// but it is better to be safe than sorry.
bytes32 public constant UNSAFE_BLOCK_SIGNER_SLOT = keccak256("systemconfig.unsafeblocksigner");
/// @notice Storage slot that the L1CrossDomainMessenger address is stored at.
bytes32 public constant L1_CROSS_DOMAIN_MESSENGER_SLOT =
bytes32(uint256(keccak256("systemconfig.l1crossdomainmessenger")) - 1);
/// @notice Storage slot that the L1ERC721Bridge address is stored at.
bytes32 public constant L1_ERC_721_BRIDGE_SLOT = bytes32(uint256(keccak256("systemconfig.l1erc721bridge")) - 1);
/// @notice Storage slot that the L1StandardBridge address is stored at.
bytes32 public constant L1_STANDARD_BRIDGE_SLOT = bytes32(uint256(keccak256("systemconfig.l1standardbridge")) - 1);
/// @notice Storage slot that the OptimismPortal address is stored at.
bytes32 public constant OPTIMISM_PORTAL_SLOT = bytes32(uint256(keccak256("systemconfig.optimismportal")) - 1);
/// @notice Storage slot that the OptimismMintableERC20Factory address is stored at.
bytes32 public constant OPTIMISM_MINTABLE_ERC20_FACTORY_SLOT =
bytes32(uint256(keccak256("systemconfig.optimismmintableerc20factory")) - 1);
/// @notice Storage slot that the batch inbox address is stored at.
bytes32 public constant BATCH_INBOX_SLOT = bytes32(uint256(keccak256("systemconfig.batchinbox")) - 1);
/// @notice Storage slot for block at which the op-node can start searching for logs from.
bytes32 public constant START_BLOCK_SLOT = bytes32(uint256(keccak256("systemconfig.startBlock")) - 1);
/// @notice Storage slot for the DisputeGameFactory address.
bytes32 public constant DISPUTE_GAME_FACTORY_SLOT =
bytes32(uint256(keccak256("systemconfig.disputegamefactory")) - 1);
/// @notice The number of decimals that the gas paying token has.
uint8 internal constant GAS_PAYING_TOKEN_DECIMALS = 18;
/// @notice The maximum gas limit that can be set for L2 blocks. This limit is used to enforce that the blocks
/// on L2 are not too large to process and prove. Over time, this value can be increased as various
/// optimizations and improvements are made to the system at large.
uint64 internal constant MAX_GAS_LIMIT = 200_000_000;
/// @notice Fixed L2 gas overhead. Used as part of the L2 fee calculation.
/// Deprecated since the Ecotone network upgrade
uint256 public overhead;
/// @notice Dynamic L2 gas overhead. Used as part of the L2 fee calculation.
/// The most significant byte is used to determine the version since the
/// Ecotone network upgrade.
uint256 public scalar;
/// @notice Identifier for the batcher.
/// For version 1 of this configuration, this is represented as an address left-padded
/// with zeros to 32 bytes.
bytes32 public batcherHash;
/// @notice L2 block gas limit.
uint64 public gasLimit;
/// @notice Basefee scalar value. Part of the L2 fee calculation since the Ecotone network upgrade.
uint32 public basefeeScalar;
/// @notice Blobbasefee scalar value. Part of the L2 fee calculation since the Ecotone network upgrade.
uint32 public blobbasefeeScalar;
/// @notice The configuration for the deposit fee market.
/// Used by the OptimismPortal to meter the cost of buying L2 gas on L1.
/// Set as internal with a getter so that the struct is returned instead of a tuple.
IResourceMetering.ResourceConfig internal _resourceConfig;
/// @notice The EIP-1559 base fee max change denominator.
uint32 public eip1559Denominator;
/// @notice The EIP-1559 elasticity multiplier.
uint32 public eip1559Elasticity;
/// @notice Emitted when configuration is updated.
/// @param version SystemConfig version.
/// @param updateType Type of update.
/// @param data Encoded update data.
event ConfigUpdate(uint256 indexed version, UpdateType indexed updateType, bytes data);
/// @notice Semantic version.
/// @custom:semver 2.3.0
function version() public pure virtual returns (string memory) {
return "2.3.0";
}
/// @notice Constructs the SystemConfig contract. Cannot set
/// the owner to `address(0)` due to the Ownable contract's
/// implementation, so set it to `address(0xdEaD)`
/// @dev START_BLOCK_SLOT is set to type(uint256).max here so that it will be a dead value
/// in the singleton and is skipped by initialize when setting the start block.
constructor() {
Storage.setUint(START_BLOCK_SLOT, type(uint256).max);
initialize({
_owner: address(0xdEaD),
_basefeeScalar: 0,
_blobbasefeeScalar: 0,
_batcherHash: bytes32(0),
_gasLimit: 1,
_unsafeBlockSigner: address(0),
_config: IResourceMetering.ResourceConfig({
maxResourceLimit: 1,
elasticityMultiplier: 1,
baseFeeMaxChangeDenominator: 2,
minimumBaseFee: 0,
systemTxMaxGas: 0,
maximumBaseFee: 0
}),
_batchInbox: address(0),
_addresses: SystemConfig.Addresses({
l1CrossDomainMessenger: address(0),
l1ERC721Bridge: address(0),
l1StandardBridge: address(0),
disputeGameFactory: address(0),
optimismPortal: address(0),
optimismMintableERC20Factory: address(0),
gasPayingToken: address(0)
})
});
}
/// @notice Initializer.
/// The resource config must be set before the require check.
/// @param _owner Initial owner of the contract.
/// @param _basefeeScalar Initial basefee scalar value.
/// @param _blobbasefeeScalar Initial blobbasefee scalar value.
/// @param _batcherHash Initial batcher hash.
/// @param _gasLimit Initial gas limit.
/// @param _unsafeBlockSigner Initial unsafe block signer address.
/// @param _config Initial ResourceConfig.
/// @param _batchInbox Batch inbox address. An identifier for the op-node to find
/// canonical data.
/// @param _addresses Set of L1 contract addresses. These should be the proxies.
function initialize(
address _owner,
uint32 _basefeeScalar,
uint32 _blobbasefeeScalar,
bytes32 _batcherHash,
uint64 _gasLimit,
address _unsafeBlockSigner,
IResourceMetering.ResourceConfig memory _config,
address _batchInbox,
SystemConfig.Addresses memory _addresses
)
public
initializer
{
__Ownable_init();
transferOwnership(_owner);
// These are set in ascending order of their UpdateTypes.
_setBatcherHash(_batcherHash);
_setGasConfigEcotone({ _basefeeScalar: _basefeeScalar, _blobbasefeeScalar: _blobbasefeeScalar });
_setGasLimit(_gasLimit);
Storage.setAddress(UNSAFE_BLOCK_SIGNER_SLOT, _unsafeBlockSigner);
Storage.setAddress(BATCH_INBOX_SLOT, _batchInbox);
Storage.setAddress(L1_CROSS_DOMAIN_MESSENGER_SLOT, _addresses.l1CrossDomainMessenger);
Storage.setAddress(L1_ERC_721_BRIDGE_SLOT, _addresses.l1ERC721Bridge);
Storage.setAddress(L1_STANDARD_BRIDGE_SLOT, _addresses.l1StandardBridge);
Storage.setAddress(DISPUTE_GAME_FACTORY_SLOT, _addresses.disputeGameFactory);
Storage.setAddress(OPTIMISM_PORTAL_SLOT, _addresses.optimismPortal);
Storage.setAddress(OPTIMISM_MINTABLE_ERC20_FACTORY_SLOT, _addresses.optimismMintableERC20Factory);
_setStartBlock();
_setGasPayingToken(_addresses.gasPayingToken);
_setResourceConfig(_config);
require(_gasLimit >= minimumGasLimit(), "SystemConfig: gas limit too low");
}
/// @notice Returns the minimum L2 gas limit that can be safely set for the system to
/// operate. The L2 gas limit must be larger than or equal to the amount of
/// gas that is allocated for deposits per block plus the amount of gas that
/// is allocated for the system transaction.
/// This function is used to determine if changes to parameters are safe.
/// @return uint64 Minimum gas limit.
function minimumGasLimit() public view returns (uint64) {
return uint64(_resourceConfig.maxResourceLimit) + uint64(_resourceConfig.systemTxMaxGas);
}
/// @notice Returns the maximum L2 gas limit that can be safely set for the system to
/// operate. This bound is used to prevent the gas limit from being set too high
/// and causing the system to be unable to process and/or prove L2 blocks.
/// @return uint64 Maximum gas limit.
function maximumGasLimit() public pure returns (uint64) {
return MAX_GAS_LIMIT;
}
/// @notice High level getter for the unsafe block signer address.
/// Unsafe blocks can be propagated across the p2p network if they are signed by the
/// key corresponding to this address.
/// @return addr_ Address of the unsafe block signer.
function unsafeBlockSigner() public view returns (address addr_) {
addr_ = Storage.getAddress(UNSAFE_BLOCK_SIGNER_SLOT);
}
/// @notice Getter for the L1CrossDomainMessenger address.
function l1CrossDomainMessenger() external view returns (address addr_) {
addr_ = Storage.getAddress(L1_CROSS_DOMAIN_MESSENGER_SLOT);
}
/// @notice Getter for the L1ERC721Bridge address.
function l1ERC721Bridge() external view returns (address addr_) {
addr_ = Storage.getAddress(L1_ERC_721_BRIDGE_SLOT);
}
/// @notice Getter for the L1StandardBridge address.
function l1StandardBridge() external view returns (address addr_) {
addr_ = Storage.getAddress(L1_STANDARD_BRIDGE_SLOT);
}
/// @notice Getter for the DisputeGameFactory address.
function disputeGameFactory() external view returns (address addr_) {
addr_ = Storage.getAddress(DISPUTE_GAME_FACTORY_SLOT);
}
/// @notice Getter for the OptimismPortal address.
function optimismPortal() public view returns (address addr_) {
addr_ = Storage.getAddress(OPTIMISM_PORTAL_SLOT);
}
/// @notice Getter for the OptimismMintableERC20Factory address.
function optimismMintableERC20Factory() external view returns (address addr_) {
addr_ = Storage.getAddress(OPTIMISM_MINTABLE_ERC20_FACTORY_SLOT);
}
/// @notice Getter for the BatchInbox address.
function batchInbox() external view returns (address addr_) {
addr_ = Storage.getAddress(BATCH_INBOX_SLOT);
}
/// @notice Getter for the StartBlock number.
function startBlock() external view returns (uint256 startBlock_) {
startBlock_ = Storage.getUint(START_BLOCK_SLOT);
}
/// @notice Getter for the gas paying asset address.
function gasPayingToken() public view returns (address addr_, uint8 decimals_) {
(addr_, decimals_) = GasPayingToken.getToken();
}
/// @notice Getter for custom gas token paying networks. Returns true if the
/// network uses a custom gas token.
function isCustomGasToken() public view returns (bool) {
(address token,) = gasPayingToken();
return token != Constants.ETHER;
}
/// @notice Getter for the gas paying token name.
function gasPayingTokenName() external view returns (string memory name_) {
name_ = GasPayingToken.getName();
}
/// @notice Getter for the gas paying token symbol.
function gasPayingTokenSymbol() external view returns (string memory symbol_) {
symbol_ = GasPayingToken.getSymbol();
}
/// @notice Internal setter for the gas paying token address, includes validation.
/// The token must not already be set and must be non zero and not the ether address
/// to set the token address. This prevents the token address from being changed
/// and makes it explicitly opt-in to use custom gas token.
/// @param _token Address of the gas paying token.
function _setGasPayingToken(address _token) internal virtual {
if (_token != address(0) && _token != Constants.ETHER && !isCustomGasToken()) {
require(
ERC20(_token).decimals() == GAS_PAYING_TOKEN_DECIMALS, "SystemConfig: bad decimals of gas paying token"
);
bytes32 name = GasPayingToken.sanitize(ERC20(_token).name());
bytes32 symbol = GasPayingToken.sanitize(ERC20(_token).symbol());
// Set the gas paying token in storage and in the OptimismPortal.
GasPayingToken.set({ _token: _token, _decimals: GAS_PAYING_TOKEN_DECIMALS, _name: name, _symbol: symbol });
IOptimismPortal(payable(optimismPortal())).setGasPayingToken({
_token: _token,
_decimals: GAS_PAYING_TOKEN_DECIMALS,
_name: name,
_symbol: symbol
});
}
}
/// @notice Updates the unsafe block signer address. Can only be called by the owner.
/// @param _unsafeBlockSigner New unsafe block signer address.
function setUnsafeBlockSigner(address _unsafeBlockSigner) external onlyOwner {
_setUnsafeBlockSigner(_unsafeBlockSigner);
}
/// @notice Updates the unsafe block signer address.
/// @param _unsafeBlockSigner New unsafe block signer address.
function _setUnsafeBlockSigner(address _unsafeBlockSigner) internal {
Storage.setAddress(UNSAFE_BLOCK_SIGNER_SLOT, _unsafeBlockSigner);
bytes memory data = abi.encode(_unsafeBlockSigner);
emit ConfigUpdate(VERSION, UpdateType.UNSAFE_BLOCK_SIGNER, data);
}
/// @notice Updates the batcher hash. Can only be called by the owner.
/// @param _batcherHash New batcher hash.
function setBatcherHash(bytes32 _batcherHash) external onlyOwner {
_setBatcherHash(_batcherHash);
}
/// @notice Internal function for updating the batcher hash.
/// @param _batcherHash New batcher hash.
function _setBatcherHash(bytes32 _batcherHash) internal {
batcherHash = _batcherHash;
bytes memory data = abi.encode(_batcherHash);
emit ConfigUpdate(VERSION, UpdateType.BATCHER, data);
}
/// @notice Updates gas config. Can only be called by the owner.
/// Deprecated in favor of setGasConfigEcotone since the Ecotone upgrade.
/// @param _overhead New overhead value.
/// @param _scalar New scalar value.
function setGasConfig(uint256 _overhead, uint256 _scalar) external onlyOwner {
_setGasConfig(_overhead, _scalar);
}
/// @notice Internal function for updating the gas config.
/// @param _overhead New overhead value.
/// @param _scalar New scalar value.
function _setGasConfig(uint256 _overhead, uint256 _scalar) internal {
require((uint256(0xff) << 248) & _scalar == 0, "SystemConfig: scalar exceeds max.");
overhead = _overhead;
scalar = _scalar;
bytes memory data = abi.encode(_overhead, _scalar);
emit ConfigUpdate(VERSION, UpdateType.FEE_SCALARS, data);
}
/// @notice Updates gas config as of the Ecotone upgrade. Can only be called by the owner.
/// @param _basefeeScalar New basefeeScalar value.
/// @param _blobbasefeeScalar New blobbasefeeScalar value.
function setGasConfigEcotone(uint32 _basefeeScalar, uint32 _blobbasefeeScalar) external onlyOwner {
_setGasConfigEcotone(_basefeeScalar, _blobbasefeeScalar);
}
/// @notice Internal function for updating the fee scalars as of the Ecotone upgrade.
/// @param _basefeeScalar New basefeeScalar value.
/// @param _blobbasefeeScalar New blobbasefeeScalar value.
function _setGasConfigEcotone(uint32 _basefeeScalar, uint32 _blobbasefeeScalar) internal {
basefeeScalar = _basefeeScalar;
blobbasefeeScalar = _blobbasefeeScalar;
scalar = (uint256(0x01) << 248) | (uint256(_blobbasefeeScalar) << 32) | _basefeeScalar;
bytes memory data = abi.encode(overhead, scalar);
emit ConfigUpdate(VERSION, UpdateType.FEE_SCALARS, data);
}
/// @notice Updates the L2 gas limit. Can only be called by the owner.
/// @param _gasLimit New gas limit.
function setGasLimit(uint64 _gasLimit) external onlyOwner {
_setGasLimit(_gasLimit);
}
/// @notice Internal function for updating the L2 gas limit.
/// @param _gasLimit New gas limit.
function _setGasLimit(uint64 _gasLimit) internal {
require(_gasLimit >= minimumGasLimit(), "SystemConfig: gas limit too low");
require(_gasLimit <= maximumGasLimit(), "SystemConfig: gas limit too high");
gasLimit = _gasLimit;
bytes memory data = abi.encode(_gasLimit);
emit ConfigUpdate(VERSION, UpdateType.GAS_LIMIT, data);
}
/// @notice Updates the EIP-1559 parameters of the chain. Can only be called by the owner.
/// @param _denominator EIP-1559 base fee max change denominator.
/// @param _elasticity EIP-1559 elasticity multiplier.
function setEIP1559Params(uint32 _denominator, uint32 _elasticity) external onlyOwner {
_setEIP1559Params(_denominator, _elasticity);
}
/// @notice Internal function for updating the EIP-1559 parameters.
function _setEIP1559Params(uint32 _denominator, uint32 _elasticity) internal {
// require the parameters have sane values:
require(_denominator >= 1, "SystemConfig: denominator must be >= 1");
require(_elasticity >= 1, "SystemConfig: elasticity must be >= 1");
eip1559Denominator = _denominator;
eip1559Elasticity = _elasticity;
bytes memory data = abi.encode(uint256(_denominator) << 32 | uint64(_elasticity));
emit ConfigUpdate(VERSION, UpdateType.EIP_1559_PARAMS, data);
}
/// @notice Sets the start block in a backwards compatible way. Proxies
/// that were initialized before the startBlock existed in storage
/// can have their start block set by a user provided override.
/// A start block of 0 indicates that there is no override and the
/// start block will be set by `block.number`.
/// @dev This logic is used to patch legacy deployments with new storage values.
/// Use the override if it is provided as a non zero value and the value
/// has not already been set in storage. Use `block.number` if the value
/// has already been set in storage
function _setStartBlock() internal {
if (Storage.getUint(START_BLOCK_SLOT) == 0) {
Storage.setUint(START_BLOCK_SLOT, block.number);
}
}
/// @notice A getter for the resource config.
/// Ensures that the struct is returned instead of a tuple.
/// @return ResourceConfig
function resourceConfig() external view returns (IResourceMetering.ResourceConfig memory) {
return _resourceConfig;
}
/// @notice An internal setter for the resource config.
/// Ensures that the config is sane before storing it by checking for invariants.
/// In the future, this method may emit an event that the `op-node` picks up
/// for when the resource config is changed.
/// @param _config The new resource config.
function _setResourceConfig(IResourceMetering.ResourceConfig memory _config) internal {
// Min base fee must be less than or equal to max base fee.
require(
_config.minimumBaseFee <= _config.maximumBaseFee, "SystemConfig: min base fee must be less than max base"
);
// Base fee change denominator must be greater than 1.
require(_config.baseFeeMaxChangeDenominator > 1, "SystemConfig: denominator must be larger than 1");
// Max resource limit plus system tx gas must be less than or equal to the L2 gas limit.
// The gas limit must be increased before these values can be increased.
require(_config.maxResourceLimit + _config.systemTxMaxGas <= gasLimit, "SystemConfig: gas limit too low");
// Elasticity multiplier must be greater than 0.
require(_config.elasticityMultiplier > 0, "SystemConfig: elasticity multiplier cannot be 0");
// No precision loss when computing target resource limit.
require(
((_config.maxResourceLimit / _config.elasticityMultiplier) * _config.elasticityMultiplier)
== _config.maxResourceLimit,
"SystemConfig: precision loss with target resource limit"
);
_resourceConfig = _config;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/ContextUpgradeable.sol";
import "../proxy/utils/Initializable.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
function __Ownable_init() internal onlyInitializing {
__Ownable_init_unchained();
}
function __Ownable_init_unchained() internal onlyInitializing {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/ERC20.sol)
pragma solidity ^0.8.0;
import "./IERC20.sol";
import "./extensions/IERC20Metadata.sol";
import "../../utils/Context.sol";
/**
* @dev Implementation of the {IERC20} interface.
*
* This implementation is agnostic to the way tokens are created. This means
* that a supply mechanism has to be added in a derived contract using {_mint}.
* For a generic mechanism see {ERC20PresetMinterPauser}.
*
* TIP: For a detailed writeup see our guide
* https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
* to implement supply mechanisms].
*
* We have followed general OpenZeppelin Contracts guidelines: functions revert
* instead returning `false` on failure. This behavior is nonetheless
* conventional and does not conflict with the expectations of ERC20
* applications.
*
* Additionally, an {Approval} event is emitted on calls to {transferFrom}.
* This allows applications to reconstruct the allowance for all accounts just
* by listening to said events. Other implementations of the EIP may not emit
* these events, as it isn't required by the specification.
*
* Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
* functions have been added to mitigate the well-known issues around setting
* allowances. See {IERC20-approve}.
*/
contract ERC20 is Context, IERC20, IERC20Metadata {
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
/**
* @dev Sets the values for {name} and {symbol}.
*
* The default value of {decimals} is 18. To select a different value for
* {decimals} you should overload it.
*
* All two of these values are immutable: they can only be set once during
* construction.
*/
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
/**
* @dev Returns the name of the token.
*/
function name() public view virtual override returns (string memory) {
return _name;
}
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
/**
* @dev Returns the number of decimals used to get its user representation.
* For example, if `decimals` equals `2`, a balance of `505` tokens should
* be displayed to a user as `5.05` (`505 / 10 ** 2`).
*
* Tokens usually opt for a value of 18, imitating the relationship between
* Ether and Wei. This is the value {ERC20} uses, unless this function is
* overridden;
*
* NOTE: This information is only used for _display_ purposes: it in
* no way affects any of the arithmetic of the contract, including
* {IERC20-balanceOf} and {IERC20-transfer}.
*/
function decimals() public view virtual override returns (uint8) {
return 18;
}
/**
* @dev See {IERC20-totalSupply}.
*/
function totalSupply() public view virtual override returns (uint256) {
return _totalSupply;
}
/**
* @dev See {IERC20-balanceOf}.
*/
function balanceOf(address account) public view virtual override returns (uint256) {
return _balances[account];
}
/**
* @dev See {IERC20-transfer}.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - the caller must have a balance of at least `amount`.
*/
function transfer(address to, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_transfer(owner, to, amount);
return true;
}
/**
* @dev See {IERC20-allowance}.
*/
function allowance(address owner, address spender) public view virtual override returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*
* NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
* `transferFrom`. This is semantically equivalent to an infinite approval.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_approve(owner, spender, amount);
return true;
}
/**
* @dev See {IERC20-transferFrom}.
*
* Emits an {Approval} event indicating the updated allowance. This is not
* required by the EIP. See the note at the beginning of {ERC20}.
*
* NOTE: Does not update the allowance if the current allowance
* is the maximum `uint256`.
*
* Requirements:
*
* - `from` and `to` cannot be the zero address.
* - `from` must have a balance of at least `amount`.
* - the caller must have allowance for ``from``'s tokens of at least
* `amount`.
*/
function transferFrom(
address from,
address to,
uint256 amount
) public virtual override returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, amount);
_transfer(from, to, amount);
return true;
}
/**
* @dev Atomically increases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, allowance(owner, spender) + addedValue);
return true;
}
/**
* @dev Atomically decreases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `spender` must have allowance for the caller of at least
* `subtractedValue`.
*/
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
address owner = _msgSender();
uint256 currentAllowance = allowance(owner, spender);
require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
unchecked {
_approve(owner, spender, currentAllowance - subtractedValue);
}
return true;
}
/**
* @dev Moves `amount` of tokens from `from` to `to`.
*
* This internal function is equivalent to {transfer}, and can be used to
* e.g. implement automatic token fees, slashing mechanisms, etc.
*
* Emits a {Transfer} event.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `from` must have a balance of at least `amount`.
*/
function _transfer(
address from,
address to,
uint256 amount
) internal virtual {
require(from != address(0), "ERC20: transfer from the zero address");
require(to != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(from, to, amount);
uint256 fromBalance = _balances[from];
require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
unchecked {
_balances[from] = fromBalance - amount;
}
_balances[to] += amount;
emit Transfer(from, to, amount);
_afterTokenTransfer(from, to, amount);
}
/** @dev Creates `amount` tokens and assigns them to `account`, increasing
* the total supply.
*
* Emits a {Transfer} event with `from` set to the zero address.
*
* Requirements:
*
* - `account` cannot be the zero address.
*/
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: mint to the zero address");
_beforeTokenTransfer(address(0), account, amount);
_totalSupply += amount;
_balances[account] += amount;
emit Transfer(address(0), account, amount);
_afterTokenTransfer(address(0), account, amount);
}
/**
* @dev Destroys `amount` tokens from `account`, reducing the
* total supply.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* Requirements:
*
* - `account` cannot be the zero address.
* - `account` must have at least `amount` tokens.
*/
function _burn(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: burn from the zero address");
_beforeTokenTransfer(account, address(0), amount);
uint256 accountBalance = _balances[account];
require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
unchecked {
_balances[account] = accountBalance - amount;
}
_totalSupply -= amount;
emit Transfer(account, address(0), amount);
_afterTokenTransfer(account, address(0), amount);
}
/**
* @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
*
* This internal function is equivalent to `approve`, and can be used to
* e.g. set automatic allowances for certain subsystems, etc.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `owner` cannot be the zero address.
* - `spender` cannot be the zero address.
*/
function _approve(
address owner,
address spender,
uint256 amount
) internal virtual {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
/**
* @dev Updates `owner` s allowance for `spender` based on spent `amount`.
*
* Does not update the allowance amount in case of infinite allowance.
* Revert if not enough allowance is available.
*
* Might emit an {Approval} event.
*/
function _spendAllowance(
address owner,
address spender,
uint256 amount
) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
require(currentAllowance >= amount, "ERC20: insufficient allowance");
unchecked {
_approve(owner, spender, currentAllowance - amount);
}
}
}
/**
* @dev Hook that is called before any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* will be transferred to `to`.
* - when `from` is zero, `amount` tokens will be minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens will be burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _beforeTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual {}
/**
* @dev Hook that is called after any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* has been transferred to `to`.
* - when `from` is zero, `amount` tokens have been minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens have been burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _afterTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual {}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @title Storage
/// @notice Storage handles reading and writing to arbitary storage locations
library Storage {
/// @notice Returns an address stored in an arbitrary storage slot.
/// These storage slots decouple the storage layout from
/// solc's automation.
/// @param _slot The storage slot to retrieve the address from.
function getAddress(bytes32 _slot) internal view returns (address addr_) {
assembly {
addr_ := sload(_slot)
}
}
/// @notice Stores an address in an arbitrary storage slot, `_slot`.
/// @param _slot The storage slot to store the address in.
/// @param _address The protocol version to store
/// @dev WARNING! This function must be used cautiously, as it allows for overwriting addresses
/// in arbitrary storage slots.
function setAddress(bytes32 _slot, address _address) internal {
assembly {
sstore(_slot, _address)
}
}
/// @notice Returns a uint256 stored in an arbitrary storage slot.
/// These storage slots decouple the storage layout from
/// solc's automation.
/// @param _slot The storage slot to retrieve the address from.
function getUint(bytes32 _slot) internal view returns (uint256 value_) {
assembly {
value_ := sload(_slot)
}
}
/// @notice Stores a value in an arbitrary storage slot, `_slot`.
/// @param _slot The storage slot to store the address in.
/// @param _value The protocol version to store
/// @dev WARNING! This function must be used cautiously, as it allows for overwriting values
/// in arbitrary storage slots.
function setUint(bytes32 _slot, uint256 _value) internal {
assembly {
sstore(_slot, _value)
}
}
/// @notice Returns a bytes32 stored in an arbitrary storage slot.
/// These storage slots decouple the storage layout from
/// solc's automation.
/// @param _slot The storage slot to retrieve the address from.
function getBytes32(bytes32 _slot) internal view returns (bytes32 value_) {
assembly {
value_ := sload(_slot)
}
}
/// @notice Stores a bytes32 value in an arbitrary storage slot, `_slot`.
/// @param _slot The storage slot to store the address in.
/// @param _value The bytes32 value to store.
/// @dev WARNING! This function must be used cautiously, as it allows for overwriting values
/// in arbitrary storage slots.
function setBytes32(bytes32 _slot, bytes32 _value) internal {
assembly {
sstore(_slot, _value)
}
}
/// @notice Stores a bool value in an arbitrary storage slot, `_slot`.
/// @param _slot The storage slot to store the bool in.
/// @param _value The bool value to store
/// @dev WARNING! This function must be used cautiously, as it allows for overwriting values
/// in arbitrary storage slots.
function setBool(bytes32 _slot, bool _value) internal {
assembly {
sstore(_slot, _value)
}
}
/// @notice Returns a bool stored in an arbitrary storage slot.
/// @param _slot The storage slot to retrieve the bool from.
function getBool(bytes32 _slot) internal view returns (bool value_) {
assembly {
value_ := sload(_slot)
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { IResourceMetering } from "src/L1/interfaces/IResourceMetering.sol";
/// @title Constants
/// @notice Constants is a library for storing constants. Simple! Don't put everything in here, just
/// the stuff used in multiple contracts. Constants that only apply to a single contract
/// should be defined in that contract instead.
library Constants {
/// @notice Special address to be used as the tx origin for gas estimation calls in the
/// OptimismPortal and CrossDomainMessenger calls. You only need to use this address if
/// the minimum gas limit specified by the user is not actually enough to execute the
/// given message and you're attempting to estimate the actual necessary gas limit. We
/// use address(1) because it's the ecrecover precompile and therefore guaranteed to
/// never have any code on any EVM chain.
address internal constant ESTIMATION_ADDRESS = address(1);
/// @notice Value used for the L2 sender storage slot in both the OptimismPortal and the
/// CrossDomainMessenger contracts before an actual sender is set. This value is
/// non-zero to reduce the gas cost of message passing transactions.
address internal constant DEFAULT_L2_SENDER = 0x000000000000000000000000000000000000dEaD;
/// @notice The storage slot that holds the address of a proxy implementation.
/// @dev `bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)`
bytes32 internal constant PROXY_IMPLEMENTATION_ADDRESS =
0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
/// @notice The storage slot that holds the address of the owner.
/// @dev `bytes32(uint256(keccak256('eip1967.proxy.admin')) - 1)`
bytes32 internal constant PROXY_OWNER_ADDRESS = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
/// @notice The address that represents ether when dealing with ERC20 token addresses.
address internal constant ETHER = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
/// @notice The address that represents the system caller responsible for L1 attributes
/// transactions.
address internal constant DEPOSITOR_ACCOUNT = 0xDeaDDEaDDeAdDeAdDEAdDEaddeAddEAdDEAd0001;
/// @notice Returns the default values for the ResourceConfig. These are the recommended values
/// for a production network.
function DEFAULT_RESOURCE_CONFIG() internal pure returns (IResourceMetering.ResourceConfig memory) {
IResourceMetering.ResourceConfig memory config = IResourceMetering.ResourceConfig({
maxResourceLimit: 20_000_000,
elasticityMultiplier: 10,
baseFeeMaxChangeDenominator: 8,
minimumBaseFee: 1 gwei,
systemTxMaxGas: 1_000_000,
maximumBaseFee: type(uint128).max
});
return config;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { Storage } from "src/libraries/Storage.sol";
import { Constants } from "src/libraries/Constants.sol";
import { LibString } from "@solady/utils/LibString.sol";
/// @title IGasToken
/// @notice Implemented by contracts that are aware of the custom gas token used
/// by the L2 network.
interface IGasToken {
/// @notice Getter for the ERC20 token address that is used to pay for gas and its decimals.
function gasPayingToken() external view returns (address, uint8);
/// @notice Returns the gas token name.
function gasPayingTokenName() external view returns (string memory);
/// @notice Returns the gas token symbol.
function gasPayingTokenSymbol() external view returns (string memory);
/// @notice Returns true if the network uses a custom gas token.
function isCustomGasToken() external view returns (bool);
}
/// @title GasPayingToken
/// @notice Handles reading and writing the custom gas token to storage.
/// To be used in any place where gas token information is read or
/// written to state. If multiple contracts use this library, the
/// values in storage should be kept in sync between them.
library GasPayingToken {
/// @notice The storage slot that contains the address and decimals of the gas paying token
bytes32 internal constant GAS_PAYING_TOKEN_SLOT = bytes32(uint256(keccak256("opstack.gaspayingtoken")) - 1);
/// @notice The storage slot that contains the ERC20 `name()` of the gas paying token
bytes32 internal constant GAS_PAYING_TOKEN_NAME_SLOT = bytes32(uint256(keccak256("opstack.gaspayingtokenname")) - 1);
/// @notice the storage slot that contains the ERC20 `symbol()` of the gas paying token
bytes32 internal constant GAS_PAYING_TOKEN_SYMBOL_SLOT =
bytes32(uint256(keccak256("opstack.gaspayingtokensymbol")) - 1);
/// @notice Reads the gas paying token and its decimals from the magic
/// storage slot. If nothing is set in storage, then the ether
/// address is returned instead.
function getToken() internal view returns (address addr_, uint8 decimals_) {
bytes32 slot = Storage.getBytes32(GAS_PAYING_TOKEN_SLOT);
addr_ = address(uint160(uint256(slot) & uint256(type(uint160).max)));
if (addr_ == address(0)) {
addr_ = Constants.ETHER;
decimals_ = 18;
} else {
decimals_ = uint8(uint256(slot) >> 160);
}
}
/// @notice Reads the gas paying token's name from the magic storage slot.
/// If nothing is set in storage, then the ether name, 'Ether', is returned instead.
function getName() internal view returns (string memory name_) {
(address addr,) = getToken();
if (addr == Constants.ETHER) {
name_ = "Ether";
} else {
name_ = LibString.fromSmallString(Storage.getBytes32(GAS_PAYING_TOKEN_NAME_SLOT));
}
}
/// @notice Reads the gas paying token's symbol from the magic storage slot.
/// If nothing is set in storage, then the ether symbol, 'ETH', is returned instead.
function getSymbol() internal view returns (string memory symbol_) {
(address addr,) = getToken();
if (addr == Constants.ETHER) {
symbol_ = "ETH";
} else {
symbol_ = LibString.fromSmallString(Storage.getBytes32(GAS_PAYING_TOKEN_SYMBOL_SLOT));
}
}
/// @notice Writes the gas paying token, its decimals, name and symbol to the magic storage slot.
function set(address _token, uint8 _decimals, bytes32 _name, bytes32 _symbol) internal {
Storage.setBytes32(GAS_PAYING_TOKEN_SLOT, bytes32(uint256(_decimals) << 160 | uint256(uint160(_token))));
Storage.setBytes32(GAS_PAYING_TOKEN_NAME_SLOT, _name);
Storage.setBytes32(GAS_PAYING_TOKEN_SYMBOL_SLOT, _symbol);
}
/// @notice Maps a string to a normalized null-terminated small string.
function sanitize(string memory _str) internal pure returns (bytes32) {
require(bytes(_str).length <= 32, "GasPayingToken: string cannot be greater than 32 bytes");
return LibString.toSmallString(_str);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @title ISemver
/// @notice ISemver is a simple contract for ensuring that contracts are
/// versioned using semantic versioning.
interface ISemver {
/// @notice Getter for the semantic version of the contract. This is not
/// meant to be used onchain but instead meant to be used by offchain
/// tooling.
/// @return Semver contract version as a string.
function version() external view returns (string memory);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { Types } from "src/libraries/Types.sol";
import { ISystemConfig } from "src/L1/interfaces/ISystemConfig.sol";
import { ISuperchainConfig } from "src/L1/interfaces/ISuperchainConfig.sol";
import { IL2OutputOracle } from "src/L1/interfaces/IL2OutputOracle.sol";
interface IOptimismPortal {
error BadTarget();
error CallPaused();
error ContentLengthMismatch();
error EmptyItem();
error GasEstimation();
error InvalidDataRemainder();
error InvalidHeader();
error LargeCalldata();
error NoValue();
error NonReentrant();
error OnlyCustomGasToken();
error OutOfGas();
error SmallGasLimit();
error TransferFailed();
error Unauthorized();
error UnexpectedList();
error UnexpectedString();
event Initialized(uint8 version);
event TransactionDeposited(address indexed from, address indexed to, uint256 indexed version, bytes opaqueData);
event WithdrawalFinalized(bytes32 indexed withdrawalHash, bool success);
event WithdrawalProven(bytes32 indexed withdrawalHash, address indexed from, address indexed to);
receive() external payable;
function balance() external view returns (uint256);
function depositERC20Transaction(
address _to,
uint256 _mint,
uint256 _value,
uint64 _gasLimit,
bool _isCreation,
bytes memory _data
)
external;
function depositTransaction(
address _to,
uint256 _value,
uint64 _gasLimit,
bool _isCreation,
bytes memory _data
)
external
payable;
function donateETH() external payable;
function finalizeWithdrawalTransaction(Types.WithdrawalTransaction memory _tx) external;
function finalizedWithdrawals(bytes32) external view returns (bool);
function guardian() external view returns (address);
function initialize(
IL2OutputOracle _l2Oracle,
ISystemConfig _systemConfig,
ISuperchainConfig _superchainConfig
)
external;
function isOutputFinalized(uint256 _l2OutputIndex) external view returns (bool);
function l2Oracle() external view returns (IL2OutputOracle);
function l2Sender() external view returns (address);
function minimumGasLimit(uint64 _byteCount) external pure returns (uint64);
function params() external view returns (uint128 prevBaseFee, uint64 prevBoughtGas, uint64 prevBlockNum); // nosemgrep
function paused() external view returns (bool paused_);
function proveWithdrawalTransaction(
Types.WithdrawalTransaction memory _tx,
uint256 _l2OutputIndex,
Types.OutputRootProof memory _outputRootProof,
bytes[] memory _withdrawalProof
)
external;
function provenWithdrawals(bytes32)
external
view
returns (bytes32 outputRoot, uint128 timestamp, uint128 l2OutputIndex); // nosemgrep
function setGasPayingToken(address _token, uint8 _decimals, bytes32 _name, bytes32 _symbol) external;
function superchainConfig() external view returns (ISuperchainConfig);
function systemConfig() external view returns (ISystemConfig);
function version() external pure returns (string memory);
function __constructor__() external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IResourceMetering {
struct ResourceParams {
uint128 prevBaseFee;
uint64 prevBoughtGas;
uint64 prevBlockNum;
}
struct ResourceConfig {
uint32 maxResourceLimit;
uint8 elasticityMultiplier;
uint8 baseFeeMaxChangeDenominator;
uint32 minimumBaseFee;
uint32 systemTxMaxGas;
uint128 maximumBaseFee;
}
error OutOfGas();
event Initialized(uint8 version);
function params() external view returns (uint128 prevBaseFee, uint64 prevBoughtGas, uint64 prevBlockNum); // nosemgrep
function __constructor__() external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
import "../proxy/utils/Initializable.sol";
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract ContextUpgradeable is Initializable {
function __Context_init() internal onlyInitializing {
}
function __Context_init_unchained() internal onlyInitializing {
}
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[50] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.2;
import "../../utils/AddressUpgradeable.sol";
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Indicates that the contract has been initialized.
* @custom:oz-retyped-from bool
*/
uint8 private _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private _initializing;
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint8 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts. Equivalent to `reinitializer(1)`.
*/
modifier initializer() {
bool isTopLevelCall = !_initializing;
require(
(isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
"Initializable: contract is already initialized"
);
_initialized = 1;
if (isTopLevelCall) {
_initializing = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original
* initialization step. This is essential to configure modules that are added through upgrades and that require
* initialization.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*/
modifier reinitializer(uint8 version) {
require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
_initialized = version;
_initializing = true;
_;
_initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
require(_initializing, "Initializable: contract is not initializing");
_;
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*/
function _disableInitializers() internal virtual {
require(!_initializing, "Initializable: contract is initializing");
if (_initialized < type(uint8).max) {
_initialized = type(uint8).max;
emit Initialized(type(uint8).max);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*
* _Available since v4.1._
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Library for converting numbers into strings and other string operations.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibString.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/LibString.sol)
///
/// Note:
/// For performance and bytecode compactness, most of the string operations are restricted to
/// byte strings (7-bit ASCII), except where otherwise specified.
/// Usage of byte string operations on charsets with runes spanning two or more bytes
/// can lead to undefined behavior.
library LibString {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The length of the output is too small to contain all the hex digits.
error HexLengthInsufficient();
/// @dev The length of the string is more than 32 bytes.
error TooBigForSmallString();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The constant returned when the `search` is not found in the string.
uint256 internal constant NOT_FOUND = type(uint256).max;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* DECIMAL OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the base 10 decimal representation of `value`.
function toString(uint256 value) internal pure returns (string memory str) {
/// @solidity memory-safe-assembly
assembly {
// The maximum value of a uint256 contains 78 digits (1 byte per digit), but
// we allocate 0xa0 bytes to keep the free memory pointer 32-byte word aligned.
// We will need 1 word for the trailing zeros padding, 1 word for the length,
// and 3 words for a maximum of 78 digits.
str := add(mload(0x40), 0x80)
// Update the free memory pointer to allocate.
mstore(0x40, add(str, 0x20))
// Zeroize the slot after the string.
mstore(str, 0)
// Cache the end of the memory to calculate the length later.
let end := str
let w := not(0) // Tsk.
// We write the string from rightmost digit to leftmost digit.
// The following is essentially a do-while loop that also handles the zero case.
for { let temp := value } 1 {} {
str := add(str, w) // `sub(str, 1)`.
// Write the character to the pointer.
// The ASCII index of the '0' character is 48.
mstore8(str, add(48, mod(temp, 10)))
// Keep dividing `temp` until zero.
temp := div(temp, 10)
if iszero(temp) { break }
}
let length := sub(end, str)
// Move the pointer 32 bytes leftwards to make room for the length.
str := sub(str, 0x20)
// Store the length.
mstore(str, length)
}
}
/// @dev Returns the base 10 decimal representation of `value`.
function toString(int256 value) internal pure returns (string memory str) {
if (value >= 0) {
return toString(uint256(value));
}
unchecked {
str = toString(uint256(-value));
}
/// @solidity memory-safe-assembly
assembly {
// We still have some spare memory space on the left,
// as we have allocated 3 words (96 bytes) for up to 78 digits.
let length := mload(str) // Load the string length.
mstore(str, 0x2d) // Store the '-' character.
str := sub(str, 1) // Move back the string pointer by a byte.
mstore(str, add(length, 1)) // Update the string length.
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* HEXADECIMAL OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the hexadecimal representation of `value`,
/// left-padded to an input length of `length` bytes.
/// The output is prefixed with "0x" encoded using 2 hexadecimal digits per byte,
/// giving a total length of `length * 2 + 2` bytes.
/// Reverts if `length` is too small for the output to contain all the digits.
function toHexString(uint256 value, uint256 length) internal pure returns (string memory str) {
str = toHexStringNoPrefix(value, length);
/// @solidity memory-safe-assembly
assembly {
let strLength := add(mload(str), 2) // Compute the length.
mstore(str, 0x3078) // Write the "0x" prefix.
str := sub(str, 2) // Move the pointer.
mstore(str, strLength) // Write the length.
}
}
/// @dev Returns the hexadecimal representation of `value`,
/// left-padded to an input length of `length` bytes.
/// The output is prefixed with "0x" encoded using 2 hexadecimal digits per byte,
/// giving a total length of `length * 2` bytes.
/// Reverts if `length` is too small for the output to contain all the digits.
function toHexStringNoPrefix(uint256 value, uint256 length)
internal
pure
returns (string memory str)
{
/// @solidity memory-safe-assembly
assembly {
// We need 0x20 bytes for the trailing zeros padding, `length * 2` bytes
// for the digits, 0x02 bytes for the prefix, and 0x20 bytes for the length.
// We add 0x20 to the total and round down to a multiple of 0x20.
// (0x20 + 0x20 + 0x02 + 0x20) = 0x62.
str := add(mload(0x40), and(add(shl(1, length), 0x42), not(0x1f)))
// Allocate the memory.
mstore(0x40, add(str, 0x20))
// Zeroize the slot after the string.
mstore(str, 0)
// Cache the end to calculate the length later.
let end := str
// Store "0123456789abcdef" in scratch space.
mstore(0x0f, 0x30313233343536373839616263646566)
let start := sub(str, add(length, length))
let w := not(1) // Tsk.
let temp := value
// We write the string from rightmost digit to leftmost digit.
// The following is essentially a do-while loop that also handles the zero case.
for {} 1 {} {
str := add(str, w) // `sub(str, 2)`.
mstore8(add(str, 1), mload(and(temp, 15)))
mstore8(str, mload(and(shr(4, temp), 15)))
temp := shr(8, temp)
if iszero(xor(str, start)) { break }
}
if temp {
mstore(0x00, 0x2194895a) // `HexLengthInsufficient()`.
revert(0x1c, 0x04)
}
// Compute the string's length.
let strLength := sub(end, str)
// Move the pointer and write the length.
str := sub(str, 0x20)
mstore(str, strLength)
}
}
/// @dev Returns the hexadecimal representation of `value`.
/// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte.
/// As address are 20 bytes long, the output will left-padded to have
/// a length of `20 * 2 + 2` bytes.
function toHexString(uint256 value) internal pure returns (string memory str) {
str = toHexStringNoPrefix(value);
/// @solidity memory-safe-assembly
assembly {
let strLength := add(mload(str), 2) // Compute the length.
mstore(str, 0x3078) // Write the "0x" prefix.
str := sub(str, 2) // Move the pointer.
mstore(str, strLength) // Write the length.
}
}
/// @dev Returns the hexadecimal representation of `value`.
/// The output is prefixed with "0x".
/// The output excludes leading "0" from the `toHexString` output.
/// `0x00: "0x0", 0x01: "0x1", 0x12: "0x12", 0x123: "0x123"`.
function toMinimalHexString(uint256 value) internal pure returns (string memory str) {
str = toHexStringNoPrefix(value);
/// @solidity memory-safe-assembly
assembly {
let o := eq(byte(0, mload(add(str, 0x20))), 0x30) // Whether leading zero is present.
let strLength := add(mload(str), 2) // Compute the length.
mstore(add(str, o), 0x3078) // Write the "0x" prefix, accounting for leading zero.
str := sub(add(str, o), 2) // Move the pointer, accounting for leading zero.
mstore(str, sub(strLength, o)) // Write the length, accounting for leading zero.
}
}
/// @dev Returns the hexadecimal representation of `value`.
/// The output excludes leading "0" from the `toHexStringNoPrefix` output.
/// `0x00: "0", 0x01: "1", 0x12: "12", 0x123: "123"`.
function toMinimalHexStringNoPrefix(uint256 value) internal pure returns (string memory str) {
str = toHexStringNoPrefix(value);
/// @solidity memory-safe-assembly
assembly {
let o := eq(byte(0, mload(add(str, 0x20))), 0x30) // Whether leading zero is present.
let strLength := mload(str) // Get the length.
str := add(str, o) // Move the pointer, accounting for leading zero.
mstore(str, sub(strLength, o)) // Write the length, accounting for leading zero.
}
}
/// @dev Returns the hexadecimal representation of `value`.
/// The output is encoded using 2 hexadecimal digits per byte.
/// As address are 20 bytes long, the output will left-padded to have
/// a length of `20 * 2` bytes.
function toHexStringNoPrefix(uint256 value) internal pure returns (string memory str) {
/// @solidity memory-safe-assembly
assembly {
// We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length,
// 0x02 bytes for the prefix, and 0x40 bytes for the digits.
// The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x40) is 0xa0.
str := add(mload(0x40), 0x80)
// Allocate the memory.
mstore(0x40, add(str, 0x20))
// Zeroize the slot after the string.
mstore(str, 0)
// Cache the end to calculate the length later.
let end := str
// Store "0123456789abcdef" in scratch space.
mstore(0x0f, 0x30313233343536373839616263646566)
let w := not(1) // Tsk.
// We write the string from rightmost digit to leftmost digit.
// The following is essentially a do-while loop that also handles the zero case.
for { let temp := value } 1 {} {
str := add(str, w) // `sub(str, 2)`.
mstore8(add(str, 1), mload(and(temp, 15)))
mstore8(str, mload(and(shr(4, temp), 15)))
temp := shr(8, temp)
if iszero(temp) { break }
}
// Compute the string's length.
let strLength := sub(end, str)
// Move the pointer and write the length.
str := sub(str, 0x20)
mstore(str, strLength)
}
}
/// @dev Returns the hexadecimal representation of `value`.
/// The output is prefixed with "0x", encoded using 2 hexadecimal digits per byte,
/// and the alphabets are capitalized conditionally according to
/// https://eips.ethereum.org/EIPS/eip-55
function toHexStringChecksummed(address value) internal pure returns (string memory str) {
str = toHexString(value);
/// @solidity memory-safe-assembly
assembly {
let mask := shl(6, div(not(0), 255)) // `0b010000000100000000 ...`
let o := add(str, 0x22)
let hashed := and(keccak256(o, 40), mul(34, mask)) // `0b10001000 ... `
let t := shl(240, 136) // `0b10001000 << 240`
for { let i := 0 } 1 {} {
mstore(add(i, i), mul(t, byte(i, hashed)))
i := add(i, 1)
if eq(i, 20) { break }
}
mstore(o, xor(mload(o), shr(1, and(mload(0x00), and(mload(o), mask)))))
o := add(o, 0x20)
mstore(o, xor(mload(o), shr(1, and(mload(0x20), and(mload(o), mask)))))
}
}
/// @dev Returns the hexadecimal representation of `value`.
/// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte.
function toHexString(address value) internal pure returns (string memory str) {
str = toHexStringNoPrefix(value);
/// @solidity memory-safe-assembly
assembly {
let strLength := add(mload(str), 2) // Compute the length.
mstore(str, 0x3078) // Write the "0x" prefix.
str := sub(str, 2) // Move the pointer.
mstore(str, strLength) // Write the length.
}
}
/// @dev Returns the hexadecimal representation of `value`.
/// The output is encoded using 2 hexadecimal digits per byte.
function toHexStringNoPrefix(address value) internal pure returns (string memory str) {
/// @solidity memory-safe-assembly
assembly {
str := mload(0x40)
// Allocate the memory.
// We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length,
// 0x02 bytes for the prefix, and 0x28 bytes for the digits.
// The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x28) is 0x80.
mstore(0x40, add(str, 0x80))
// Store "0123456789abcdef" in scratch space.
mstore(0x0f, 0x30313233343536373839616263646566)
str := add(str, 2)
mstore(str, 40)
let o := add(str, 0x20)
mstore(add(o, 40), 0)
value := shl(96, value)
// We write the string from rightmost digit to leftmost digit.
// The following is essentially a do-while loop that also handles the zero case.
for { let i := 0 } 1 {} {
let p := add(o, add(i, i))
let temp := byte(i, value)
mstore8(add(p, 1), mload(and(temp, 15)))
mstore8(p, mload(shr(4, temp)))
i := add(i, 1)
if eq(i, 20) { break }
}
}
}
/// @dev Returns the hex encoded string from the raw bytes.
/// The output is encoded using 2 hexadecimal digits per byte.
function toHexString(bytes memory raw) internal pure returns (string memory str) {
str = toHexStringNoPrefix(raw);
/// @solidity memory-safe-assembly
assembly {
let strLength := add(mload(str), 2) // Compute the length.
mstore(str, 0x3078) // Write the "0x" prefix.
str := sub(str, 2) // Move the pointer.
mstore(str, strLength) // Write the length.
}
}
/// @dev Returns the hex encoded string from the raw bytes.
/// The output is encoded using 2 hexadecimal digits per byte.
function toHexStringNoPrefix(bytes memory raw) internal pure returns (string memory str) {
/// @solidity memory-safe-assembly
assembly {
let length := mload(raw)
str := add(mload(0x40), 2) // Skip 2 bytes for the optional prefix.
mstore(str, add(length, length)) // Store the length of the output.
// Store "0123456789abcdef" in scratch space.
mstore(0x0f, 0x30313233343536373839616263646566)
let o := add(str, 0x20)
let end := add(raw, length)
for {} iszero(eq(raw, end)) {} {
raw := add(raw, 1)
mstore8(add(o, 1), mload(and(mload(raw), 15)))
mstore8(o, mload(and(shr(4, mload(raw)), 15)))
o := add(o, 2)
}
mstore(o, 0) // Zeroize the slot after the string.
mstore(0x40, add(o, 0x20)) // Allocate the memory.
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* RUNE STRING OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the number of UTF characters in the string.
function runeCount(string memory s) internal pure returns (uint256 result) {
/// @solidity memory-safe-assembly
assembly {
if mload(s) {
mstore(0x00, div(not(0), 255))
mstore(0x20, 0x0202020202020202020202020202020202020202020202020303030304040506)
let o := add(s, 0x20)
let end := add(o, mload(s))
for { result := 1 } 1 { result := add(result, 1) } {
o := add(o, byte(0, mload(shr(250, mload(o)))))
if iszero(lt(o, end)) { break }
}
}
}
}
/// @dev Returns if this string is a 7-bit ASCII string.
/// (i.e. all characters codes are in [0..127])
function is7BitASCII(string memory s) internal pure returns (bool result) {
/// @solidity memory-safe-assembly
assembly {
let mask := shl(7, div(not(0), 255))
result := 1
let n := mload(s)
if n {
let o := add(s, 0x20)
let end := add(o, n)
let last := mload(end)
mstore(end, 0)
for {} 1 {} {
if and(mask, mload(o)) {
result := 0
break
}
o := add(o, 0x20)
if iszero(lt(o, end)) { break }
}
mstore(end, last)
}
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* BYTE STRING OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
// For performance and bytecode compactness, byte string operations are restricted
// to 7-bit ASCII strings. All offsets are byte offsets, not UTF character offsets.
// Usage of byte string operations on charsets with runes spanning two or more bytes
// can lead to undefined behavior.
/// @dev Returns `subject` all occurrences of `search` replaced with `replacement`.
function replace(string memory subject, string memory search, string memory replacement)
internal
pure
returns (string memory result)
{
/// @solidity memory-safe-assembly
assembly {
let subjectLength := mload(subject)
let searchLength := mload(search)
let replacementLength := mload(replacement)
subject := add(subject, 0x20)
search := add(search, 0x20)
replacement := add(replacement, 0x20)
result := add(mload(0x40), 0x20)
let subjectEnd := add(subject, subjectLength)
if iszero(gt(searchLength, subjectLength)) {
let subjectSearchEnd := add(sub(subjectEnd, searchLength), 1)
let h := 0
if iszero(lt(searchLength, 0x20)) { h := keccak256(search, searchLength) }
let m := shl(3, sub(0x20, and(searchLength, 0x1f)))
let s := mload(search)
for {} 1 {} {
let t := mload(subject)
// Whether the first `searchLength % 32` bytes of
// `subject` and `search` matches.
if iszero(shr(m, xor(t, s))) {
if h {
if iszero(eq(keccak256(subject, searchLength), h)) {
mstore(result, t)
result := add(result, 1)
subject := add(subject, 1)
if iszero(lt(subject, subjectSearchEnd)) { break }
continue
}
}
// Copy the `replacement` one word at a time.
for { let o := 0 } 1 {} {
mstore(add(result, o), mload(add(replacement, o)))
o := add(o, 0x20)
if iszero(lt(o, replacementLength)) { break }
}
result := add(result, replacementLength)
subject := add(subject, searchLength)
if searchLength {
if iszero(lt(subject, subjectSearchEnd)) { break }
continue
}
}
mstore(result, t)
result := add(result, 1)
subject := add(subject, 1)
if iszero(lt(subject, subjectSearchEnd)) { break }
}
}
let resultRemainder := result
result := add(mload(0x40), 0x20)
let k := add(sub(resultRemainder, result), sub(subjectEnd, subject))
// Copy the rest of the string one word at a time.
for {} lt(subject, subjectEnd) {} {
mstore(resultRemainder, mload(subject))
resultRemainder := add(resultRemainder, 0x20)
subject := add(subject, 0x20)
}
result := sub(result, 0x20)
let last := add(add(result, 0x20), k) // Zeroize the slot after the string.
mstore(last, 0)
mstore(0x40, add(last, 0x20)) // Allocate the memory.
mstore(result, k) // Store the length.
}
}
/// @dev Returns the byte index of the first location of `search` in `subject`,
/// searching from left to right, starting from `from`.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.
function indexOf(string memory subject, string memory search, uint256 from)
internal
pure
returns (uint256 result)
{
/// @solidity memory-safe-assembly
assembly {
for { let subjectLength := mload(subject) } 1 {} {
if iszero(mload(search)) {
if iszero(gt(from, subjectLength)) {
result := from
break
}
result := subjectLength
break
}
let searchLength := mload(search)
let subjectStart := add(subject, 0x20)
result := not(0) // Initialize to `NOT_FOUND`.
subject := add(subjectStart, from)
let end := add(sub(add(subjectStart, subjectLength), searchLength), 1)
let m := shl(3, sub(0x20, and(searchLength, 0x1f)))
let s := mload(add(search, 0x20))
if iszero(and(lt(subject, end), lt(from, subjectLength))) { break }
if iszero(lt(searchLength, 0x20)) {
for { let h := keccak256(add(search, 0x20), searchLength) } 1 {} {
if iszero(shr(m, xor(mload(subject), s))) {
if eq(keccak256(subject, searchLength), h) {
result := sub(subject, subjectStart)
break
}
}
subject := add(subject, 1)
if iszero(lt(subject, end)) { break }
}
break
}
for {} 1 {} {
if iszero(shr(m, xor(mload(subject), s))) {
result := sub(subject, subjectStart)
break
}
subject := add(subject, 1)
if iszero(lt(subject, end)) { break }
}
break
}
}
}
/// @dev Returns the byte index of the first location of `search` in `subject`,
/// searching from left to right.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.
function indexOf(string memory subject, string memory search)
internal
pure
returns (uint256 result)
{
result = indexOf(subject, search, 0);
}
/// @dev Returns the byte index of the first location of `search` in `subject`,
/// searching from right to left, starting from `from`.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.
function lastIndexOf(string memory subject, string memory search, uint256 from)
internal
pure
returns (uint256 result)
{
/// @solidity memory-safe-assembly
assembly {
for {} 1 {} {
result := not(0) // Initialize to `NOT_FOUND`.
let searchLength := mload(search)
if gt(searchLength, mload(subject)) { break }
let w := result
let fromMax := sub(mload(subject), searchLength)
if iszero(gt(fromMax, from)) { from := fromMax }
let end := add(add(subject, 0x20), w)
subject := add(add(subject, 0x20), from)
if iszero(gt(subject, end)) { break }
// As this function is not too often used,
// we shall simply use keccak256 for smaller bytecode size.
for { let h := keccak256(add(search, 0x20), searchLength) } 1 {} {
if eq(keccak256(subject, searchLength), h) {
result := sub(subject, add(end, 1))
break
}
subject := add(subject, w) // `sub(subject, 1)`.
if iszero(gt(subject, end)) { break }
}
break
}
}
}
/// @dev Returns the byte index of the first location of `search` in `subject`,
/// searching from right to left.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.
function lastIndexOf(string memory subject, string memory search)
internal
pure
returns (uint256 result)
{
result = lastIndexOf(subject, search, uint256(int256(-1)));
}
/// @dev Returns true if `search` is found in `subject`, false otherwise.
function contains(string memory subject, string memory search) internal pure returns (bool) {
return indexOf(subject, search) != NOT_FOUND;
}
/// @dev Returns whether `subject` starts with `search`.
function startsWith(string memory subject, string memory search)
internal
pure
returns (bool result)
{
/// @solidity memory-safe-assembly
assembly {
let searchLength := mload(search)
// Just using keccak256 directly is actually cheaper.
// forgefmt: disable-next-item
result := and(
iszero(gt(searchLength, mload(subject))),
eq(
keccak256(add(subject, 0x20), searchLength),
keccak256(add(search, 0x20), searchLength)
)
)
}
}
/// @dev Returns whether `subject` ends with `search`.
function endsWith(string memory subject, string memory search)
internal
pure
returns (bool result)
{
/// @solidity memory-safe-assembly
assembly {
let searchLength := mload(search)
let subjectLength := mload(subject)
// Whether `search` is not longer than `subject`.
let withinRange := iszero(gt(searchLength, subjectLength))
// Just using keccak256 directly is actually cheaper.
// forgefmt: disable-next-item
result := and(
withinRange,
eq(
keccak256(
// `subject + 0x20 + max(subjectLength - searchLength, 0)`.
add(add(subject, 0x20), mul(withinRange, sub(subjectLength, searchLength))),
searchLength
),
keccak256(add(search, 0x20), searchLength)
)
)
}
}
/// @dev Returns `subject` repeated `times`.
function repeat(string memory subject, uint256 times)
internal
pure
returns (string memory result)
{
/// @solidity memory-safe-assembly
assembly {
let subjectLength := mload(subject)
if iszero(or(iszero(times), iszero(subjectLength))) {
subject := add(subject, 0x20)
result := mload(0x40)
let output := add(result, 0x20)
for {} 1 {} {
// Copy the `subject` one word at a time.
for { let o := 0 } 1 {} {
mstore(add(output, o), mload(add(subject, o)))
o := add(o, 0x20)
if iszero(lt(o, subjectLength)) { break }
}
output := add(output, subjectLength)
times := sub(times, 1)
if iszero(times) { break }
}
mstore(output, 0) // Zeroize the slot after the string.
let resultLength := sub(output, add(result, 0x20))
mstore(result, resultLength) // Store the length.
// Allocate the memory.
mstore(0x40, add(result, add(resultLength, 0x20)))
}
}
}
/// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive).
/// `start` and `end` are byte offsets.
function slice(string memory subject, uint256 start, uint256 end)
internal
pure
returns (string memory result)
{
/// @solidity memory-safe-assembly
assembly {
let subjectLength := mload(subject)
if iszero(gt(subjectLength, end)) { end := subjectLength }
if iszero(gt(subjectLength, start)) { start := subjectLength }
if lt(start, end) {
result := mload(0x40)
let resultLength := sub(end, start)
mstore(result, resultLength)
subject := add(subject, start)
let w := not(0x1f)
// Copy the `subject` one word at a time, backwards.
for { let o := and(add(resultLength, 0x1f), w) } 1 {} {
mstore(add(result, o), mload(add(subject, o)))
o := add(o, w) // `sub(o, 0x20)`.
if iszero(o) { break }
}
// Zeroize the slot after the string.
mstore(add(add(result, 0x20), resultLength), 0)
// Allocate memory for the length and the bytes,
// rounded up to a multiple of 32.
mstore(0x40, add(result, and(add(resultLength, 0x3f), w)))
}
}
}
/// @dev Returns a copy of `subject` sliced from `start` to the end of the string.
/// `start` is a byte offset.
function slice(string memory subject, uint256 start)
internal
pure
returns (string memory result)
{
result = slice(subject, start, uint256(int256(-1)));
}
/// @dev Returns all the indices of `search` in `subject`.
/// The indices are byte offsets.
function indicesOf(string memory subject, string memory search)
internal
pure
returns (uint256[] memory result)
{
/// @solidity memory-safe-assembly
assembly {
let subjectLength := mload(subject)
let searchLength := mload(search)
if iszero(gt(searchLength, subjectLength)) {
subject := add(subject, 0x20)
search := add(search, 0x20)
result := add(mload(0x40), 0x20)
let subjectStart := subject
let subjectSearchEnd := add(sub(add(subject, subjectLength), searchLength), 1)
let h := 0
if iszero(lt(searchLength, 0x20)) { h := keccak256(search, searchLength) }
let m := shl(3, sub(0x20, and(searchLength, 0x1f)))
let s := mload(search)
for {} 1 {} {
let t := mload(subject)
// Whether the first `searchLength % 32` bytes of
// `subject` and `search` matches.
if iszero(shr(m, xor(t, s))) {
if h {
if iszero(eq(keccak256(subject, searchLength), h)) {
subject := add(subject, 1)
if iszero(lt(subject, subjectSearchEnd)) { break }
continue
}
}
// Append to `result`.
mstore(result, sub(subject, subjectStart))
result := add(result, 0x20)
// Advance `subject` by `searchLength`.
subject := add(subject, searchLength)
if searchLength {
if iszero(lt(subject, subjectSearchEnd)) { break }
continue
}
}
subject := add(subject, 1)
if iszero(lt(subject, subjectSearchEnd)) { break }
}
let resultEnd := result
// Assign `result` to the free memory pointer.
result := mload(0x40)
// Store the length of `result`.
mstore(result, shr(5, sub(resultEnd, add(result, 0x20))))
// Allocate memory for result.
// We allocate one more word, so this array can be recycled for {split}.
mstore(0x40, add(resultEnd, 0x20))
}
}
}
/// @dev Returns a arrays of strings based on the `delimiter` inside of the `subject` string.
function split(string memory subject, string memory delimiter)
internal
pure
returns (string[] memory result)
{
uint256[] memory indices = indicesOf(subject, delimiter);
/// @solidity memory-safe-assembly
assembly {
let w := not(0x1f)
let indexPtr := add(indices, 0x20)
let indicesEnd := add(indexPtr, shl(5, add(mload(indices), 1)))
mstore(add(indicesEnd, w), mload(subject))
mstore(indices, add(mload(indices), 1))
let prevIndex := 0
for {} 1 {} {
let index := mload(indexPtr)
mstore(indexPtr, 0x60)
if iszero(eq(index, prevIndex)) {
let element := mload(0x40)
let elementLength := sub(index, prevIndex)
mstore(element, elementLength)
// Copy the `subject` one word at a time, backwards.
for { let o := and(add(elementLength, 0x1f), w) } 1 {} {
mstore(add(element, o), mload(add(add(subject, prevIndex), o)))
o := add(o, w) // `sub(o, 0x20)`.
if iszero(o) { break }
}
// Zeroize the slot after the string.
mstore(add(add(element, 0x20), elementLength), 0)
// Allocate memory for the length and the bytes,
// rounded up to a multiple of 32.
mstore(0x40, add(element, and(add(elementLength, 0x3f), w)))
// Store the `element` into the array.
mstore(indexPtr, element)
}
prevIndex := add(index, mload(delimiter))
indexPtr := add(indexPtr, 0x20)
if iszero(lt(indexPtr, indicesEnd)) { break }
}
result := indices
if iszero(mload(delimiter)) {
result := add(indices, 0x20)
mstore(result, sub(mload(indices), 2))
}
}
}
/// @dev Returns a concatenated string of `a` and `b`.
/// Cheaper than `string.concat()` and does not de-align the free memory pointer.
function concat(string memory a, string memory b)
internal
pure
returns (string memory result)
{
/// @solidity memory-safe-assembly
assembly {
let w := not(0x1f)
result := mload(0x40)
let aLength := mload(a)
// Copy `a` one word at a time, backwards.
for { let o := and(add(aLength, 0x20), w) } 1 {} {
mstore(add(result, o), mload(add(a, o)))
o := add(o, w) // `sub(o, 0x20)`.
if iszero(o) { break }
}
let bLength := mload(b)
let output := add(result, aLength)
// Copy `b` one word at a time, backwards.
for { let o := and(add(bLength, 0x20), w) } 1 {} {
mstore(add(output, o), mload(add(b, o)))
o := add(o, w) // `sub(o, 0x20)`.
if iszero(o) { break }
}
let totalLength := add(aLength, bLength)
let last := add(add(result, 0x20), totalLength)
// Zeroize the slot after the string.
mstore(last, 0)
// Stores the length.
mstore(result, totalLength)
// Allocate memory for the length and the bytes,
// rounded up to a multiple of 32.
mstore(0x40, and(add(last, 0x1f), w))
}
}
/// @dev Returns a copy of the string in either lowercase or UPPERCASE.
/// WARNING! This function is only compatible with 7-bit ASCII strings.
function toCase(string memory subject, bool toUpper)
internal
pure
returns (string memory result)
{
/// @solidity memory-safe-assembly
assembly {
let length := mload(subject)
if length {
result := add(mload(0x40), 0x20)
subject := add(subject, 1)
let flags := shl(add(70, shl(5, toUpper)), 0x3ffffff)
let w := not(0)
for { let o := length } 1 {} {
o := add(o, w)
let b := and(0xff, mload(add(subject, o)))
mstore8(add(result, o), xor(b, and(shr(b, flags), 0x20)))
if iszero(o) { break }
}
result := mload(0x40)
mstore(result, length) // Store the length.
let last := add(add(result, 0x20), length)
mstore(last, 0) // Zeroize the slot after the string.
mstore(0x40, add(last, 0x20)) // Allocate the memory.
}
}
}
/// @dev Returns a string from a small bytes32 string.
/// `s` must be null-terminated, or behavior will be undefined.
function fromSmallString(bytes32 s) internal pure returns (string memory result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40)
let n := 0
for {} byte(n, s) { n := add(n, 1) } {} // Scan for '\0'.
mstore(result, n)
let o := add(result, 0x20)
mstore(o, s)
mstore(add(o, n), 0)
mstore(0x40, add(result, 0x40))
}
}
/// @dev Returns the small string, with all bytes after the first null byte zeroized.
function normalizeSmallString(bytes32 s) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
for {} byte(result, s) { result := add(result, 1) } {} // Scan for '\0'.
mstore(0x00, s)
mstore(result, 0x00)
result := mload(0x00)
}
}
/// @dev Returns the string as a normalized null-terminated small string.
function toSmallString(string memory s) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(s)
if iszero(lt(result, 33)) {
mstore(0x00, 0xec92f9a3) // `TooBigForSmallString()`.
revert(0x1c, 0x04)
}
result := shl(shl(3, sub(32, result)), mload(add(s, result)))
}
}
/// @dev Returns a lowercased copy of the string.
/// WARNING! This function is only compatible with 7-bit ASCII strings.
function lower(string memory subject) internal pure returns (string memory result) {
result = toCase(subject, false);
}
/// @dev Returns an UPPERCASED copy of the string.
/// WARNING! This function is only compatible with 7-bit ASCII strings.
function upper(string memory subject) internal pure returns (string memory result) {
result = toCase(subject, true);
}
/// @dev Escapes the string to be used within HTML tags.
function escapeHTML(string memory s) internal pure returns (string memory result) {
/// @solidity memory-safe-assembly
assembly {
let end := add(s, mload(s))
result := add(mload(0x40), 0x20)
// Store the bytes of the packed offsets and strides into the scratch space.
// `packed = (stride << 5) | offset`. Max offset is 20. Max stride is 6.
mstore(0x1f, 0x900094)
mstore(0x08, 0xc0000000a6ab)
// Store ""&'<>" into the scratch space.
mstore(0x00, shl(64, 0x2671756f743b26616d703b262333393b266c743b2667743b))
for {} iszero(eq(s, end)) {} {
s := add(s, 1)
let c := and(mload(s), 0xff)
// Not in `["\"","'","&","<",">"]`.
if iszero(and(shl(c, 1), 0x500000c400000000)) {
mstore8(result, c)
result := add(result, 1)
continue
}
let t := shr(248, mload(c))
mstore(result, mload(and(t, 0x1f)))
result := add(result, shr(5, t))
}
let last := result
mstore(last, 0) // Zeroize the slot after the string.
result := mload(0x40)
mstore(result, sub(last, add(result, 0x20))) // Store the length.
mstore(0x40, add(last, 0x20)) // Allocate the memory.
}
}
/// @dev Escapes the string to be used within double-quotes in a JSON.
/// If `addDoubleQuotes` is true, the result will be enclosed in double-quotes.
function escapeJSON(string memory s, bool addDoubleQuotes)
internal
pure
returns (string memory result)
{
/// @solidity memory-safe-assembly
assembly {
let end := add(s, mload(s))
result := add(mload(0x40), 0x20)
if addDoubleQuotes {
mstore8(result, 34)
result := add(1, result)
}
// Store "\\u0000" in scratch space.
// Store "0123456789abcdef" in scratch space.
// Also, store `{0x08:"b", 0x09:"t", 0x0a:"n", 0x0c:"f", 0x0d:"r"}`.
// into the scratch space.
mstore(0x15, 0x5c75303030303031323334353637383961626364656662746e006672)
// Bitmask for detecting `["\"","\\"]`.
let e := or(shl(0x22, 1), shl(0x5c, 1))
for {} iszero(eq(s, end)) {} {
s := add(s, 1)
let c := and(mload(s), 0xff)
if iszero(lt(c, 0x20)) {
if iszero(and(shl(c, 1), e)) {
// Not in `["\"","\\"]`.
mstore8(result, c)
result := add(result, 1)
continue
}
mstore8(result, 0x5c) // "\\".
mstore8(add(result, 1), c)
result := add(result, 2)
continue
}
if iszero(and(shl(c, 1), 0x3700)) {
// Not in `["\b","\t","\n","\f","\d"]`.
mstore8(0x1d, mload(shr(4, c))) // Hex value.
mstore8(0x1e, mload(and(c, 15))) // Hex value.
mstore(result, mload(0x19)) // "\\u00XX".
result := add(result, 6)
continue
}
mstore8(result, 0x5c) // "\\".
mstore8(add(result, 1), mload(add(c, 8)))
result := add(result, 2)
}
if addDoubleQuotes {
mstore8(result, 34)
result := add(1, result)
}
let last := result
mstore(last, 0) // Zeroize the slot after the string.
result := mload(0x40)
mstore(result, sub(last, add(result, 0x20))) // Store the length.
mstore(0x40, add(last, 0x20)) // Allocate the memory.
}
}
/// @dev Escapes the string to be used within double-quotes in a JSON.
function escapeJSON(string memory s) internal pure returns (string memory result) {
result = escapeJSON(s, false);
}
/// @dev Returns whether `a` equals `b`.
function eq(string memory a, string memory b) internal pure returns (bool result) {
/// @solidity memory-safe-assembly
assembly {
result := eq(keccak256(add(a, 0x20), mload(a)), keccak256(add(b, 0x20), mload(b)))
}
}
/// @dev Returns whether `a` equals `b`, where `b` is a null-terminated small string.
function eqs(string memory a, bytes32 b) internal pure returns (bool result) {
/// @solidity memory-safe-assembly
assembly {
// These should be evaluated on compile time, as far as possible.
let m := not(shl(7, div(not(iszero(b)), 255))) // `0x7f7f ...`.
let x := not(or(m, or(b, add(m, and(b, m)))))
let r := shl(7, iszero(iszero(shr(128, x))))
r := or(r, shl(6, iszero(iszero(shr(64, shr(r, x))))))
r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffff, shr(r, x))))
r := or(r, shl(3, lt(0xff, shr(r, x))))
// forgefmt: disable-next-item
result := gt(eq(mload(a), add(iszero(x), xor(31, shr(3, r)))),
xor(shr(add(8, r), b), shr(add(8, r), mload(add(a, 0x20)))))
}
}
/// @dev Packs a single string with its length into a single word.
/// Returns `bytes32(0)` if the length is zero or greater than 31.
function packOne(string memory a) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
// We don't need to zero right pad the string,
// since this is our own custom non-standard packing scheme.
result :=
mul(
// Load the length and the bytes.
mload(add(a, 0x1f)),
// `length != 0 && length < 32`. Abuses underflow.
// Assumes that the length is valid and within the block gas limit.
lt(sub(mload(a), 1), 0x1f)
)
}
}
/// @dev Unpacks a string packed using {packOne}.
/// Returns the empty string if `packed` is `bytes32(0)`.
/// If `packed` is not an output of {packOne}, the output behavior is undefined.
function unpackOne(bytes32 packed) internal pure returns (string memory result) {
/// @solidity memory-safe-assembly
assembly {
// Grab the free memory pointer.
result := mload(0x40)
// Allocate 2 words (1 for the length, 1 for the bytes).
mstore(0x40, add(result, 0x40))
// Zeroize the length slot.
mstore(result, 0)
// Store the length and bytes.
mstore(add(result, 0x1f), packed)
// Right pad with zeroes.
mstore(add(add(result, 0x20), mload(result)), 0)
}
}
/// @dev Packs two strings with their lengths into a single word.
/// Returns `bytes32(0)` if combined length is zero or greater than 30.
function packTwo(string memory a, string memory b) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let aLength := mload(a)
// We don't need to zero right pad the strings,
// since this is our own custom non-standard packing scheme.
result :=
mul(
// Load the length and the bytes of `a` and `b`.
or(
shl(shl(3, sub(0x1f, aLength)), mload(add(a, aLength))),
mload(sub(add(b, 0x1e), aLength))
),
// `totalLength != 0 && totalLength < 31`. Abuses underflow.
// Assumes that the lengths are valid and within the block gas limit.
lt(sub(add(aLength, mload(b)), 1), 0x1e)
)
}
}
/// @dev Unpacks strings packed using {packTwo}.
/// Returns the empty strings if `packed` is `bytes32(0)`.
/// If `packed` is not an output of {packTwo}, the output behavior is undefined.
function unpackTwo(bytes32 packed)
internal
pure
returns (string memory resultA, string memory resultB)
{
/// @solidity memory-safe-assembly
assembly {
// Grab the free memory pointer.
resultA := mload(0x40)
resultB := add(resultA, 0x40)
// Allocate 2 words for each string (1 for the length, 1 for the byte). Total 4 words.
mstore(0x40, add(resultB, 0x40))
// Zeroize the length slots.
mstore(resultA, 0)
mstore(resultB, 0)
// Store the lengths and bytes.
mstore(add(resultA, 0x1f), packed)
mstore(add(resultB, 0x1f), mload(add(add(resultA, 0x20), mload(resultA))))
// Right pad with zeroes.
mstore(add(add(resultA, 0x20), mload(resultA)), 0)
mstore(add(add(resultB, 0x20), mload(resultB)), 0)
}
}
/// @dev Directly returns `a` without copying.
function directReturn(string memory a) internal pure {
assembly {
// Assumes that the string does not start from the scratch space.
let retStart := sub(a, 0x20)
let retSize := add(mload(a), 0x40)
// Right pad with zeroes. Just in case the string is produced
// by a method that doesn't zero right pad.
mstore(add(retStart, retSize), 0)
// Store the return offset.
mstore(retStart, 0x20)
// End the transaction, returning the string.
return(retStart, retSize)
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @title Types
/// @notice Contains various types used throughout the Optimism contract system.
library Types {
/// @notice OutputProposal represents a commitment to the L2 state. The timestamp is the L1
/// timestamp that the output root is posted. This timestamp is used to verify that the
/// finalization period has passed since the output root was submitted.
/// @custom:field outputRoot Hash of the L2 output.
/// @custom:field timestamp Timestamp of the L1 block that the output root was submitted in.
/// @custom:field l2BlockNumber L2 block number that the output corresponds to.
struct OutputProposal {
bytes32 outputRoot;
uint128 timestamp;
uint128 l2BlockNumber;
}
/// @notice Struct representing the elements that are hashed together to generate an output root
/// which itself represents a snapshot of the L2 state.
/// @custom:field version Version of the output root.
/// @custom:field stateRoot Root of the state trie at the block of this output.
/// @custom:field messagePasserStorageRoot Root of the message passer storage trie.
/// @custom:field latestBlockhash Hash of the block this output was generated from.
struct OutputRootProof {
bytes32 version;
bytes32 stateRoot;
bytes32 messagePasserStorageRoot;
bytes32 latestBlockhash;
}
/// @notice Struct representing a deposit transaction (L1 => L2 transaction) created by an end
/// user (as opposed to a system deposit transaction generated by the system).
/// @custom:field from Address of the sender of the transaction.
/// @custom:field to Address of the recipient of the transaction.
/// @custom:field isCreation True if the transaction is a contract creation.
/// @custom:field value Value to send to the recipient.
/// @custom:field mint Amount of ETH to mint.
/// @custom:field gasLimit Gas limit of the transaction.
/// @custom:field data Data of the transaction.
/// @custom:field l1BlockHash Hash of the block the transaction was submitted in.
/// @custom:field logIndex Index of the log in the block the transaction was submitted in.
struct UserDepositTransaction {
address from;
address to;
bool isCreation;
uint256 value;
uint256 mint;
uint64 gasLimit;
bytes data;
bytes32 l1BlockHash;
uint256 logIndex;
}
/// @notice Struct representing a withdrawal transaction.
/// @custom:field nonce Nonce of the withdrawal transaction
/// @custom:field sender Address of the sender of the transaction.
/// @custom:field target Address of the recipient of the transaction.
/// @custom:field value Value to send to the recipient.
/// @custom:field gasLimit Gas limit of the transaction.
/// @custom:field data Data of the transaction.
struct WithdrawalTransaction {
uint256 nonce;
address sender;
address target;
uint256 value;
uint256 gasLimit;
bytes data;
}
/// @notice Enum representing where the FeeVault withdraws funds to.
/// @custom:value L1 FeeVault withdraws funds to L1.
/// @custom:value L2 FeeVault withdraws funds to L2.
enum WithdrawalNetwork {
L1,
L2
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { IResourceMetering } from "src/L1/interfaces/IResourceMetering.sol";
/// @notice This interface corresponds to the Custom Gas Token version of the SystemConfig contract.
interface ISystemConfig {
enum UpdateType {
BATCHER,
FEE_SCALARS,
GAS_LIMIT,
UNSAFE_BLOCK_SIGNER,
EIP_1559_PARAMS
}
struct Addresses {
address l1CrossDomainMessenger;
address l1ERC721Bridge;
address l1StandardBridge;
address disputeGameFactory;
address optimismPortal;
address optimismMintableERC20Factory;
address gasPayingToken;
}
event ConfigUpdate(uint256 indexed version, UpdateType indexed updateType, bytes data);
event Initialized(uint8 version);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
function BATCH_INBOX_SLOT() external view returns (bytes32);
function DISPUTE_GAME_FACTORY_SLOT() external view returns (bytes32);
function L1_CROSS_DOMAIN_MESSENGER_SLOT() external view returns (bytes32);
function L1_ERC_721_BRIDGE_SLOT() external view returns (bytes32);
function L1_STANDARD_BRIDGE_SLOT() external view returns (bytes32);
function OPTIMISM_MINTABLE_ERC20_FACTORY_SLOT() external view returns (bytes32);
function OPTIMISM_PORTAL_SLOT() external view returns (bytes32);
function START_BLOCK_SLOT() external view returns (bytes32);
function UNSAFE_BLOCK_SIGNER_SLOT() external view returns (bytes32);
function VERSION() external view returns (uint256);
function basefeeScalar() external view returns (uint32);
function batchInbox() external view returns (address addr_);
function batcherHash() external view returns (bytes32);
function blobbasefeeScalar() external view returns (uint32);
function disputeGameFactory() external view returns (address addr_);
function gasLimit() external view returns (uint64);
function eip1559Denominator() external view returns (uint32);
function eip1559Elasticity() external view returns (uint32);
function gasPayingToken() external view returns (address addr_, uint8 decimals_);
function gasPayingTokenName() external view returns (string memory name_);
function gasPayingTokenSymbol() external view returns (string memory symbol_);
function initialize(
address _owner,
uint32 _basefeeScalar,
uint32 _blobbasefeeScalar,
bytes32 _batcherHash,
uint64 _gasLimit,
address _unsafeBlockSigner,
IResourceMetering.ResourceConfig memory _config,
address _batchInbox,
Addresses memory _addresses
)
external;
function isCustomGasToken() external view returns (bool);
function l1CrossDomainMessenger() external view returns (address addr_);
function l1ERC721Bridge() external view returns (address addr_);
function l1StandardBridge() external view returns (address addr_);
function maximumGasLimit() external pure returns (uint64);
function minimumGasLimit() external view returns (uint64);
function optimismMintableERC20Factory() external view returns (address addr_);
function optimismPortal() external view returns (address addr_);
function overhead() external view returns (uint256);
function owner() external view returns (address);
function renounceOwnership() external;
function resourceConfig() external view returns (IResourceMetering.ResourceConfig memory);
function scalar() external view returns (uint256);
function setBatcherHash(bytes32 _batcherHash) external;
function setGasConfig(uint256 _overhead, uint256 _scalar) external;
function setGasConfigEcotone(uint32 _basefeeScalar, uint32 _blobbasefeeScalar) external;
function setGasLimit(uint64 _gasLimit) external;
function setUnsafeBlockSigner(address _unsafeBlockSigner) external;
function setEIP1559Params(uint32 _denominator, uint32 _elasticity) external;
function startBlock() external view returns (uint256 startBlock_);
function transferOwnership(address newOwner) external; // nosemgrep
function unsafeBlockSigner() external view returns (address addr_);
function version() external pure returns (string memory);
function __constructor__() external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface ISuperchainConfig {
enum UpdateType {
GUARDIAN
}
event ConfigUpdate(UpdateType indexed updateType, bytes data);
event Initialized(uint8 version);
event Paused(string identifier);
event Unpaused();
function GUARDIAN_SLOT() external view returns (bytes32);
function PAUSED_SLOT() external view returns (bytes32);
function guardian() external view returns (address guardian_);
function initialize(address _guardian, bool _paused) external;
function pause(string memory _identifier) external;
function paused() external view returns (bool paused_);
function unpause() external;
function version() external view returns (string memory);
function __constructor__() external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { Types } from "src/libraries/Types.sol";
interface IL2OutputOracle {
event Initialized(uint8 version);
event OutputProposed(
bytes32 indexed outputRoot, uint256 indexed l2OutputIndex, uint256 indexed l2BlockNumber, uint256 l1Timestamp
);
event OutputsDeleted(uint256 indexed prevNextOutputIndex, uint256 indexed newNextOutputIndex);
function CHALLENGER() external view returns (address);
function FINALIZATION_PERIOD_SECONDS() external view returns (uint256);
function L2_BLOCK_TIME() external view returns (uint256);
function PROPOSER() external view returns (address);
function SUBMISSION_INTERVAL() external view returns (uint256);
function challenger() external view returns (address);
function computeL2Timestamp(uint256 _l2BlockNumber) external view returns (uint256);
function deleteL2Outputs(uint256 _l2OutputIndex) external;
function finalizationPeriodSeconds() external view returns (uint256);
function getL2Output(uint256 _l2OutputIndex) external view returns (Types.OutputProposal memory);
function getL2OutputAfter(uint256 _l2BlockNumber) external view returns (Types.OutputProposal memory);
function getL2OutputIndexAfter(uint256 _l2BlockNumber) external view returns (uint256);
function initialize(
uint256 _submissionInterval,
uint256 _l2BlockTime,
uint256 _startingBlockNumber,
uint256 _startingTimestamp,
address _proposer,
address _challenger,
uint256 _finalizationPeriodSeconds
)
external;
function l2BlockTime() external view returns (uint256);
function latestBlockNumber() external view returns (uint256);
function latestOutputIndex() external view returns (uint256);
function nextBlockNumber() external view returns (uint256);
function nextOutputIndex() external view returns (uint256);
function proposeL2Output(
bytes32 _outputRoot,
uint256 _l2BlockNumber,
bytes32 _l1BlockHash,
uint256 _l1BlockNumber
)
external
payable;
function proposer() external view returns (address);
function startingBlockNumber() external view returns (uint256);
function startingTimestamp() external view returns (uint256);
function submissionInterval() external view returns (uint256);
function version() external view returns (string memory);
function __constructor__() external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library AddressUpgradeable {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}{
"remappings": [
"@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
"@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
"@openzeppelin/contracts-v5/=lib/openzeppelin-contracts-v5/contracts/",
"@rari-capital/solmate/=lib/solmate/",
"@lib-keccak/=lib/lib-keccak/contracts/lib/",
"@solady/=lib/solady/src/",
"@solady-v0.0.245/=lib/solady-v0.0.245/src/",
"forge-std/=lib/forge-std/src/",
"ds-test/=lib/forge-std/lib/ds-test/src/",
"safe-contracts/=lib/safe-contracts/contracts/",
"kontrol-cheatcodes/=lib/kontrol-cheatcodes/src/",
"gelato/=lib/automate/contracts/",
"@solady-test/=lib/lib-keccak/lib/solady/test/",
"automate/=lib/automate/contracts/",
"erc4626-tests/=lib/openzeppelin-contracts-v5/lib/erc4626-tests/",
"hardhat/=lib/automate/node_modules/hardhat/",
"lib-keccak/=lib/lib-keccak/contracts/",
"openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
"openzeppelin-contracts-v5/=lib/openzeppelin-contracts-v5/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/",
"prb-test/=lib/automate/lib/prb-test/src/",
"prb/-est/=lib/automate/lib/prb-test/src/",
"solady-v0.0.245/=lib/solady-v0.0.245/src/",
"solady/=lib/solady/",
"solmate/=lib/solmate/src/"
],
"optimizer": {
"enabled": true,
"runs": 999999
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "none"
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "london",
"viaIR": false,
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"version","type":"uint256"},{"indexed":true,"internalType":"enum SystemConfig.UpdateType","name":"updateType","type":"uint8"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"}],"name":"ConfigUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[],"name":"BATCH_INBOX_SLOT","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DISPUTE_GAME_FACTORY_SLOT","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"L1_CROSS_DOMAIN_MESSENGER_SLOT","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"L1_ERC_721_BRIDGE_SLOT","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"L1_STANDARD_BRIDGE_SLOT","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"OPTIMISM_MINTABLE_ERC20_FACTORY_SLOT","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"OPTIMISM_PORTAL_SLOT","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"START_BLOCK_SLOT","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UNSAFE_BLOCK_SIGNER_SLOT","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VERSION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"basefeeScalar","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"batchInbox","outputs":[{"internalType":"address","name":"addr_","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"batcherHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"blobbasefeeScalar","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"disputeGameFactory","outputs":[{"internalType":"address","name":"addr_","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"eip1559Denominator","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"eip1559Elasticity","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gasLimit","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gasPayingToken","outputs":[{"internalType":"address","name":"addr_","type":"address"},{"internalType":"uint8","name":"decimals_","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gasPayingTokenName","outputs":[{"internalType":"string","name":"name_","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gasPayingTokenSymbol","outputs":[{"internalType":"string","name":"symbol_","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"uint32","name":"_basefeeScalar","type":"uint32"},{"internalType":"uint32","name":"_blobbasefeeScalar","type":"uint32"},{"internalType":"bytes32","name":"_batcherHash","type":"bytes32"},{"internalType":"uint64","name":"_gasLimit","type":"uint64"},{"internalType":"address","name":"_unsafeBlockSigner","type":"address"},{"components":[{"internalType":"uint32","name":"maxResourceLimit","type":"uint32"},{"internalType":"uint8","name":"elasticityMultiplier","type":"uint8"},{"internalType":"uint8","name":"baseFeeMaxChangeDenominator","type":"uint8"},{"internalType":"uint32","name":"minimumBaseFee","type":"uint32"},{"internalType":"uint32","name":"systemTxMaxGas","type":"uint32"},{"internalType":"uint128","name":"maximumBaseFee","type":"uint128"}],"internalType":"struct IResourceMetering.ResourceConfig","name":"_config","type":"tuple"},{"internalType":"address","name":"_batchInbox","type":"address"},{"components":[{"internalType":"address","name":"l1CrossDomainMessenger","type":"address"},{"internalType":"address","name":"l1ERC721Bridge","type":"address"},{"internalType":"address","name":"l1StandardBridge","type":"address"},{"internalType":"address","name":"disputeGameFactory","type":"address"},{"internalType":"address","name":"optimismPortal","type":"address"},{"internalType":"address","name":"optimismMintableERC20Factory","type":"address"},{"internalType":"address","name":"gasPayingToken","type":"address"}],"internalType":"struct SystemConfig.Addresses","name":"_addresses","type":"tuple"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isCustomGasToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"l1CrossDomainMessenger","outputs":[{"internalType":"address","name":"addr_","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"l1ERC721Bridge","outputs":[{"internalType":"address","name":"addr_","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"l1StandardBridge","outputs":[{"internalType":"address","name":"addr_","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maximumGasLimit","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"minimumGasLimit","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"optimismMintableERC20Factory","outputs":[{"internalType":"address","name":"addr_","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"optimismPortal","outputs":[{"internalType":"address","name":"addr_","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"overhead","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"resourceConfig","outputs":[{"components":[{"internalType":"uint32","name":"maxResourceLimit","type":"uint32"},{"internalType":"uint8","name":"elasticityMultiplier","type":"uint8"},{"internalType":"uint8","name":"baseFeeMaxChangeDenominator","type":"uint8"},{"internalType":"uint32","name":"minimumBaseFee","type":"uint32"},{"internalType":"uint32","name":"systemTxMaxGas","type":"uint32"},{"internalType":"uint128","name":"maximumBaseFee","type":"uint128"}],"internalType":"struct IResourceMetering.ResourceConfig","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"scalar","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_batcherHash","type":"bytes32"}],"name":"setBatcherHash","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_denominator","type":"uint32"},{"internalType":"uint32","name":"_elasticity","type":"uint32"}],"name":"setEIP1559Params","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_overhead","type":"uint256"},{"internalType":"uint256","name":"_scalar","type":"uint256"}],"name":"setGasConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_basefeeScalar","type":"uint32"},{"internalType":"uint32","name":"_blobbasefeeScalar","type":"uint32"}],"name":"setGasConfigEcotone","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"_gasLimit","type":"uint64"}],"name":"setGasLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_unsafeBlockSigner","type":"address"}],"name":"setUnsafeBlockSigner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"startBlock","outputs":[{"internalType":"uint256","name":"startBlock_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unsafeBlockSigner","outputs":[{"internalType":"address","name":"addr_","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"}]Contract Creation Code
60806040523480156200001157600080fd5b506200004962000032600160008051602062003f2783398151915262001203565b60001b600019620000d160201b620010341760201c565b6040805160c080820183526001808352602080840182905260028486015260006060808601829052608080870183905260a0808801849052885160e081018a528481529485018490529784018390529083018290528201819052948101859052918201849052620000cb9361dead9390928392839290918391908290620000d5565b6200142c565b9055565b600054610100900460ff1615808015620000f65750600054600160ff909116105b806200012657506200011330620004e660201b620010381760201c565b15801562000126575060005460ff166001145b6200018f5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff191660011790558015620001b3576000805461ff0019166101001790555b620001bd620004f5565b620001c88a6200055d565b620001d387620005dc565b620001df89896200062e565b620001ea86620006f5565b620002217f65a7ed542fb37fe237fdfbdd70b31598523fe5b32879e307bae27a0bd9581c0886620000d160201b620010341760201c565b620002676200025260017f71ac12829d66ee73d8d95bff50b3589745ce57edae70a3fb111a2342464dc59862001203565b60001b84620000d160201b620010341760201c565b620002b16200029860017f383f291819e6d54073bc9a648251d97421076bdd101933c0c022219ce958063762001203565b60001b8360000151620000d160201b620010341760201c565b620002fb620002e260017f46adcbebc6be8ce551740c29c47c8798210f23f7f4086c41752944352568d5a862001203565b60001b8360200151620000d160201b620010341760201c565b620003456200032c60017f9904ba90dde5696cda05c9e0dab5cbaa0fea005ace4d11218a02ac668dad637762001203565b60001b8360400151620000d160201b620010341760201c565b6200038f6200037660017f52322a25d9f59ea17656545543306b7aef62bc0cc53a0e65ccfa0c75b97aa90762001203565b60001b8360600151620000d160201b620010341760201c565b620003c8620003af600160008051602062003f0783398151915262001203565b60001b8360800151620000d160201b620010341760201c565b62000412620003f960017fa04c5bb938ca6fc46d95553abf0a76345ce3e722a30bf4f74928b8e7d852320d62001203565b60001b8360a00151620000d160201b620010341760201c565b6200041c620007f1565b60c08201516200042c9062000862565b620004378462000aeb565b6200044162000e2f565b6001600160401b0316866001600160401b03161015620004935760405162461bcd60e51b815260206004820152601f602482015260008051602062003ea7833981519152604482015260640162000186565b8015620004da576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050505050565b6001600160a01b03163b151590565b600054610100900460ff16620005515760405162461bcd60e51b815260206004820152602b602482015260008051602062003ee783398151915260448201526a6e697469616c697a696e6760a81b606482015260840162000186565b6200055b62000e5c565b565b6200056762000ec3565b6001600160a01b038116620005ce5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840162000186565b620005d98162000f1f565b50565b60678190556040805160208082018490528251808303909101815290820190915260005b600060008051602062003ec7833981519152836040516200062291906200124c565b60405180910390a35050565b60688054600160401b600160801b0319166801000000000000000063ffffffff85811691820263ffffffff60601b1916929092176c010000000000000000000000009285169290920291909117909155600160f81b602083811b67ffffffff0000000016909217176066819055606554604080519384019190915282015260009060600160408051601f1981840301815291905290506001600060008051602062003ec783398151915283604051620006e891906200124c565b60405180910390a3505050565b620006ff62000e2f565b6001600160401b0316816001600160401b03161015620007515760405162461bcd60e51b815260206004820152601f602482015260008051602062003ea7833981519152604482015260640162000186565b630bebc2006001600160401b0382161115620007b05760405162461bcd60e51b815260206004820181905260248201527f53797374656d436f6e6669673a20676173206c696d697420746f6f2068696768604482015260640162000186565b606880546001600160401b0319166001600160401b038316908117909155604080516020808201939093528151808203909301835281019052600262000600565b6200082562000811600160008051602062003f2783398151915262001203565b60001b62000f7160201b620007b41760201c565b6000036200055b576200055b6200084d600160008051602062003f2783398151915262001203565b60001b43620000d160201b620010341760201c565b6001600160a01b038116158015906200089857506001600160a01b03811673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14155b8015620008ac5750620008aa62000f75565b155b15620005d957601260ff16816001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015620008f6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200091c919062001281565b60ff1614620009855760405162461bcd60e51b815260206004820152602e60248201527f53797374656d436f6e6669673a2062616420646563696d616c73206f6620676160448201526d39903830bcb4b733903a37b5b2b760911b606482015260840162000186565b600062000a05826001600160a01b03166306fdde036040518163ffffffff1660e01b8152600401600060405180830381865afa158015620009ca573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052620009f49190810190620012c3565b62000fa960201b620010541760201c565b9050600062000a4c836001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015620009ca573d6000803e3d6000fd5b905062000a6883601284846200104160201b620010f71760201c565b62000a726200111d565b6040516371cfaa3f60e01b81526001600160a01b03858116600483015260126024830152604482018590526064820184905291909116906371cfaa3f90608401600060405180830381600087803b15801562000acd57600080fd5b505af115801562000ae2573d6000803e3d6000fd5b50505050505050565b8060a001516001600160801b0316816060015163ffffffff16111562000b7a5760405162461bcd60e51b815260206004820152603560248201527f53797374656d436f6e6669673a206d696e206261736520666565206d7573742060448201527f6265206c657373207468616e206d617820626173650000000000000000000000606482015260840162000186565b6001816040015160ff161162000beb5760405162461bcd60e51b815260206004820152602f60248201527f53797374656d436f6e6669673a2064656e6f6d696e61746f72206d757374206260448201526e65206c6172676572207468616e203160881b606482015260840162000186565b606854608082015182516001600160401b039092169162000c0d91906200137b565b63ffffffff16111562000c525760405162461bcd60e51b815260206004820152601f602482015260008051602062003ea7833981519152604482015260640162000186565b6000816020015160ff161162000cc35760405162461bcd60e51b815260206004820152602f60248201527f53797374656d436f6e6669673a20656c6173746963697479206d756c7469706c60448201526e06965722063616e6e6f74206265203608c1b606482015260840162000186565b8051602082015163ffffffff82169160ff9091169062000ce5908290620013a6565b62000cf19190620013d8565b63ffffffff161462000d6c5760405162461bcd60e51b815260206004820152603760248201527f53797374656d436f6e6669673a20707265636973696f6e206c6f73732077697460448201527f6820746172676574207265736f75726365206c696d6974000000000000000000606482015260840162000186565b805160698054602084015160408501516060860151608087015160a09097015163ffffffff96871664ffffffffff199095169490941764010000000060ff948516021764ffffffffff60281b191665010000000000939092169290920263ffffffff60301b19161766010000000000009185169190910217600160501b600160f01b0319166a01000000000000000000009390941692909202600160701b600160f01b03191692909217600160701b6001600160801b0390921691909102179055565b60695460009062000e579063ffffffff6a010000000000000000000082048116911662001407565b905090565b600054610100900460ff1662000eb85760405162461bcd60e51b815260206004820152602b602482015260008051602062003ee783398151915260448201526a6e697469616c697a696e6760a81b606482015260840162000186565b6200055b3362000f1f565b6033546001600160a01b031633146200055b5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640162000186565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b5490565b60008062000f826200113f565b506001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee141592915050565b6000602082511115620010255760405162461bcd60e51b815260206004820152603660248201527f476173506179696e67546f6b656e3a20737472696e672063616e6e6f7420626560448201527f2067726561746572207468616e20333220627974657300000000000000000000606482015260840162000186565b6200103b826200116060201b620011c91760201c565b92915050565b6200108b62001061600160008051602062003e8783398151915262001203565b60001b856001600160a01b031660a08660ff16901b1760001b620000d160201b620010341760201c565b620010d1620010bc60017f657c3582c29b3176614e3a33ddd1ec48352696a04e92b3c0566d72010fa8863d62001203565b60001b83620000d160201b620010341760201c565b620011176200110260017fa48b38a4b44951360fbdcbfaaeae5ed6ae92585412e9841b70ec72ed8cd0576462001203565b60001b82620000d160201b620010341760201c565b50505050565b600062000e5762000811600160008051602062003f0783398151915262001203565b600080620011576200118a60201b620011f21760201c565b90939092509050565b805160218110620011795763ec92f9a36000526004601cfd5b9081015160209190910360031b1b90565b60008080620011ae62000811600160008051602062003e8783398151915262001203565b6001600160a01b0381169350905082620011e1575073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee92601292509050565b60a081901c9150509091565b634e487b7160e01b600052601160045260246000fd5b600082821015620012185762001218620011ed565b500390565b60005b838110156200123a57818101518382015260200162001220565b83811115620011175750506000910152565b60208152600082518060208401526200126d8160408501602087016200121d565b601f01601f19169190910160400192915050565b6000602082840312156200129457600080fd5b815160ff81168114620012a657600080fd5b9392505050565b634e487b7160e01b600052604160045260246000fd5b600060208284031215620012d657600080fd5b81516001600160401b0380821115620012ee57600080fd5b818401915084601f8301126200130357600080fd5b815181811115620013185762001318620012ad565b604051601f8201601f19908116603f01168101908382118183101715620013435762001343620012ad565b816040528281528760208487010111156200135d57600080fd5b620013708360208301602088016200121d565b979650505050505050565b600063ffffffff8083168185168083038211156200139d576200139d620011ed565b01949350505050565b600063ffffffff80841680620013cc57634e487b7160e01b600052601260045260246000fd5b92169190910492915050565b600063ffffffff80831681851681830481118215151615620013fe57620013fe620011ed565b02949350505050565b60006001600160401b038281168482168083038211156200139d576200139d620011ed565b612a4b806200143c6000396000f3fe608060405234801561001057600080fd5b50600436106102ff5760003560e01c8063b40a817c1161019c578063db9040fa116100ee578063f2fde38b11610097578063f8c68de011610071578063f8c68de01461073e578063fd32aa0f14610746578063ffa1ad741461074e57600080fd5b8063f2fde38b1461070e578063f45e65d814610721578063f68016b71461072a57600080fd5b8063e81b2c6d116100c8578063e81b2c6d146106dd578063ec707517146106e6578063f2b4e6171461070657600080fd5b8063db9040fa146106ba578063e0e2016d146106cd578063e2a3285c146106d557600080fd5b8063c9b26f6111610150578063d220a9e01161012a578063d220a9e01461069a578063d8444715146106aa578063dac6e63a146106b257600080fd5b8063c9b26f611461053b578063c9ff2d161461054e578063cc731b021461056657600080fd5b8063bfb14fb711610181578063bfb14fb7146104ef578063c0fd4b4114610520578063c4e8ddfa1461053357600080fd5b8063b40a817c146104d4578063bc49ce5f146104e757600080fd5b806348cd4cb1116102555780635d73369c11610209578063935f029e116101e3578063935f029e146104b15780639b7d7f0a146104c4578063a7119869146104cc57600080fd5b80635d73369c14610483578063715018a61461048b5780638da5cb5b1461049357600080fd5b80634f16540b1161023a5780634f16540b1461041257806354fd4d5014610439578063550fcdc91461047b57600080fd5b806348cd4cb1146104025780634add321d1461040a57600080fd5b806318d13918116102b7578063213268491161029157806321326849146103a157806321d7fde5146103b95780634397dfef146103cc57600080fd5b806318d139181461037c57806319f5cea8146103915780631fd19ee11461039957600080fd5b80630a49cb03116102e85780630a49cb031461034c5780630ae14b1b146103545780630c18c1621461037357600080fd5b806306c9265714610304578063078f29cf1461031f575b600080fd5b61030c610756565b6040519081526020015b60405180910390f35b610327610784565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610316565b6103276107bd565b630bebc2005b60405167ffffffffffffffff9091168152602001610316565b61030c60655481565b61038f61038a366004612482565b6107ed565b005b61030c610801565b61032761082c565b6103a9610856565b6040519015158152602001610316565b61038f6103c73660046124b8565b610895565b6103d46108ab565b6040805173ffffffffffffffffffffffffffffffffffffffff909316835260ff909116602083015201610316565b61030c6108bf565b61035a6108ef565b61030c7f65a7ed542fb37fe237fdfbdd70b31598523fe5b32879e307bae27a0bd9581c0881565b60408051808201909152600581527f322e332e3000000000000000000000000000000000000000000000000000000060208201525b6040516103169190612561565b61046e610915565b61030c61091f565b61038f61094a565b60335473ffffffffffffffffffffffffffffffffffffffff16610327565b61038f6104bf366004612574565b61095e565b610327610970565b6103276109a0565b61038f6104e23660046125ae565b6109d0565b61030c6109e1565b60685461050b9068010000000000000000900463ffffffff1681565b60405163ffffffff9091168152602001610316565b61038f61052e3660046124b8565b610a0c565b610327610a1e565b61038f6105493660046125c9565b610a4e565b606a5461050b90640100000000900463ffffffff1681565b61062a6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a0810191909152506040805160c08101825260695463ffffffff8082168352640100000000820460ff9081166020850152650100000000008304169383019390935266010000000000008104831660608301526a0100000000000000000000810490921660808201526e0100000000000000000000000000009091046fffffffffffffffffffffffffffffffff1660a082015290565b6040516103169190600060c08201905063ffffffff80845116835260ff602085015116602084015260ff6040850151166040840152806060850151166060840152806080850151166080840152506fffffffffffffffffffffffffffffffff60a08401511660a083015292915050565b606a5461050b9063ffffffff1681565b61046e610a5f565b610327610a69565b61038f6106c83660046126fc565b610a99565b61030c610ea4565b61030c610ecf565b61030c60675481565b60685461050b906c01000000000000000000000000900463ffffffff1681565b610327610efa565b61038f61071c366004612482565b610f2a565b61030c60665481565b60685461035a9067ffffffffffffffff1681565b61030c610fde565b61030c611009565b61030c600081565b61078160017fa04c5bb938ca6fc46d95553abf0a76345ce3e722a30bf4f74928b8e7d852320d61287e565b81565b60006107b86107b460017f9904ba90dde5696cda05c9e0dab5cbaa0fea005ace4d11218a02ac668dad637761287e565b5490565b905090565b60006107b86107b460017f4b6c74f9e688cb39801f2112c14a8c57232a3fc5202e1444126d4bce86eb19ad61287e565b6107f561126f565b6107fe816112f0565b50565b61078160017f46adcbebc6be8ce551740c29c47c8798210f23f7f4086c41752944352568d5a861287e565b60006107b87f65a7ed542fb37fe237fdfbdd70b31598523fe5b32879e307bae27a0bd9581c085490565b6000806108616108ab565b5073ffffffffffffffffffffffffffffffffffffffff1673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee141592915050565b61089d61126f565b6108a782826113ad565b5050565b6000806108b66111f2565b90939092509050565b60006107b86107b460017fa11ee3ab75b40e88a0105e935d17cd36c8faee0138320d776c411291bdbbb1a061287e565b6069546000906107b89063ffffffff6a0100000000000000000000820481169116612895565b60606107b86114ec565b61078160017f383f291819e6d54073bc9a648251d97421076bdd101933c0c022219ce958063761287e565b61095261126f565b61095c60006115ad565b565b61096661126f565b6108a78282611624565b60006107b86107b460017fa04c5bb938ca6fc46d95553abf0a76345ce3e722a30bf4f74928b8e7d852320d61287e565b60006107b86107b460017f383f291819e6d54073bc9a648251d97421076bdd101933c0c022219ce958063761287e565b6109d861126f565b6107fe816116fa565b61078160017f71ac12829d66ee73d8d95bff50b3589745ce57edae70a3fb111a2342464dc59861287e565b610a1461126f565b6108a78282611850565b60006107b86107b460017f46adcbebc6be8ce551740c29c47c8798210f23f7f4086c41752944352568d5a861287e565b610a5661126f565b6107fe81611a22565b60606107b8611a4a565b60006107b86107b460017f71ac12829d66ee73d8d95bff50b3589745ce57edae70a3fb111a2342464dc59861287e565b600054610100900460ff1615808015610ab95750600054600160ff909116105b80610ad35750303b158015610ad3575060005460ff166001145b610b64576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084015b60405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790558015610bc257600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b610bca611b00565b610bd38a610f2a565b610bdc87611a22565b610be689896113ad565b610bef866116fa565b610c187f65a7ed542fb37fe237fdfbdd70b31598523fe5b32879e307bae27a0bd9581c08869055565b610c4b610c4660017f71ac12829d66ee73d8d95bff50b3589745ce57edae70a3fb111a2342464dc59861287e565b849055565b610c7f610c7960017f383f291819e6d54073bc9a648251d97421076bdd101933c0c022219ce958063761287e565b83519055565b610cb6610cad60017f46adcbebc6be8ce551740c29c47c8798210f23f7f4086c41752944352568d5a861287e565b60208401519055565b610ced610ce460017f9904ba90dde5696cda05c9e0dab5cbaa0fea005ace4d11218a02ac668dad637761287e565b60408401519055565b610d24610d1b60017f52322a25d9f59ea17656545543306b7aef62bc0cc53a0e65ccfa0c75b97aa90761287e565b60608401519055565b610d5b610d5260017f4b6c74f9e688cb39801f2112c14a8c57232a3fc5202e1444126d4bce86eb19ad61287e565b60808401519055565b610d92610d8960017fa04c5bb938ca6fc46d95553abf0a76345ce3e722a30bf4f74928b8e7d852320d61287e565b60a08401519055565b610d9a611b9f565b610da78260c00151611c07565b610db084611f11565b610db86108ef565b67ffffffffffffffff168667ffffffffffffffff161015610e35576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f53797374656d436f6e6669673a20676173206c696d697420746f6f206c6f77006044820152606401610b5b565b8015610e9857600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050505050565b61078160017fa11ee3ab75b40e88a0105e935d17cd36c8faee0138320d776c411291bdbbb1a061287e565b61078160017f52322a25d9f59ea17656545543306b7aef62bc0cc53a0e65ccfa0c75b97aa90761287e565b60006107b86107b460017f52322a25d9f59ea17656545543306b7aef62bc0cc53a0e65ccfa0c75b97aa90761287e565b610f3261126f565b73ffffffffffffffffffffffffffffffffffffffff8116610fd5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610b5b565b6107fe816115ad565b61078160017f9904ba90dde5696cda05c9e0dab5cbaa0fea005ace4d11218a02ac668dad637761287e565b61078160017f4b6c74f9e688cb39801f2112c14a8c57232a3fc5202e1444126d4bce86eb19ad61287e565b9055565b73ffffffffffffffffffffffffffffffffffffffff163b151590565b60006020825111156110e8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603660248201527f476173506179696e67546f6b656e3a20737472696e672063616e6e6f7420626560448201527f2067726561746572207468616e203332206279746573000000000000000000006064820152608401610b5b565b6110f1826111c9565b92915050565b61115d61112560017f04adb1412b2ddc16fcc0d4538d5c8f07cf9c83abecc6b41f6f69037b708fbcec61287e565b74ff000000000000000000000000000000000000000060a086901b1673ffffffffffffffffffffffffffffffffffffffff8716179055565b61119061118b60017f657c3582c29b3176614e3a33ddd1ec48352696a04e92b3c0566d72010fa8863d61287e565b839055565b6111c36111be60017fa48b38a4b44951360fbdcbfaaeae5ed6ae92585412e9841b70ec72ed8cd0576461287e565b829055565b50505050565b8051602181106111e15763ec92f9a36000526004601cfd5b9081015160209190910360031b1b90565b600080806112246107b460017f04adb1412b2ddc16fcc0d4538d5c8f07cf9c83abecc6b41f6f69037b708fbcec61287e565b73ffffffffffffffffffffffffffffffffffffffff81169350905082611263575073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee92601292509050565b60a081901c9150509091565b60335473ffffffffffffffffffffffffffffffffffffffff16331461095c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b5b565b6113197f65a7ed542fb37fe237fdfbdd70b31598523fe5b32879e307bae27a0bd9581c08829055565b6040805173ffffffffffffffffffffffffffffffffffffffff8316602082015260009101604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052905060035b60007f1d2b0bda21d56b8bd12d4f94ebacffdfb35f5e226f84b461103bb8beab6353be836040516113a19190612561565b60405180910390a35050565b606880547fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff166801000000000000000063ffffffff8581169182027fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff16929092176c0100000000000000000000000092851692909202919091179091557f0100000000000000000000000000000000000000000000000000000000000000602083811b67ffffffff000000001690921717606681905560655460408051938401919091528201526000906060015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052905060015b60007f1d2b0bda21d56b8bd12d4f94ebacffdfb35f5e226f84b461103bb8beab6353be836040516114df9190612561565b60405180910390a3505050565b606060006114f86111f2565b5090507fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff82160161157157505060408051808201909152600381527f4554480000000000000000000000000000000000000000000000000000000000602082015290565b6115a76115a26107b460017fa48b38a4b44951360fbdcbfaaeae5ed6ae92585412e9841b70ec72ed8cd0576461287e565b612385565b91505090565b6033805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b7fff000000000000000000000000000000000000000000000000000000000000008116156116d4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f53797374656d436f6e6669673a207363616c61722065786365656473206d617860448201527f2e000000000000000000000000000000000000000000000000000000000000006064820152608401610b5b565b60658290556066819055604080516020810184905290810182905260009060600161147b565b6117026108ef565b67ffffffffffffffff168167ffffffffffffffff16101561177f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f53797374656d436f6e6669673a20676173206c696d697420746f6f206c6f77006044820152606401610b5b565b630bebc20067ffffffffffffffff821611156117f7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f53797374656d436f6e6669673a20676173206c696d697420746f6f20686967686044820152606401610b5b565b606880547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff83169081179091556040805160208082019390935281518082039093018352810190526002611370565b60018263ffffffff1610156118e7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53797374656d436f6e6669673a2064656e6f6d696e61746f72206d757374206260448201527f65203e3d203100000000000000000000000000000000000000000000000000006064820152608401610b5b565b60018163ffffffff16101561197e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f53797374656d436f6e6669673a20656c6173746963697479206d75737420626560448201527f203e3d20310000000000000000000000000000000000000000000000000000006064820152608401610b5b565b606a805463ffffffff83811664010000000081027fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000090931691861691909117919091179091556040516000916119eb91602086811b67ffffffff0000000016909217910190815260200190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052905060046114ae565b6067819055604080516020808201849052825180830390910181529082019091526000611370565b60606000611a566111f2565b5090507fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff821601611acf57505060408051808201909152600581527f4574686572000000000000000000000000000000000000000000000000000000602082015290565b6115a76115a26107b460017f657c3582c29b3176614e3a33ddd1ec48352696a04e92b3c0566d72010fa8863d61287e565b600054610100900460ff16611b97576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610b5b565b61095c6123b9565b611bcd6107b460017fa11ee3ab75b40e88a0105e935d17cd36c8faee0138320d776c411291bdbbb1a061287e565b60000361095c5761095c611c0260017fa11ee3ab75b40e88a0105e935d17cd36c8faee0138320d776c411291bdbbb1a061287e565b439055565b73ffffffffffffffffffffffffffffffffffffffff811615801590611c56575073ffffffffffffffffffffffffffffffffffffffff811673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14155b8015611c675750611c65610856565b155b156107fe57601260ff168173ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611cbc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ce091906128c1565b60ff1614611d70576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f53797374656d436f6e6669673a2062616420646563696d616c73206f6620676160448201527f7320706179696e6720746f6b656e0000000000000000000000000000000000006064820152608401610b5b565b6000611e0b8273ffffffffffffffffffffffffffffffffffffffff166306fdde036040518163ffffffff1660e01b8152600401600060405180830381865afa158015611dc0573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611e0691908101906128de565b611054565b90506000611e5d8373ffffffffffffffffffffffffffffffffffffffff166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015611dc0573d6000803e3d6000fd5b9050611e6c83601284846110f7565b611e746107bd565b6040517f71cfaa3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff858116600483015260126024830152604482018590526064820184905291909116906371cfaa3f90608401600060405180830381600087803b158015611ef457600080fd5b505af1158015611f08573d6000803e3d6000fd5b50505050505050565b8060a001516fffffffffffffffffffffffffffffffff16816060015163ffffffff161115611fc1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603560248201527f53797374656d436f6e6669673a206d696e206261736520666565206d7573742060448201527f6265206c657373207468616e206d6178206261736500000000000000000000006064820152608401610b5b565b6001816040015160ff1611612058576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f53797374656d436f6e6669673a2064656e6f6d696e61746f72206d757374206260448201527f65206c6172676572207468616e203100000000000000000000000000000000006064820152608401610b5b565b6068546080820151825167ffffffffffffffff9092169161207991906129a9565b63ffffffff1611156120e7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f53797374656d436f6e6669673a20676173206c696d697420746f6f206c6f77006044820152606401610b5b565b6000816020015160ff161161217e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f53797374656d436f6e6669673a20656c6173746963697479206d756c7469706c60448201527f6965722063616e6e6f74206265203000000000000000000000000000000000006064820152608401610b5b565b8051602082015163ffffffff82169160ff9091169061219e9082906129c8565b6121a89190612a12565b63ffffffff161461223b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603760248201527f53797374656d436f6e6669673a20707265636973696f6e206c6f73732077697460448201527f6820746172676574207265736f75726365206c696d69740000000000000000006064820152608401610b5b565b805160698054602084015160408501516060860151608087015160a09097015163ffffffff9687167fffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000009095169490941764010000000060ff94851602177fffffffffffffffffffffffffffffffffffffffffffff0000000000ffffffffff166501000000000093909216929092027fffffffffffffffffffffffffffffffffffffffffffff00000000ffffffffffff1617660100000000000091851691909102177fffff0000000000000000000000000000000000000000ffffffffffffffffffff166a010000000000000000000093909416929092027fffff00000000000000000000000000000000ffffffffffffffffffffffffffff16929092176e0100000000000000000000000000006fffffffffffffffffffffffffffffffff90921691909102179055565b60405160005b82811a1561239b5760010161238b565b80825260208201838152600082820152505060408101604052919050565b600054610100900460ff16612450576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610b5b565b61095c336115ad565b803573ffffffffffffffffffffffffffffffffffffffff8116811461247d57600080fd5b919050565b60006020828403121561249457600080fd5b61249d82612459565b9392505050565b803563ffffffff8116811461247d57600080fd5b600080604083850312156124cb57600080fd5b6124d4836124a4565b91506124e2602084016124a4565b90509250929050565b60005b838110156125065781810151838201526020016124ee565b838111156111c35750506000910152565b6000815180845261252f8160208601602086016124eb565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60208152600061249d6020830184612517565b6000806040838503121561258757600080fd5b50508035926020909101359150565b803567ffffffffffffffff8116811461247d57600080fd5b6000602082840312156125c057600080fd5b61249d82612596565b6000602082840312156125db57600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160c0810167ffffffffffffffff81118282101715612634576126346125e2565b60405290565b60ff811681146107fe57600080fd5b600060e0828403121561265b57600080fd5b60405160e0810181811067ffffffffffffffff8211171561267e5761267e6125e2565b60405290508061268d83612459565b815261269b60208401612459565b60208201526126ac60408401612459565b60408201526126bd60608401612459565b60608201526126ce60808401612459565b60808201526126df60a08401612459565b60a08201526126f060c08401612459565b60c08201525092915050565b6000806000806000806000806000898b0361028081121561271c57600080fd5b6127258b612459565b995061273360208c016124a4565b985061274160408c016124a4565b975060608b0135965061275660808c01612596565b955061276460a08c01612459565b945060c07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff408201121561279657600080fd5b5061279f612611565b6127ab60c08c016124a4565b815260e08b01356127bb8161263a565b60208201526101008b01356127cf8161263a565b60408201526127e16101208c016124a4565b60608201526127f36101408c016124a4565b60808201526101608b01356fffffffffffffffffffffffffffffffff8116811461281c57600080fd5b60a082015292506128306101808b01612459565b91506128408b6101a08c01612649565b90509295985092959850929598565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000828210156128905761289061284f565b500390565b600067ffffffffffffffff8083168185168083038211156128b8576128b861284f565b01949350505050565b6000602082840312156128d357600080fd5b815161249d8161263a565b6000602082840312156128f057600080fd5b815167ffffffffffffffff8082111561290857600080fd5b818401915084601f83011261291c57600080fd5b81518181111561292e5761292e6125e2565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908382118183101715612974576129746125e2565b8160405282815287602084870101111561298d57600080fd5b61299e8360208301602088016124eb565b979650505050505050565b600063ffffffff8083168185168083038211156128b8576128b861284f565b600063ffffffff80841680612a06577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b92169190910492915050565b600063ffffffff80831681851681830481118215151615612a3557612a3561284f565b0294935050505056fea164736f6c634300080f000a04adb1412b2ddc16fcc0d4538d5c8f07cf9c83abecc6b41f6f69037b708fbcec53797374656d436f6e6669673a20676173206c696d697420746f6f206c6f77001d2b0bda21d56b8bd12d4f94ebacffdfb35f5e226f84b461103bb8beab6353be496e697469616c697a61626c653a20636f6e7472616374206973206e6f7420694b6c74f9e688cb39801f2112c14a8c57232a3fc5202e1444126d4bce86eb19ada11ee3ab75b40e88a0105e935d17cd36c8faee0138320d776c411291bdbbb1a0
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106102ff5760003560e01c8063b40a817c1161019c578063db9040fa116100ee578063f2fde38b11610097578063f8c68de011610071578063f8c68de01461073e578063fd32aa0f14610746578063ffa1ad741461074e57600080fd5b8063f2fde38b1461070e578063f45e65d814610721578063f68016b71461072a57600080fd5b8063e81b2c6d116100c8578063e81b2c6d146106dd578063ec707517146106e6578063f2b4e6171461070657600080fd5b8063db9040fa146106ba578063e0e2016d146106cd578063e2a3285c146106d557600080fd5b8063c9b26f6111610150578063d220a9e01161012a578063d220a9e01461069a578063d8444715146106aa578063dac6e63a146106b257600080fd5b8063c9b26f611461053b578063c9ff2d161461054e578063cc731b021461056657600080fd5b8063bfb14fb711610181578063bfb14fb7146104ef578063c0fd4b4114610520578063c4e8ddfa1461053357600080fd5b8063b40a817c146104d4578063bc49ce5f146104e757600080fd5b806348cd4cb1116102555780635d73369c11610209578063935f029e116101e3578063935f029e146104b15780639b7d7f0a146104c4578063a7119869146104cc57600080fd5b80635d73369c14610483578063715018a61461048b5780638da5cb5b1461049357600080fd5b80634f16540b1161023a5780634f16540b1461041257806354fd4d5014610439578063550fcdc91461047b57600080fd5b806348cd4cb1146104025780634add321d1461040a57600080fd5b806318d13918116102b7578063213268491161029157806321326849146103a157806321d7fde5146103b95780634397dfef146103cc57600080fd5b806318d139181461037c57806319f5cea8146103915780631fd19ee11461039957600080fd5b80630a49cb03116102e85780630a49cb031461034c5780630ae14b1b146103545780630c18c1621461037357600080fd5b806306c9265714610304578063078f29cf1461031f575b600080fd5b61030c610756565b6040519081526020015b60405180910390f35b610327610784565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610316565b6103276107bd565b630bebc2005b60405167ffffffffffffffff9091168152602001610316565b61030c60655481565b61038f61038a366004612482565b6107ed565b005b61030c610801565b61032761082c565b6103a9610856565b6040519015158152602001610316565b61038f6103c73660046124b8565b610895565b6103d46108ab565b6040805173ffffffffffffffffffffffffffffffffffffffff909316835260ff909116602083015201610316565b61030c6108bf565b61035a6108ef565b61030c7f65a7ed542fb37fe237fdfbdd70b31598523fe5b32879e307bae27a0bd9581c0881565b60408051808201909152600581527f322e332e3000000000000000000000000000000000000000000000000000000060208201525b6040516103169190612561565b61046e610915565b61030c61091f565b61038f61094a565b60335473ffffffffffffffffffffffffffffffffffffffff16610327565b61038f6104bf366004612574565b61095e565b610327610970565b6103276109a0565b61038f6104e23660046125ae565b6109d0565b61030c6109e1565b60685461050b9068010000000000000000900463ffffffff1681565b60405163ffffffff9091168152602001610316565b61038f61052e3660046124b8565b610a0c565b610327610a1e565b61038f6105493660046125c9565b610a4e565b606a5461050b90640100000000900463ffffffff1681565b61062a6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a0810191909152506040805160c08101825260695463ffffffff8082168352640100000000820460ff9081166020850152650100000000008304169383019390935266010000000000008104831660608301526a0100000000000000000000810490921660808201526e0100000000000000000000000000009091046fffffffffffffffffffffffffffffffff1660a082015290565b6040516103169190600060c08201905063ffffffff80845116835260ff602085015116602084015260ff6040850151166040840152806060850151166060840152806080850151166080840152506fffffffffffffffffffffffffffffffff60a08401511660a083015292915050565b606a5461050b9063ffffffff1681565b61046e610a5f565b610327610a69565b61038f6106c83660046126fc565b610a99565b61030c610ea4565b61030c610ecf565b61030c60675481565b60685461050b906c01000000000000000000000000900463ffffffff1681565b610327610efa565b61038f61071c366004612482565b610f2a565b61030c60665481565b60685461035a9067ffffffffffffffff1681565b61030c610fde565b61030c611009565b61030c600081565b61078160017fa04c5bb938ca6fc46d95553abf0a76345ce3e722a30bf4f74928b8e7d852320d61287e565b81565b60006107b86107b460017f9904ba90dde5696cda05c9e0dab5cbaa0fea005ace4d11218a02ac668dad637761287e565b5490565b905090565b60006107b86107b460017f4b6c74f9e688cb39801f2112c14a8c57232a3fc5202e1444126d4bce86eb19ad61287e565b6107f561126f565b6107fe816112f0565b50565b61078160017f46adcbebc6be8ce551740c29c47c8798210f23f7f4086c41752944352568d5a861287e565b60006107b87f65a7ed542fb37fe237fdfbdd70b31598523fe5b32879e307bae27a0bd9581c085490565b6000806108616108ab565b5073ffffffffffffffffffffffffffffffffffffffff1673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee141592915050565b61089d61126f565b6108a782826113ad565b5050565b6000806108b66111f2565b90939092509050565b60006107b86107b460017fa11ee3ab75b40e88a0105e935d17cd36c8faee0138320d776c411291bdbbb1a061287e565b6069546000906107b89063ffffffff6a0100000000000000000000820481169116612895565b60606107b86114ec565b61078160017f383f291819e6d54073bc9a648251d97421076bdd101933c0c022219ce958063761287e565b61095261126f565b61095c60006115ad565b565b61096661126f565b6108a78282611624565b60006107b86107b460017fa04c5bb938ca6fc46d95553abf0a76345ce3e722a30bf4f74928b8e7d852320d61287e565b60006107b86107b460017f383f291819e6d54073bc9a648251d97421076bdd101933c0c022219ce958063761287e565b6109d861126f565b6107fe816116fa565b61078160017f71ac12829d66ee73d8d95bff50b3589745ce57edae70a3fb111a2342464dc59861287e565b610a1461126f565b6108a78282611850565b60006107b86107b460017f46adcbebc6be8ce551740c29c47c8798210f23f7f4086c41752944352568d5a861287e565b610a5661126f565b6107fe81611a22565b60606107b8611a4a565b60006107b86107b460017f71ac12829d66ee73d8d95bff50b3589745ce57edae70a3fb111a2342464dc59861287e565b600054610100900460ff1615808015610ab95750600054600160ff909116105b80610ad35750303b158015610ad3575060005460ff166001145b610b64576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084015b60405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790558015610bc257600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b610bca611b00565b610bd38a610f2a565b610bdc87611a22565b610be689896113ad565b610bef866116fa565b610c187f65a7ed542fb37fe237fdfbdd70b31598523fe5b32879e307bae27a0bd9581c08869055565b610c4b610c4660017f71ac12829d66ee73d8d95bff50b3589745ce57edae70a3fb111a2342464dc59861287e565b849055565b610c7f610c7960017f383f291819e6d54073bc9a648251d97421076bdd101933c0c022219ce958063761287e565b83519055565b610cb6610cad60017f46adcbebc6be8ce551740c29c47c8798210f23f7f4086c41752944352568d5a861287e565b60208401519055565b610ced610ce460017f9904ba90dde5696cda05c9e0dab5cbaa0fea005ace4d11218a02ac668dad637761287e565b60408401519055565b610d24610d1b60017f52322a25d9f59ea17656545543306b7aef62bc0cc53a0e65ccfa0c75b97aa90761287e565b60608401519055565b610d5b610d5260017f4b6c74f9e688cb39801f2112c14a8c57232a3fc5202e1444126d4bce86eb19ad61287e565b60808401519055565b610d92610d8960017fa04c5bb938ca6fc46d95553abf0a76345ce3e722a30bf4f74928b8e7d852320d61287e565b60a08401519055565b610d9a611b9f565b610da78260c00151611c07565b610db084611f11565b610db86108ef565b67ffffffffffffffff168667ffffffffffffffff161015610e35576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f53797374656d436f6e6669673a20676173206c696d697420746f6f206c6f77006044820152606401610b5b565b8015610e9857600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050505050565b61078160017fa11ee3ab75b40e88a0105e935d17cd36c8faee0138320d776c411291bdbbb1a061287e565b61078160017f52322a25d9f59ea17656545543306b7aef62bc0cc53a0e65ccfa0c75b97aa90761287e565b60006107b86107b460017f52322a25d9f59ea17656545543306b7aef62bc0cc53a0e65ccfa0c75b97aa90761287e565b610f3261126f565b73ffffffffffffffffffffffffffffffffffffffff8116610fd5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610b5b565b6107fe816115ad565b61078160017f9904ba90dde5696cda05c9e0dab5cbaa0fea005ace4d11218a02ac668dad637761287e565b61078160017f4b6c74f9e688cb39801f2112c14a8c57232a3fc5202e1444126d4bce86eb19ad61287e565b9055565b73ffffffffffffffffffffffffffffffffffffffff163b151590565b60006020825111156110e8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603660248201527f476173506179696e67546f6b656e3a20737472696e672063616e6e6f7420626560448201527f2067726561746572207468616e203332206279746573000000000000000000006064820152608401610b5b565b6110f1826111c9565b92915050565b61115d61112560017f04adb1412b2ddc16fcc0d4538d5c8f07cf9c83abecc6b41f6f69037b708fbcec61287e565b74ff000000000000000000000000000000000000000060a086901b1673ffffffffffffffffffffffffffffffffffffffff8716179055565b61119061118b60017f657c3582c29b3176614e3a33ddd1ec48352696a04e92b3c0566d72010fa8863d61287e565b839055565b6111c36111be60017fa48b38a4b44951360fbdcbfaaeae5ed6ae92585412e9841b70ec72ed8cd0576461287e565b829055565b50505050565b8051602181106111e15763ec92f9a36000526004601cfd5b9081015160209190910360031b1b90565b600080806112246107b460017f04adb1412b2ddc16fcc0d4538d5c8f07cf9c83abecc6b41f6f69037b708fbcec61287e565b73ffffffffffffffffffffffffffffffffffffffff81169350905082611263575073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee92601292509050565b60a081901c9150509091565b60335473ffffffffffffffffffffffffffffffffffffffff16331461095c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b5b565b6113197f65a7ed542fb37fe237fdfbdd70b31598523fe5b32879e307bae27a0bd9581c08829055565b6040805173ffffffffffffffffffffffffffffffffffffffff8316602082015260009101604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052905060035b60007f1d2b0bda21d56b8bd12d4f94ebacffdfb35f5e226f84b461103bb8beab6353be836040516113a19190612561565b60405180910390a35050565b606880547fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff166801000000000000000063ffffffff8581169182027fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff16929092176c0100000000000000000000000092851692909202919091179091557f0100000000000000000000000000000000000000000000000000000000000000602083811b67ffffffff000000001690921717606681905560655460408051938401919091528201526000906060015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052905060015b60007f1d2b0bda21d56b8bd12d4f94ebacffdfb35f5e226f84b461103bb8beab6353be836040516114df9190612561565b60405180910390a3505050565b606060006114f86111f2565b5090507fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff82160161157157505060408051808201909152600381527f4554480000000000000000000000000000000000000000000000000000000000602082015290565b6115a76115a26107b460017fa48b38a4b44951360fbdcbfaaeae5ed6ae92585412e9841b70ec72ed8cd0576461287e565b612385565b91505090565b6033805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b7fff000000000000000000000000000000000000000000000000000000000000008116156116d4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f53797374656d436f6e6669673a207363616c61722065786365656473206d617860448201527f2e000000000000000000000000000000000000000000000000000000000000006064820152608401610b5b565b60658290556066819055604080516020810184905290810182905260009060600161147b565b6117026108ef565b67ffffffffffffffff168167ffffffffffffffff16101561177f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f53797374656d436f6e6669673a20676173206c696d697420746f6f206c6f77006044820152606401610b5b565b630bebc20067ffffffffffffffff821611156117f7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f53797374656d436f6e6669673a20676173206c696d697420746f6f20686967686044820152606401610b5b565b606880547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff83169081179091556040805160208082019390935281518082039093018352810190526002611370565b60018263ffffffff1610156118e7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53797374656d436f6e6669673a2064656e6f6d696e61746f72206d757374206260448201527f65203e3d203100000000000000000000000000000000000000000000000000006064820152608401610b5b565b60018163ffffffff16101561197e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f53797374656d436f6e6669673a20656c6173746963697479206d75737420626560448201527f203e3d20310000000000000000000000000000000000000000000000000000006064820152608401610b5b565b606a805463ffffffff83811664010000000081027fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000090931691861691909117919091179091556040516000916119eb91602086811b67ffffffff0000000016909217910190815260200190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052905060046114ae565b6067819055604080516020808201849052825180830390910181529082019091526000611370565b60606000611a566111f2565b5090507fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff821601611acf57505060408051808201909152600581527f4574686572000000000000000000000000000000000000000000000000000000602082015290565b6115a76115a26107b460017f657c3582c29b3176614e3a33ddd1ec48352696a04e92b3c0566d72010fa8863d61287e565b600054610100900460ff16611b97576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610b5b565b61095c6123b9565b611bcd6107b460017fa11ee3ab75b40e88a0105e935d17cd36c8faee0138320d776c411291bdbbb1a061287e565b60000361095c5761095c611c0260017fa11ee3ab75b40e88a0105e935d17cd36c8faee0138320d776c411291bdbbb1a061287e565b439055565b73ffffffffffffffffffffffffffffffffffffffff811615801590611c56575073ffffffffffffffffffffffffffffffffffffffff811673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14155b8015611c675750611c65610856565b155b156107fe57601260ff168173ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611cbc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ce091906128c1565b60ff1614611d70576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f53797374656d436f6e6669673a2062616420646563696d616c73206f6620676160448201527f7320706179696e6720746f6b656e0000000000000000000000000000000000006064820152608401610b5b565b6000611e0b8273ffffffffffffffffffffffffffffffffffffffff166306fdde036040518163ffffffff1660e01b8152600401600060405180830381865afa158015611dc0573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052611e0691908101906128de565b611054565b90506000611e5d8373ffffffffffffffffffffffffffffffffffffffff166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015611dc0573d6000803e3d6000fd5b9050611e6c83601284846110f7565b611e746107bd565b6040517f71cfaa3f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff858116600483015260126024830152604482018590526064820184905291909116906371cfaa3f90608401600060405180830381600087803b158015611ef457600080fd5b505af1158015611f08573d6000803e3d6000fd5b50505050505050565b8060a001516fffffffffffffffffffffffffffffffff16816060015163ffffffff161115611fc1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603560248201527f53797374656d436f6e6669673a206d696e206261736520666565206d7573742060448201527f6265206c657373207468616e206d6178206261736500000000000000000000006064820152608401610b5b565b6001816040015160ff1611612058576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f53797374656d436f6e6669673a2064656e6f6d696e61746f72206d757374206260448201527f65206c6172676572207468616e203100000000000000000000000000000000006064820152608401610b5b565b6068546080820151825167ffffffffffffffff9092169161207991906129a9565b63ffffffff1611156120e7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f53797374656d436f6e6669673a20676173206c696d697420746f6f206c6f77006044820152606401610b5b565b6000816020015160ff161161217e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f53797374656d436f6e6669673a20656c6173746963697479206d756c7469706c60448201527f6965722063616e6e6f74206265203000000000000000000000000000000000006064820152608401610b5b565b8051602082015163ffffffff82169160ff9091169061219e9082906129c8565b6121a89190612a12565b63ffffffff161461223b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603760248201527f53797374656d436f6e6669673a20707265636973696f6e206c6f73732077697460448201527f6820746172676574207265736f75726365206c696d69740000000000000000006064820152608401610b5b565b805160698054602084015160408501516060860151608087015160a09097015163ffffffff9687167fffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000009095169490941764010000000060ff94851602177fffffffffffffffffffffffffffffffffffffffffffff0000000000ffffffffff166501000000000093909216929092027fffffffffffffffffffffffffffffffffffffffffffff00000000ffffffffffff1617660100000000000091851691909102177fffff0000000000000000000000000000000000000000ffffffffffffffffffff166a010000000000000000000093909416929092027fffff00000000000000000000000000000000ffffffffffffffffffffffffffff16929092176e0100000000000000000000000000006fffffffffffffffffffffffffffffffff90921691909102179055565b60405160005b82811a1561239b5760010161238b565b80825260208201838152600082820152505060408101604052919050565b600054610100900460ff16612450576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610b5b565b61095c336115ad565b803573ffffffffffffffffffffffffffffffffffffffff8116811461247d57600080fd5b919050565b60006020828403121561249457600080fd5b61249d82612459565b9392505050565b803563ffffffff8116811461247d57600080fd5b600080604083850312156124cb57600080fd5b6124d4836124a4565b91506124e2602084016124a4565b90509250929050565b60005b838110156125065781810151838201526020016124ee565b838111156111c35750506000910152565b6000815180845261252f8160208601602086016124eb565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60208152600061249d6020830184612517565b6000806040838503121561258757600080fd5b50508035926020909101359150565b803567ffffffffffffffff8116811461247d57600080fd5b6000602082840312156125c057600080fd5b61249d82612596565b6000602082840312156125db57600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160c0810167ffffffffffffffff81118282101715612634576126346125e2565b60405290565b60ff811681146107fe57600080fd5b600060e0828403121561265b57600080fd5b60405160e0810181811067ffffffffffffffff8211171561267e5761267e6125e2565b60405290508061268d83612459565b815261269b60208401612459565b60208201526126ac60408401612459565b60408201526126bd60608401612459565b60608201526126ce60808401612459565b60808201526126df60a08401612459565b60a08201526126f060c08401612459565b60c08201525092915050565b6000806000806000806000806000898b0361028081121561271c57600080fd5b6127258b612459565b995061273360208c016124a4565b985061274160408c016124a4565b975060608b0135965061275660808c01612596565b955061276460a08c01612459565b945060c07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff408201121561279657600080fd5b5061279f612611565b6127ab60c08c016124a4565b815260e08b01356127bb8161263a565b60208201526101008b01356127cf8161263a565b60408201526127e16101208c016124a4565b60608201526127f36101408c016124a4565b60808201526101608b01356fffffffffffffffffffffffffffffffff8116811461281c57600080fd5b60a082015292506128306101808b01612459565b91506128408b6101a08c01612649565b90509295985092959850929598565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000828210156128905761289061284f565b500390565b600067ffffffffffffffff8083168185168083038211156128b8576128b861284f565b01949350505050565b6000602082840312156128d357600080fd5b815161249d8161263a565b6000602082840312156128f057600080fd5b815167ffffffffffffffff8082111561290857600080fd5b818401915084601f83011261291c57600080fd5b81518181111561292e5761292e6125e2565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908382118183101715612974576129746125e2565b8160405282815287602084870101111561298d57600080fd5b61299e8360208301602088016124eb565b979650505050505050565b600063ffffffff8083168185168083038211156128b8576128b861284f565b600063ffffffff80841680612a06577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b92169190910492915050565b600063ffffffff80831681851681830481118215151615612a3557612a3561284f565b0294935050505056fea164736f6c634300080f000a
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.