Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 8 from a total of 8 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Transfer Asset | 38574652 | 52 days ago | IN | 0 ETH | 0.00009741 | ||||
| Accept Ownership | 38534165 | 53 days ago | IN | 0 ETH | 0.00000007 | ||||
| Transfer Ownersh... | 38534111 | 53 days ago | IN | 0 ETH | 0.00004715 | ||||
| Set Operator | 38534039 | 53 days ago | IN | 0 ETH | 0.00004679 | ||||
| Transfer Asset | 38527514 | 53 days ago | IN | 0 ETH | 0.00007176 | ||||
| Complete Withdra... | 38525190 | 53 days ago | IN | 0 ETH | 0.0000871 | ||||
| Transfer Asset | 38524126 | 53 days ago | IN | 0 ETH | 0.00007176 | ||||
| Set Operator | 38508190 | 53 days ago | IN | 0 ETH | 0.00007243 |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
SherpaUSD
Compiler Version
v0.8.24+commit.e11b9ed9
Optimization Enabled:
Yes with 200 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {Ownable2Step} from "./external/Ownable2Step.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {ReentrancyGuardTransient} from "./external/ReentrancyGuardTransient.sol";
/**
* @title SherpaUSD
* @notice 1:1 wrapper for USDC with epoch-based withdrawals
* @dev Simplified version for CCIP - bridging handled by separate token pools
*/
contract SherpaUSD is ERC20, Ownable2Step, ReentrancyGuardTransient {
using SafeERC20 for IERC20;
/// @notice The asset being wrapped (USDC)
address public immutable asset;
/// @notice The current epoch number
uint32 public currentEpoch;
/// @notice Enable automatic USDC transfers in processWithdrawals()
bool public autoTransfer;
/// @notice The vault/keeper address
address public keeper;
/// @notice The operator address for automated operations
address public operator;
/// @notice Prevents keeper-swap attack (owner swaps keeper to drain user USDC approvals)
bool private keeperLocked;
/// @notice User withdrawal receipts
mapping(address user => WithdrawalReceipt receipt) public withdrawalReceipts;
/// @notice Withdrawal amount for current epoch
uint256 public withdrawalAmountForEpoch;
/// @notice Deposit amount for current epoch
uint256 public depositAmountForEpoch;
/// @notice Approved adjustment amounts for vault rebalancing
mapping(address vault => uint256 amount) public approvedTotalStakedAdjustment;
mapping(address vault => uint256 amount) public approvedAccountingAdjustment;
struct WithdrawalReceipt {
uint224 amount;
uint32 epoch;
}
event DepositToVault(address indexed user, uint256 amount);
event WithdrawalInitiated(address indexed user, uint224 amount, uint32 indexed epoch);
event Withdrawn(address indexed user, uint256 amount);
event WithdrawalsProcessed(uint256 withdrawalAmount, uint256 balance, uint32 indexed epoch);
event AssetTransferred(address indexed to, uint256 amount);
event PermissionedMint(address indexed to, uint256 amount);
event PermissionedBurn(address indexed from, uint256 amount);
event KeeperSet(address indexed oldKeeper, address indexed newKeeper);
event AutoTransferSet(bool oldValue, bool newValue);
event OperatorUpdated(address indexed oldOperator, address indexed newOperator);
event RebalanceApprovalSet(address indexed vault, uint256 totalStakedAmount, uint256 accountingAmount);
event TotalStakedApprovalConsumed(address indexed vault);
event AccountingApprovalConsumed(address indexed vault);
error AmountMustBeGreaterThanZero();
error AddressMustBeNonZero();
error InsufficientBalance();
error NotKeeper();
error CannotCompleteWithdrawalInSameEpoch();
error OnlyOperator();
error InvalidAssetDecimals();
error CannotRenounceOwnership();
error KeeperAlreadyLocked();
error ApprovalNotConsumed();
modifier onlyKeeper() {
if (msg.sender != keeper) revert NotKeeper();
_;
}
modifier onlyOperator() {
if (msg.sender != operator && msg.sender != owner()) revert OnlyOperator();
_;
}
constructor(
address _asset,
address _keeper
) ERC20("Sherpa USD", "sherpaUSD") {
if (_asset == address(0)) revert AddressMustBeNonZero();
if (_keeper == address(0)) revert AddressMustBeNonZero();
// CRITICAL: SherpaUSD only supports 6-decimal assets WITHOUT transfer fees (e.g., USDC)
// DO NOT use fee-on-transfer tokens (including USDT which has dormant fee mechanisms)
if (IERC20Metadata(_asset).decimals() != 6) revert InvalidAssetDecimals();
asset = _asset;
keeper = _keeper;
currentEpoch = 1;
autoTransfer = false; // Default to manual mode for safety
}
/**
* @notice Vault deposits USDC from user and mints sherpaUSD to keeper
* @param from User depositing USDC
* @param amount Amount of USDC to deposit
* @dev INTENTIONAL DESIGN: Uses `from` parameter instead of msg.sender to allow keeper (vault)
* to pull funds on behalf of users. Users approve this contract and call vault.depositAndStake(),
* which calls this function with the user's address. Users must trust keeper to only pass the
* actual caller's address. Malicious/compromised keeper could drain approved users.
*/
function depositToVault(
address from,
uint256 amount
) external nonReentrant onlyKeeper {
if (amount == 0) revert AmountMustBeGreaterThanZero();
_mint(keeper, amount);
depositAmountForEpoch += amount;
emit DepositToVault(from, amount);
IERC20(asset).safeTransferFrom(from, address(this), amount);
}
/**
* @notice Initiate withdrawal - burns sherpaUSD and creates receipt
* @param amount Amount to withdraw
*/
function initiateWithdrawal(uint224 amount) external nonReentrant {
if (amount == 0) revert AmountMustBeGreaterThanZero();
if (balanceOf(msg.sender) < amount) revert InsufficientBalance();
_burn(msg.sender, amount);
WithdrawalReceipt storage receipt = withdrawalReceipts[msg.sender];
receipt.amount = uint224(uint256(receipt.amount) + amount);
receipt.epoch = currentEpoch;
withdrawalAmountForEpoch += amount;
emit WithdrawalInitiated(msg.sender, amount, currentEpoch);
}
/**
* @notice Initiate withdrawal from vault (called by vault on behalf of user)
* @param from User address to create withdrawal receipt for
* @param amount Amount to withdraw
* @dev INTENTIONAL DESIGN: Uses `from` parameter to allow keeper (vault) to create withdrawal
* receipts on behalf of users. Vault transfers sherpaUSD here, then this function burns it
* and creates receipt for user. Users trust keeper to only create receipts for legitimate unstakes.
*/
function initiateWithdrawalFromVault(
address from,
uint224 amount
) external nonReentrant onlyKeeper {
if (amount == 0) revert AmountMustBeGreaterThanZero();
// Burn from this contract (vault transferred tokens here)
_burn(address(this), amount);
// Cache current epoch
uint32 epoch = currentEpoch;
// Create/update withdrawal receipt for user
WithdrawalReceipt storage receipt = withdrawalReceipts[from];
receipt.amount = uint224(uint256(receipt.amount) + amount);
receipt.epoch = epoch;
withdrawalAmountForEpoch += amount;
emit WithdrawalInitiated(from, amount, epoch);
}
/**
* @notice Complete withdrawal after epoch passes
*/
function completeWithdrawal() external nonReentrant {
WithdrawalReceipt storage receipt = withdrawalReceipts[msg.sender];
if (receipt.epoch == currentEpoch) {
revert CannotCompleteWithdrawalInSameEpoch();
}
if (receipt.amount == 0) revert AmountMustBeGreaterThanZero();
uint256 withdrawAmount = receipt.amount;
receipt.amount = 0;
emit Withdrawn(msg.sender, withdrawAmount);
IERC20(asset).safeTransfer(msg.sender, withdrawAmount);
}
/**
* @notice Process withdrawals and roll to next epoch (keeper only)
* @dev If autoTransfer is enabled, automatically transfers USDC to/from owner
*/
function processWithdrawals() external nonReentrant onlyKeeper {
// Cache storage values
uint256 withdrawalAmount = withdrawalAmountForEpoch;
uint256 depositAmount = depositAmountForEpoch;
uint32 epoch = currentEpoch;
// Automatic transfer logic (if enabled)
if (autoTransfer) {
if (withdrawalAmount > depositAmount) {
// More withdrawals than deposits - pull from owner
IERC20(asset).safeTransferFrom(
owner(),
address(this),
withdrawalAmount - depositAmount
);
} else if (withdrawalAmount < depositAmount) {
// More deposits than withdrawals - send excess to owner
IERC20(asset).safeTransfer(
owner(),
depositAmount - withdrawalAmount
);
}
}
emit WithdrawalsProcessed(withdrawalAmount, depositAmount, epoch);
currentEpoch = epoch + 1;
depositAmountForEpoch = 0;
withdrawalAmountForEpoch = 0;
}
/**
* @notice Permissioned mint for yield (keeper only)
* @param to Address to mint to
* @param amount Amount to mint
*/
function permissionedMint(address to, uint256 amount) external onlyKeeper {
_mint(to, amount);
emit PermissionedMint(to, amount);
}
/**
* @notice Permissioned burn (keeper only)
* @param from Address to burn from
* @param amount Amount to burn
*/
function permissionedBurn(address from, uint256 amount) external onlyKeeper {
_burn(from, amount);
emit PermissionedBurn(from, amount);
}
/**
* @notice Operator-level mint for manual rebalancing across chains
* @param to Address to mint to
* @param amount Amount to mint
* @dev Sets approval for vault to adjust totalStaked and accountingSupply
* @dev Reverts if previous approvals not consumed (prevents accounting corruption)
*/
function ownerMint(address to, uint256 amount) external onlyOperator {
// Enforce atomicity: previous approvals must be consumed before new mint
if (approvedTotalStakedAdjustment[to] != 0) revert ApprovalNotConsumed();
if (approvedAccountingAdjustment[to] != 0) revert ApprovalNotConsumed();
_mint(to, amount);
// Approve vault to adjust by this amount
approvedTotalStakedAdjustment[to] = amount;
approvedAccountingAdjustment[to] = amount;
emit PermissionedMint(to, amount);
emit RebalanceApprovalSet(to, amount, amount);
}
/**
* @notice Operator-level burn for manual rebalancing across chains
* @param from Address to burn from
* @param amount Amount to burn
* @dev Sets approval for vault to adjust totalStaked and accountingSupply
* @dev Reverts if previous approvals not consumed (prevents accounting corruption)
*/
function ownerBurn(address from, uint256 amount) external onlyOperator {
// Enforce atomicity: previous approvals must be consumed before new burn
if (approvedTotalStakedAdjustment[from] != 0) revert ApprovalNotConsumed();
if (approvedAccountingAdjustment[from] != 0) revert ApprovalNotConsumed();
_burn(from, amount);
// Approve vault to adjust by this amount
approvedTotalStakedAdjustment[from] = amount;
approvedAccountingAdjustment[from] = amount;
emit PermissionedBurn(from, amount);
emit RebalanceApprovalSet(from, amount, amount);
}
/**
* @notice Operator-level mint for asset-only rebalancing (yield-induced backing imbalances)
* @param to Address to mint to
* @param amount Amount to mint
* @dev Only sets approval for totalStaked adjustment, NOT accountingSupply
* @dev Use this when rebalancing sherpaUSD backing without moving shUSD shares
* @dev Reverts if previous approvals not consumed (prevents accounting corruption)
*/
function ownerMintAssetOnly(address to, uint256 amount) external onlyOperator {
// Enforce atomicity: previous approvals must be consumed before new mint
if (approvedTotalStakedAdjustment[to] != 0) revert ApprovalNotConsumed();
if (approvedAccountingAdjustment[to] != 0) revert ApprovalNotConsumed();
_mint(to, amount);
// Only approve totalStaked adjustment
approvedTotalStakedAdjustment[to] = amount;
// DO NOT set approvedAccountingAdjustment - no shares are moving
emit PermissionedMint(to, amount);
emit RebalanceApprovalSet(to, amount, 0);
}
/**
* @notice Operator-level burn for asset-only rebalancing (yield-induced backing imbalances)
* @param from Address to burn from
* @param amount Amount to burn
* @dev Only sets approval for totalStaked adjustment, NOT accountingSupply
* @dev Use this when rebalancing sherpaUSD backing without moving shUSD shares
* @dev Reverts if previous approvals not consumed (prevents accounting corruption)
*/
function ownerBurnAssetOnly(address from, uint256 amount) external onlyOperator {
// Enforce atomicity: previous approvals must be consumed before new burn
if (approvedTotalStakedAdjustment[from] != 0) revert ApprovalNotConsumed();
if (approvedAccountingAdjustment[from] != 0) revert ApprovalNotConsumed();
_burn(from, amount);
// Only approve totalStaked adjustment
approvedTotalStakedAdjustment[from] = amount;
// DO NOT set approvedAccountingAdjustment - no shares are moving
emit PermissionedBurn(from, amount);
emit RebalanceApprovalSet(from, amount, 0);
}
/**
* @notice Consume approval for totalStaked adjustment
* @dev Only callable by the keeper (vault)
*/
function consumeTotalStakedApproval() external onlyKeeper {
approvedTotalStakedAdjustment[msg.sender] = 0;
emit TotalStakedApprovalConsumed(msg.sender);
}
/**
* @notice Consume approval for accounting adjustment
* @dev Only callable by the keeper (vault)
*/
function consumeAccountingApproval() external onlyKeeper {
approvedAccountingAdjustment[msg.sender] = 0;
emit AccountingApprovalConsumed(msg.sender);
}
/**
* @notice Transfer USDC to external address (operator for yield strategies)
* @param to Destination address
* @param amount Amount to transfer
*/
function transferAsset(
address to,
uint256 amount
) external onlyOperator {
if (amount == 0) revert AmountMustBeGreaterThanZero();
emit AssetTransferred(to, amount);
IERC20(asset).safeTransfer(to, amount);
}
/**
* @notice Set new keeper address (one-time only)
* @param _keeper New keeper address
* @dev SECURITY: Locks after first call to prevent keeper-swap attack where malicious keeper drains user USDC approvals
* @dev During deployment: wrapper initialized with temporary keeper, then this is called once to set vault as keeper
*/
function setKeeper(address _keeper) external onlyOwner {
if (keeperLocked) revert KeeperAlreadyLocked();
if (_keeper == address(0)) revert AddressMustBeNonZero();
emit KeeperSet(keeper, _keeper);
keeper = _keeper;
keeperLocked = true; // Lock permanently after first call
}
/**
* @notice Set or change the operator address (owner only)
* @param newOperator Address of the new operator for automated operations
*/
function setOperator(address newOperator) external onlyOwner {
if (newOperator == address(0)) revert AddressMustBeNonZero();
emit OperatorUpdated(operator, newOperator);
operator = newOperator;
}
/**
* @notice Enable or disable automatic USDC transfers in processWithdrawals()
* @param _enabled True to enable automatic transfers, false for manual control
*/
function setAutoTransfer(bool _enabled) external onlyOwner {
emit AutoTransferSet(autoTransfer, _enabled);
autoTransfer = _enabled;
}
/**
* @notice Renouncing ownership is disabled for SherpaUSD
* @dev SherpaUSD requires an active owner for keeper/operator management
* @dev Ownership is transferred to a multisig for decentralization
*/
function renounceOwnership() public override onlyOwner {
revert CannotRenounceOwnership();
}
/**
* @notice Returns 6 decimals (same as USDC)
*/
function decimals() public pure override returns (uint8) {
return 6;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* 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 Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor() {
_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. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
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);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.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.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
* to implement supply mechanisms].
*
* The default value of {decimals} is 18. To change this, you should override
* this function so it returns a different value.
*
* 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}.
*
* 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 default value returned by this function, unless
* it's 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;
// Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by
// decrementing then incrementing.
_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;
unchecked {
// Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.
_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;
// Overflow not possible: amount <= accountBalance <= totalSupply.
_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
// 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 (last updated v4.9.4) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*
* ==== Security Considerations
*
* There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
* expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
* considered as an intention to spend the allowance in any specific way. The second is that because permits have
* built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
* take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
* generally recommended is:
*
* ```solidity
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
* try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
* doThing(..., value);
* }
*
* function doThing(..., uint256 value) public {
* token.safeTransferFrom(msg.sender, address(this), value);
* ...
* }
* ```
*
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
* `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
* {SafeERC20-safeTransferFrom}).
*
* Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
* contracts should have entry points that don't rely on permit.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*
* CAUTION: See Security Considerations above.
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.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 (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/IERC20Permit.sol";
import "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(IERC20 token, address spender, uint256 value) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
* Revert on invalid signature.
*/
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
// and not revert is the subcall reverts.
(bool success, bytes memory returndata) = address(token).call(data);
return
success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @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
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [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://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.0/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 functionCallWithValue(target, data, 0, "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");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, 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) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or 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 {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (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;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable2Step.sol)
pragma solidity 0.8.24;
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
/**
* @dev Contract module which provides access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* 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.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership} and {acceptOwnership}.
*
* This module is a variant of {Ownable} that requires the new owner to accept
* the ownership transfer before it can take effect. This provides an extra layer
* of safety by preventing accidental transfers to incorrect addresses.
*/
abstract contract Ownable2Step is Ownable {
address private _pendingOwner;
event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
/**
* @dev Returns the address of the pending owner.
*/
function pendingOwner() public view virtual returns (address) {
return _pendingOwner;
}
/**
* @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual override onlyOwner {
_pendingOwner = newOwner;
emit OwnershipTransferStarted(owner(), newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual override {
delete _pendingOwner;
super._transferOwnership(newOwner);
}
/**
* @dev The new owner accepts the ownership transfer.
*/
function acceptOwnership() public virtual {
address sender = _msgSender();
require(pendingOwner() == sender, "Ownable2Step: caller is not the new owner");
_transferOwnership(sender);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/ReentrancyGuardTransient.sol)
pragma solidity 0.8.24;
import {TransientSlot} from "./TransientSlot.sol";
/**
* @dev Variant of {ReentrancyGuard} that uses transient storage.
*
* NOTE: This variant only works on networks where EIP-1153 is available.
*
* _Available since v5.1._
*/
abstract contract ReentrancyGuardTransient {
using TransientSlot for *;
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant REENTRANCY_GUARD_STORAGE =
0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00;
/**
* @dev Unauthorized reentrant call.
*/
error ReentrancyGuardReentrantCall();
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be 0
if (_reentrancyGuardEntered()) {
revert ReentrancyGuardReentrantCall();
}
// Any calls to nonReentrant after this point will fail
REENTRANCY_GUARD_STORAGE.asBoolean().tstore(true);
}
function _nonReentrantAfter() private {
REENTRANCY_GUARD_STORAGE.asBoolean().tstore(false);
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return REENTRANCY_GUARD_STORAGE.asBoolean().tload();
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/TransientSlot.sol)
// Modified from OpenZeppelin implementation
pragma solidity 0.8.24;
/**
* @dev Library for reading and writing value-types to specific transient storage slots.
*
* Transient slots are often used to store temporary data that is only needed during a transaction.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* TIP: Consider using this library along with {SlotDerivation}.
*
* _Available since v5.1._
*/
library TransientSlot {
/**
* @dev UDVT that represent a slot holding a boolean.
*/
type BooleanSlot is bytes32;
/**
* @dev Cast a bytes32 to a BooleanSlot.
*/
function asBoolean(bytes32 slot) internal pure returns (BooleanSlot) {
return BooleanSlot.wrap(slot);
}
/**
* @dev Load the value held at location `slot` in transient storage.
*/
function tload(BooleanSlot slot) internal view returns (bool value) {
assembly ("memory-safe") {
value := tload(slot)
}
}
/**
* @dev Store `value` at location `slot` in transient storage.
*/
function tstore(BooleanSlot slot, bool value) internal {
assembly ("memory-safe") {
tstore(slot, value)
}
}
}{
"optimizer": {
"enabled": true,
"runs": 200
},
"viaIR": true,
"evmVersion": "cancun",
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_asset","type":"address"},{"internalType":"address","name":"_keeper","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AddressMustBeNonZero","type":"error"},{"inputs":[],"name":"AmountMustBeGreaterThanZero","type":"error"},{"inputs":[],"name":"ApprovalNotConsumed","type":"error"},{"inputs":[],"name":"CannotCompleteWithdrawalInSameEpoch","type":"error"},{"inputs":[],"name":"CannotRenounceOwnership","type":"error"},{"inputs":[],"name":"InsufficientBalance","type":"error"},{"inputs":[],"name":"InvalidAssetDecimals","type":"error"},{"inputs":[],"name":"KeeperAlreadyLocked","type":"error"},{"inputs":[],"name":"NotKeeper","type":"error"},{"inputs":[],"name":"OnlyOperator","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"vault","type":"address"}],"name":"AccountingApprovalConsumed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"AssetTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"oldValue","type":"bool"},{"indexed":false,"internalType":"bool","name":"newValue","type":"bool"}],"name":"AutoTransferSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"DepositToVault","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldKeeper","type":"address"},{"indexed":true,"internalType":"address","name":"newKeeper","type":"address"}],"name":"KeeperSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOperator","type":"address"},{"indexed":true,"internalType":"address","name":"newOperator","type":"address"}],"name":"OperatorUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"PermissionedBurn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"PermissionedMint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"vault","type":"address"},{"indexed":false,"internalType":"uint256","name":"totalStakedAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"accountingAmount","type":"uint256"}],"name":"RebalanceApprovalSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"vault","type":"address"}],"name":"TotalStakedApprovalConsumed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint224","name":"amount","type":"uint224"},{"indexed":true,"internalType":"uint32","name":"epoch","type":"uint32"}],"name":"WithdrawalInitiated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"withdrawalAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"balance","type":"uint256"},{"indexed":true,"internalType":"uint32","name":"epoch","type":"uint32"}],"name":"WithdrawalsProcessed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdrawn","type":"event"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"vault","type":"address"}],"name":"approvedAccountingAdjustment","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"vault","type":"address"}],"name":"approvedTotalStakedAdjustment","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"asset","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"autoTransfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"completeWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"consumeAccountingApproval","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"consumeTotalStakedApproval","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"currentEpoch","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"depositAmountForEpoch","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"depositToVault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint224","name":"amount","type":"uint224"}],"name":"initiateWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"uint224","name":"amount","type":"uint224"}],"name":"initiateWithdrawalFromVault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"keeper","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"operator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ownerBurn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ownerBurnAssetOnly","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ownerMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ownerMintAssetOnly","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"permissionedBurn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"permissionedMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"processWithdrawals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_enabled","type":"bool"}],"name":"setAutoTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_keeper","type":"address"}],"name":"setKeeper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOperator","type":"address"}],"name":"setOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferAsset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawalAmountForEpoch","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"withdrawalReceipts","outputs":[{"internalType":"uint224","name":"amount","type":"uint224"},{"internalType":"uint32","name":"epoch","type":"uint32"}],"stateMutability":"view","type":"function"}]Contract Creation Code
60a06040908082523462000293578181620023f58038038091620000248285620004b1565b83398101031262000293576200003a81620004d5565b906200004a6020809201620004d5565b90835192620000598462000495565b600a84526914da195c9c18481554d160b21b828501528451936200007d8562000495565b60098552681cda195c9c185554d160ba1b8386015280516001600160401b0390818111620003a0576003908154906001948583811c931680156200048a575b8884101462000476578190601f9384811162000423575b508890848311600114620003c0575f92620003b4575b50505f1982851b1c191690851b1782555b8751928311620003a05760049788548581811c9116801562000395575b8882101462000382578281116200033a575b5086918411600114620002d3579383949184925f95620002c7575b50501b925f19911b1c19161784555b6006549360018060a01b0319928386166006556005549460018060a01b03903386881617600555885196823391167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3818516968715620002b9575016948515620002a95781839189519283809263313ce56760e01b82525afa9182156200029f575f926200025a575b505060ff60069116036200024c575060805260078054919091169190911790556001600160c81b031916600160a01b1760065551611f0a9081620004eb823960805181818161031b0152818161084601528181610f570152818161121f015281816113c601526114150152f35b855163e236476560e01b8152fd5b90809250813d831162000297575b620002748183620004b1565b8101031262000293575160ff81168103620002935760ff6006620001df565b5f80fd5b503d62000268565b88513d5f823e3d90fd5b87516309be64cd60e41b81528390fd5b6309be64cd60e41b81528490fd5b015193505f8062000144565b9190601f19841692895f5284885f20945f5b8a8983831062000322575050501062000308575b50505050811b01845562000153565b01519060f8845f19921b161c191690555f808080620002f9565b868601518955909701969485019488935001620002e5565b895f52875f208380870160051c8201928a881062000378575b0160051c019086905b8281106200036c57505062000129565b5f81550186906200035c565b9250819262000353565b60228a634e487b7160e01b5f525260245ffd5b90607f169062000117565b634e487b7160e01b5f52604160045260245ffd5b015190505f80620000e9565b90879350601f19831691865f528a5f20925f5b8c8282106200040c5750508411620003f4575b505050811b018255620000fa565b01515f1983871b60f8161c191690555f8080620003e6565b8385015186558b97909501949384019301620003d3565b909150845f52885f208480850160051c8201928b86106200046c575b918991869594930160051c01915b8281106200045d575050620000d3565b5f81558594508991016200044d565b925081926200043f565b634e487b7160e01b5f52602260045260245ffd5b92607f1692620000bc565b604081019081106001600160401b03821117620003a057604052565b601f909101601f19168101906001600160401b03821190821017620003a057604052565b51906001600160a01b0382168203620002935756fe60806040818152600480361015610014575f80fd5b5f3560e01c92836306fdde03146115c957508263095ea7b3146115a05782630d342cab1461157a5782630f604a931461155c5782631799b6931461152557826318160ddd1461150757826323b872dd146114405782632a228fc2146112cc5782632b032f3e14611269578263313ce5671461124e57826338d52e0f1461120b57826339509351146111bf5782633f1ed28614611168578263484b973c1461109c578263570ca735146110745782635833275614610faa5782635c921eb914610ee6578263600f57ec14610ec85782636116a64a14610dee57826370a0823114610db8578263715018a614610d92578263748747e614610cf45782637667180814610ccd5782637963e6e814610c96578263798002f014610b8e57826379ba509714610ac55782638133df4114610a615782638c8dc93e146109e95782638da5cb5b146109c157826395d89b41146108bf5782639649b0a214610879578263a3d11158146107b8578263a457c2d714610715578263a9059cbb146106e5578263aced1661146106bd578263b3ab15fb1461063f578263be435c8c14610526578263c00017861461043d578263c761ac8a146103c3578263dd62ed3e1461037a578263e03ff7cb1461029057508163e30c397814610269575063f2fde38b146101f9575f80fd5b3461026557602036600319011261026557610212611701565b61021a611c7b565b600680546001600160a01b0319166001600160a01b039283169081179091556005549091167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e227005f80a3005b5f80fd5b34610265575f3660031901126102655760065490516001600160a01b039091168152602090f35b9034610265575f366003190112610265576102a96119fc565b335f526009602052805f209081549163ffffffff60065460a01c168360e01c1461036a576001600160e01b03831692831561035a57610348945063ffffffff60e01b169055518181527f7084f5476618d8e60b11ef0d7d3f06914655adb8793e28ff7f018d4c76d505d560203392a2337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316611a28565b5f5f80516020611eb58339815191525d005b8251635e85ae7360e01b81528590fd5b815163258e84af60e11b81528490fd5b5034610265578060031936011261026557602090610396611701565b61039e611717565b9060018060a01b038091165f5260018452825f2091165f528252805f20549051908152f35b346102655781600319360112610265576103db611701565b600754602435936001600160a01b039390918416330361042f575091817fffb73e7f272503f7f95a05a3a748beaef6216eb560391e2f075d54a5d5b574569361042686602095611bd9565b519485521692a2005b9051631ea2564f60e31b8152fd5b34610265578160031936011261026557610455611701565b916024359160018060a01b03806008541633141580610518575b61050957841692835f52602091600c8352835f20546104fb57845f52600d8352835f20546104fb57506104b1815f80516020611e958339815191529596611ad3565b845f52600c825280835f2055600d825280835f2055847f7333c4d498e1386177054f52d50ca759ef946eff3784f7f021387fd690508b97838551848152a2825191818352820152a2005b8351630c3e4b6960e01b8152fd5b5090516327e1f1e560e01b8152fd5b50806005541633141561046f565b903461026557806003193601126102655761053f611701565b6001600160e01b039160243583811692908390036102655761055f6119fc565b6007546001600160a01b039590861633036106315783156106235750916020916105fd7f69214d191a9e2c11156aedc11f80105e29875ef3eacdde4b6e9f08bfe162dfdb946105ae8430611ad3565b63ffffffff60065460a01c169788911696875f5260098652835f20908154906105d987828416611784565b6001600160e01b0391161660e09390931b6001600160e01b03191692909217905550565b61060982600a54611784565b600a5551908152a35f5f80516020611eb58339815191525d005b8251635e85ae7360e01b8152fd5b8251631ea2564f60e31b8152fd5b3461026557602036600319011261026557610658611701565b90610661611c7b565b6001600160a01b039182169283156106b0575050816008549182167ffbe5b6cbafb274f445d7fed869dc77a838d8243a22c460de156560e8857cad035f80a36001600160a01b03191617600855005b516309be64cd60e41b8152fd5b5034610265575f3660031901126102655760075490516001600160a01b039091168152602090f35b503461026557806003193601126102655760209061070e610704611701565b602435903361188f565b5160018152f35b3461026557816003193601126102655761072d611701565b9060243590335f526001602052835f2060018060a01b0384165f52602052835f2054908282106107675760208561070e8585038733611791565b608490602086519162461bcd60e51b8352820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b6064820152fd5b90346102655780600319360112610265576107d1611701565b90602435916107de6119fc565b60018060a01b039182600754169485330361042f57841561086b57506108078461034896611bd9565b61081384600b54611784565b600b55518381527f9f27a22fea017c09821db9e9e1700a69ddd6121050f29a783f8ca5f6876865f3602084841692a230917f000000000000000000000000000000000000000000000000000000000000000016611a7a565b9051635e85ae7360e01b8152fd5b5034610265576020366003190112610265576001600160a01b0361089b611701565b165f526009602052805f205481519060018060e01b038116825260e01c6020820152f35b9034610265575f366003190112610265578051905f9280549060018260011c91600184169384156109b7575b60209485851081146109a4578488529081156109825750600114610929575b610925868661091b828b038361172d565b51918291826116ba565b0390f35b5f9081529295507f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b5b82841061096f57505050826109259461091b92820101948661090a565b8054868501880152928601928101610952565b60ff191687860152505050151560051b830101925061091b826109258661090a565b602283634e487b7160e01b5f525260245ffd5b92607f16926108eb565b5034610265575f3660031901126102655760055490516001600160a01b039091168152602090f35b34610265576020366003190112610265573580151580910361026557610a0d611c7b565b7f2bb436f86a74bfec58ced75c2d4683e2e39e032fb9c840563779cf721d4c01f360065492805160ff8560c01c1615158152836020820152a160ff60c01b1990911660c09190911b60ff60c01b1617600655005b9034610265575f366003190112610265576007546001600160a01b03163303610ab8575f90338252600d602052812055337fffb4f3289d4365fe1c862e55093489781826fb46597d0332cc25bc86ea8900135f80a2005b51631ea2564f60e31b8152fd5b9034610265575f36600319011261026557600654916001600160a01b03913383851603610b395750506bffffffffffffffffffffffff60a01b8092166006556005549133908316176005553391167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3005b906020608492519162461bcd60e51b8352820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b6064820152fd5b34610265576020366003190112610265576001600160e01b038135818116929083900361026557610bbd6119fc565b8215610c8857335f525f60205282845f205410610c7a5750610bdf8233611ad3565b335f526009602052825f2090815490610bfa84828416611784565b166001600160e01b03199182168117835560065460401b9091166001600160e01b0390911617905563ffffffff610c3382600a54611784565b600a5560065460a01c1691519081527f69214d191a9e2c11156aedc11f80105e29875ef3eacdde4b6e9f08bfe162dfdb60203392a35f5f80516020611eb58339815191525d005b8351631e9acf1760e31b8152fd5b8351635e85ae7360e01b8152fd5b5034610265576020366003190112610265576020906001600160a01b03610cbb611701565b165f52600c8252805f20549051908152f35b5034610265575f3660031901126102655760209063ffffffff60065460a01c169051908152f35b903461026557602036600319011261026557610d0e611701565b610d16611c7b565b6008549260ff8460a01c16610d84576001600160a01b039182169283156106b0575050816007549182167f50697e88bd427923002f5d3844f352091c05c0c9c3b69e43830863d2224631735f80a36001600160a01b0319161760075560ff60a01b1916600160a01b17600855005b8251634f749a9f60e01b8152fd5b9034610265575f36600319011261026557610dab611c7b565b516377aeb0ad60e01b8152fd5b5034610265576020366003190112610265576020906001600160a01b03610ddd611701565b165f525f8252805f20549051908152f35b9034610265578060031936011261026557610e07611701565b60085460243591906001600160a01b0390811633141580610eba575b610eaa57811693845f52600c602052835f20546104fb57845f52600d602052835f20546104fb575090610e65815f80516020611e958339815191529493611ad3565b835f52600c60205280825f2055837f7333c4d498e1386177054f52d50ca759ef946eff3784f7f021387fd690508b9760208451848152a281519081525f6020820152a2005b505050516327e1f1e560e01b8152fd5b508060055416331415610e23565b5034610265575f36600319011261026557602090600b549051908152f35b9034610265578060031936011261026557610eff611701565b600854602435926001600160a01b0391821633141580610f9c575b610f8d578315610f7e57610f7c9450518381527fff67663330fcde57965a89e0eed2698c4f260f4f4dfa83e4d8a1c1db935fa235602083851692a27f000000000000000000000000000000000000000000000000000000000000000016611a28565b005b51635e85ae7360e01b81528490fd5b516327e1f1e560e01b81528490fd5b508160055416331415610f1a565b9034610265578060031936011261026557610fc3611701565b60085460243591906001600160a01b0390811633141580611066575b610eaa57811693845f52600c602052835f20546104fb57845f52600d602052835f20546104fb575090611021815f80516020611e958339815191529493611bd9565b835f52600c60205280825f2055837fffb73e7f272503f7f95a05a3a748beaef6216eb560391e2f075d54a5d5b5745660208451848152a281519081525f6020820152a2005b508060055416331415610fdf565b5034610265575f3660031901126102655760085490516001600160a01b039091168152602090f35b346102655781600319360112610265576110b4611701565b916024359160018060a01b0380600854163314158061115a575b61050957841692835f52602091600c8352835f20546104fb57845f52600d8352835f20546104fb5750611110815f80516020611e958339815191529596611bd9565b845f52600c825280835f2055600d825280835f2055847fffb73e7f272503f7f95a05a3a748beaef6216eb560391e2f075d54a5d5b57456838551848152a2825191818352820152a2005b5080600554163314156110ce565b9034610265575f366003190112610265576007546001600160a01b03163303610ab8575f90338252600c602052812055337f697f0af814bd455fd326a94770013355c95714822e64c84616592038423579685f80a2005b503461026557806003193601126102655760209061070e6111de611701565b335f5260018452825f2060018060a01b0382165f528452611204602435845f2054611784565b9033611791565b5034610265575f36600319011261026557517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b5034610265575f366003190112610265576020905160068152f35b34610265578160031936011261026557611281611701565b600754602435936001600160a01b039390918416330361042f575091817f7333c4d498e1386177054f52d50ca759ef946eff3784f7f021387fd690508b979361042686602095611ad3565b34610265575f366003190112610265576112e46119fc565b6007546001600160a01b03929083163303610ab85760ff6001917f28f43e09fc3816362a33b5a6e894df1b4208d2a6e5837169939cf0434af02655600a5491600b54926006549363ffffffff98898660a01c1696879660c01c166113a5575b5082519182526020820152a20191821161139257506006549063ffffffff60a01b9060a01b169063ffffffff60a01b1916176006555f600b555f600a555f5f80516020611eb58339815191525d005b601190634e487b7160e01b5f525260245ffd5b818311156113f157806113eb9160055416906113c18486611763565b9130917f000000000000000000000000000000000000000000000000000000000000000016611a7a565b89611343565b8183106113ff575b506113eb565b8061143a91600554166114128585611763565b917f000000000000000000000000000000000000000000000000000000000000000016611a28565b896113f9565b3461026557606036600319011261026557611459611701565b611461611717565b906044359260018060a01b0382165f526001602052845f20335f52602052845f2054905f19820361149b575b60208661070e87878761188f565b8482106114c457509183916114b96020969561070e95033383611791565b91939481935061148d565b606490602087519162461bcd60e51b8352820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152fd5b5034610265575f366003190112610265576020906002549051908152f35b5034610265576020366003190112610265576020906001600160a01b0361154a611701565b165f52600d8252805f20549051908152f35b5034610265575f36600319011261026557602090600a549051908152f35b5034610265575f3660031901126102655760209060ff60065460c01c1690519015158152f35b503461026557806003193601126102655760209061070e6115bf611701565b6024359033611791565b8234610265575f366003190112610265575f9260035460018160011c916001811680156116b0575b602094858510821461169d575083875290811561167d5750600114611623575b50505061091b8261092594038361172d565b60035f9081529295507fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b5b82841061166a57505050826109259461091b9282010194611611565b805486850188015292860192810161164e565b60ff1916868501525050151560051b830101925061091b82610925611611565b602290634e487b7160e01b5f525260245ffd5b92607f16926115f1565b602080825282518183018190529093925f5b8281106116ed57505060409293505f838284010152601f8019910116010190565b8181018601518482016040015285016116cc565b600435906001600160a01b038216820361026557565b602435906001600160a01b038216820361026557565b90601f8019910116810190811067ffffffffffffffff82111761174f57604052565b634e487b7160e01b5f52604160045260245ffd5b9190820391821161177057565b634e487b7160e01b5f52601160045260245ffd5b9190820180921161177057565b6001600160a01b0390811691821561183e57169182156117ee5760207f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591835f526001825260405f20855f5282528060405f2055604051908152a3565b60405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608490fd5b60405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608490fd5b6001600160a01b039081169182156119a9571691821561195857815f525f60205260405f205481811061190457817fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92602092855f525f84520360405f2055845f5260405f20818154019055604051908152a3565b60405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608490fd5b60405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608490fd5b60405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608490fd5b5f80516020611eb5833981519152805c611a16576001905d565b604051633ee5aeb560e01b8152600490fd5b60405163a9059cbb60e01b60208201526001600160a01b039092166024830152604480830193909352918152608081019167ffffffffffffffff83118284101761174f57611a7892604052611cd3565b565b6040516323b872dd60e01b60208201526001600160a01b03928316602482015292909116604483015260648083019390935291815260a081019181831067ffffffffffffffff84111761174f57611a7892604052611cd3565b6001600160a01b03168015611b8a57805f525f60205260405f205491808310611b3a576020817fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef925f958587528684520360408620558060025403600255604051908152a3565b60405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b6064820152608490fd5b60405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608490fd5b6001600160a01b0316908115611c36577fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef602082611c1a5f94600254611784565b60025584845283825260408420818154019055604051908152a3565b60405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606490fd5b6005546001600160a01b03163303611c8f57565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b60018060a01b03166040516040810167ffffffffffffffff908281108282111761174f576040525f806020958685527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c656487860152868151910182875af13d15611df6573d91821161174f57611d669360405192611d5987601f19601f840116018561172d565b83523d5f8785013e611dff565b8051828115918215611dd6575b5050905015611d7f5750565b6084906040519062461bcd60e51b82526004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152fd5b83809293500103126102655781015180151581036102655780825f611d73565b611d6693606092505b91929015611e615750815115611e13575090565b3b15611e1c5790565b60405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606490fd5b825190915015611e745750805190602001fd5b60405162461bcd60e51b8152908190611e9090600483016116ba565b0390fdfefdb4f5fa3f91a8b2135dbd3dcee0509a3f21279b7fb77dd29134a6279b97ffab9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00a2646970667358221220c2e046ac05063ca26cf06593759b87a98df8516504374e4832216268baa6236e64736f6c63430008180033000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda0291300000000000000000000000096043804d00dcec238718eedad9ac10719778380
Deployed Bytecode
0x60806040818152600480361015610014575f80fd5b5f3560e01c92836306fdde03146115c957508263095ea7b3146115a05782630d342cab1461157a5782630f604a931461155c5782631799b6931461152557826318160ddd1461150757826323b872dd146114405782632a228fc2146112cc5782632b032f3e14611269578263313ce5671461124e57826338d52e0f1461120b57826339509351146111bf5782633f1ed28614611168578263484b973c1461109c578263570ca735146110745782635833275614610faa5782635c921eb914610ee6578263600f57ec14610ec85782636116a64a14610dee57826370a0823114610db8578263715018a614610d92578263748747e614610cf45782637667180814610ccd5782637963e6e814610c96578263798002f014610b8e57826379ba509714610ac55782638133df4114610a615782638c8dc93e146109e95782638da5cb5b146109c157826395d89b41146108bf5782639649b0a214610879578263a3d11158146107b8578263a457c2d714610715578263a9059cbb146106e5578263aced1661146106bd578263b3ab15fb1461063f578263be435c8c14610526578263c00017861461043d578263c761ac8a146103c3578263dd62ed3e1461037a578263e03ff7cb1461029057508163e30c397814610269575063f2fde38b146101f9575f80fd5b3461026557602036600319011261026557610212611701565b61021a611c7b565b600680546001600160a01b0319166001600160a01b039283169081179091556005549091167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e227005f80a3005b5f80fd5b34610265575f3660031901126102655760065490516001600160a01b039091168152602090f35b9034610265575f366003190112610265576102a96119fc565b335f526009602052805f209081549163ffffffff60065460a01c168360e01c1461036a576001600160e01b03831692831561035a57610348945063ffffffff60e01b169055518181527f7084f5476618d8e60b11ef0d7d3f06914655adb8793e28ff7f018d4c76d505d560203392a2337f000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda029136001600160a01b0316611a28565b5f5f80516020611eb58339815191525d005b8251635e85ae7360e01b81528590fd5b815163258e84af60e11b81528490fd5b5034610265578060031936011261026557602090610396611701565b61039e611717565b9060018060a01b038091165f5260018452825f2091165f528252805f20549051908152f35b346102655781600319360112610265576103db611701565b600754602435936001600160a01b039390918416330361042f575091817fffb73e7f272503f7f95a05a3a748beaef6216eb560391e2f075d54a5d5b574569361042686602095611bd9565b519485521692a2005b9051631ea2564f60e31b8152fd5b34610265578160031936011261026557610455611701565b916024359160018060a01b03806008541633141580610518575b61050957841692835f52602091600c8352835f20546104fb57845f52600d8352835f20546104fb57506104b1815f80516020611e958339815191529596611ad3565b845f52600c825280835f2055600d825280835f2055847f7333c4d498e1386177054f52d50ca759ef946eff3784f7f021387fd690508b97838551848152a2825191818352820152a2005b8351630c3e4b6960e01b8152fd5b5090516327e1f1e560e01b8152fd5b50806005541633141561046f565b903461026557806003193601126102655761053f611701565b6001600160e01b039160243583811692908390036102655761055f6119fc565b6007546001600160a01b039590861633036106315783156106235750916020916105fd7f69214d191a9e2c11156aedc11f80105e29875ef3eacdde4b6e9f08bfe162dfdb946105ae8430611ad3565b63ffffffff60065460a01c169788911696875f5260098652835f20908154906105d987828416611784565b6001600160e01b0391161660e09390931b6001600160e01b03191692909217905550565b61060982600a54611784565b600a5551908152a35f5f80516020611eb58339815191525d005b8251635e85ae7360e01b8152fd5b8251631ea2564f60e31b8152fd5b3461026557602036600319011261026557610658611701565b90610661611c7b565b6001600160a01b039182169283156106b0575050816008549182167ffbe5b6cbafb274f445d7fed869dc77a838d8243a22c460de156560e8857cad035f80a36001600160a01b03191617600855005b516309be64cd60e41b8152fd5b5034610265575f3660031901126102655760075490516001600160a01b039091168152602090f35b503461026557806003193601126102655760209061070e610704611701565b602435903361188f565b5160018152f35b3461026557816003193601126102655761072d611701565b9060243590335f526001602052835f2060018060a01b0384165f52602052835f2054908282106107675760208561070e8585038733611791565b608490602086519162461bcd60e51b8352820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b6064820152fd5b90346102655780600319360112610265576107d1611701565b90602435916107de6119fc565b60018060a01b039182600754169485330361042f57841561086b57506108078461034896611bd9565b61081384600b54611784565b600b55518381527f9f27a22fea017c09821db9e9e1700a69ddd6121050f29a783f8ca5f6876865f3602084841692a230917f000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda0291316611a7a565b9051635e85ae7360e01b8152fd5b5034610265576020366003190112610265576001600160a01b0361089b611701565b165f526009602052805f205481519060018060e01b038116825260e01c6020820152f35b9034610265575f366003190112610265578051905f9280549060018260011c91600184169384156109b7575b60209485851081146109a4578488529081156109825750600114610929575b610925868661091b828b038361172d565b51918291826116ba565b0390f35b5f9081529295507f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b5b82841061096f57505050826109259461091b92820101948661090a565b8054868501880152928601928101610952565b60ff191687860152505050151560051b830101925061091b826109258661090a565b602283634e487b7160e01b5f525260245ffd5b92607f16926108eb565b5034610265575f3660031901126102655760055490516001600160a01b039091168152602090f35b34610265576020366003190112610265573580151580910361026557610a0d611c7b565b7f2bb436f86a74bfec58ced75c2d4683e2e39e032fb9c840563779cf721d4c01f360065492805160ff8560c01c1615158152836020820152a160ff60c01b1990911660c09190911b60ff60c01b1617600655005b9034610265575f366003190112610265576007546001600160a01b03163303610ab8575f90338252600d602052812055337fffb4f3289d4365fe1c862e55093489781826fb46597d0332cc25bc86ea8900135f80a2005b51631ea2564f60e31b8152fd5b9034610265575f36600319011261026557600654916001600160a01b03913383851603610b395750506bffffffffffffffffffffffff60a01b8092166006556005549133908316176005553391167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3005b906020608492519162461bcd60e51b8352820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b6064820152fd5b34610265576020366003190112610265576001600160e01b038135818116929083900361026557610bbd6119fc565b8215610c8857335f525f60205282845f205410610c7a5750610bdf8233611ad3565b335f526009602052825f2090815490610bfa84828416611784565b166001600160e01b03199182168117835560065460401b9091166001600160e01b0390911617905563ffffffff610c3382600a54611784565b600a5560065460a01c1691519081527f69214d191a9e2c11156aedc11f80105e29875ef3eacdde4b6e9f08bfe162dfdb60203392a35f5f80516020611eb58339815191525d005b8351631e9acf1760e31b8152fd5b8351635e85ae7360e01b8152fd5b5034610265576020366003190112610265576020906001600160a01b03610cbb611701565b165f52600c8252805f20549051908152f35b5034610265575f3660031901126102655760209063ffffffff60065460a01c169051908152f35b903461026557602036600319011261026557610d0e611701565b610d16611c7b565b6008549260ff8460a01c16610d84576001600160a01b039182169283156106b0575050816007549182167f50697e88bd427923002f5d3844f352091c05c0c9c3b69e43830863d2224631735f80a36001600160a01b0319161760075560ff60a01b1916600160a01b17600855005b8251634f749a9f60e01b8152fd5b9034610265575f36600319011261026557610dab611c7b565b516377aeb0ad60e01b8152fd5b5034610265576020366003190112610265576020906001600160a01b03610ddd611701565b165f525f8252805f20549051908152f35b9034610265578060031936011261026557610e07611701565b60085460243591906001600160a01b0390811633141580610eba575b610eaa57811693845f52600c602052835f20546104fb57845f52600d602052835f20546104fb575090610e65815f80516020611e958339815191529493611ad3565b835f52600c60205280825f2055837f7333c4d498e1386177054f52d50ca759ef946eff3784f7f021387fd690508b9760208451848152a281519081525f6020820152a2005b505050516327e1f1e560e01b8152fd5b508060055416331415610e23565b5034610265575f36600319011261026557602090600b549051908152f35b9034610265578060031936011261026557610eff611701565b600854602435926001600160a01b0391821633141580610f9c575b610f8d578315610f7e57610f7c9450518381527fff67663330fcde57965a89e0eed2698c4f260f4f4dfa83e4d8a1c1db935fa235602083851692a27f000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda0291316611a28565b005b51635e85ae7360e01b81528490fd5b516327e1f1e560e01b81528490fd5b508160055416331415610f1a565b9034610265578060031936011261026557610fc3611701565b60085460243591906001600160a01b0390811633141580611066575b610eaa57811693845f52600c602052835f20546104fb57845f52600d602052835f20546104fb575090611021815f80516020611e958339815191529493611bd9565b835f52600c60205280825f2055837fffb73e7f272503f7f95a05a3a748beaef6216eb560391e2f075d54a5d5b5745660208451848152a281519081525f6020820152a2005b508060055416331415610fdf565b5034610265575f3660031901126102655760085490516001600160a01b039091168152602090f35b346102655781600319360112610265576110b4611701565b916024359160018060a01b0380600854163314158061115a575b61050957841692835f52602091600c8352835f20546104fb57845f52600d8352835f20546104fb5750611110815f80516020611e958339815191529596611bd9565b845f52600c825280835f2055600d825280835f2055847fffb73e7f272503f7f95a05a3a748beaef6216eb560391e2f075d54a5d5b57456838551848152a2825191818352820152a2005b5080600554163314156110ce565b9034610265575f366003190112610265576007546001600160a01b03163303610ab8575f90338252600c602052812055337f697f0af814bd455fd326a94770013355c95714822e64c84616592038423579685f80a2005b503461026557806003193601126102655760209061070e6111de611701565b335f5260018452825f2060018060a01b0382165f528452611204602435845f2054611784565b9033611791565b5034610265575f36600319011261026557517f000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda029136001600160a01b03168152602090f35b5034610265575f366003190112610265576020905160068152f35b34610265578160031936011261026557611281611701565b600754602435936001600160a01b039390918416330361042f575091817f7333c4d498e1386177054f52d50ca759ef946eff3784f7f021387fd690508b979361042686602095611ad3565b34610265575f366003190112610265576112e46119fc565b6007546001600160a01b03929083163303610ab85760ff6001917f28f43e09fc3816362a33b5a6e894df1b4208d2a6e5837169939cf0434af02655600a5491600b54926006549363ffffffff98898660a01c1696879660c01c166113a5575b5082519182526020820152a20191821161139257506006549063ffffffff60a01b9060a01b169063ffffffff60a01b1916176006555f600b555f600a555f5f80516020611eb58339815191525d005b601190634e487b7160e01b5f525260245ffd5b818311156113f157806113eb9160055416906113c18486611763565b9130917f000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda0291316611a7a565b89611343565b8183106113ff575b506113eb565b8061143a91600554166114128585611763565b917f000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda0291316611a28565b896113f9565b3461026557606036600319011261026557611459611701565b611461611717565b906044359260018060a01b0382165f526001602052845f20335f52602052845f2054905f19820361149b575b60208661070e87878761188f565b8482106114c457509183916114b96020969561070e95033383611791565b91939481935061148d565b606490602087519162461bcd60e51b8352820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152fd5b5034610265575f366003190112610265576020906002549051908152f35b5034610265576020366003190112610265576020906001600160a01b0361154a611701565b165f52600d8252805f20549051908152f35b5034610265575f36600319011261026557602090600a549051908152f35b5034610265575f3660031901126102655760209060ff60065460c01c1690519015158152f35b503461026557806003193601126102655760209061070e6115bf611701565b6024359033611791565b8234610265575f366003190112610265575f9260035460018160011c916001811680156116b0575b602094858510821461169d575083875290811561167d5750600114611623575b50505061091b8261092594038361172d565b60035f9081529295507fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b5b82841061166a57505050826109259461091b9282010194611611565b805486850188015292860192810161164e565b60ff1916868501525050151560051b830101925061091b82610925611611565b602290634e487b7160e01b5f525260245ffd5b92607f16926115f1565b602080825282518183018190529093925f5b8281106116ed57505060409293505f838284010152601f8019910116010190565b8181018601518482016040015285016116cc565b600435906001600160a01b038216820361026557565b602435906001600160a01b038216820361026557565b90601f8019910116810190811067ffffffffffffffff82111761174f57604052565b634e487b7160e01b5f52604160045260245ffd5b9190820391821161177057565b634e487b7160e01b5f52601160045260245ffd5b9190820180921161177057565b6001600160a01b0390811691821561183e57169182156117ee5760207f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591835f526001825260405f20855f5282528060405f2055604051908152a3565b60405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608490fd5b60405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608490fd5b6001600160a01b039081169182156119a9571691821561195857815f525f60205260405f205481811061190457817fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92602092855f525f84520360405f2055845f5260405f20818154019055604051908152a3565b60405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608490fd5b60405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608490fd5b60405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608490fd5b5f80516020611eb5833981519152805c611a16576001905d565b604051633ee5aeb560e01b8152600490fd5b60405163a9059cbb60e01b60208201526001600160a01b039092166024830152604480830193909352918152608081019167ffffffffffffffff83118284101761174f57611a7892604052611cd3565b565b6040516323b872dd60e01b60208201526001600160a01b03928316602482015292909116604483015260648083019390935291815260a081019181831067ffffffffffffffff84111761174f57611a7892604052611cd3565b6001600160a01b03168015611b8a57805f525f60205260405f205491808310611b3a576020817fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef925f958587528684520360408620558060025403600255604051908152a3565b60405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b6064820152608490fd5b60405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608490fd5b6001600160a01b0316908115611c36577fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef602082611c1a5f94600254611784565b60025584845283825260408420818154019055604051908152a3565b60405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606490fd5b6005546001600160a01b03163303611c8f57565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b60018060a01b03166040516040810167ffffffffffffffff908281108282111761174f576040525f806020958685527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c656487860152868151910182875af13d15611df6573d91821161174f57611d669360405192611d5987601f19601f840116018561172d565b83523d5f8785013e611dff565b8051828115918215611dd6575b5050905015611d7f5750565b6084906040519062461bcd60e51b82526004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152fd5b83809293500103126102655781015180151581036102655780825f611d73565b611d6693606092505b91929015611e615750815115611e13575090565b3b15611e1c5790565b60405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606490fd5b825190915015611e745750805190602001fd5b60405162461bcd60e51b8152908190611e9090600483016116ba565b0390fdfefdb4f5fa3f91a8b2135dbd3dcee0509a3f21279b7fb77dd29134a6279b97ffab9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00a2646970667358221220c2e046ac05063ca26cf06593759b87a98df8516504374e4832216268baa6236e64736f6c63430008180033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda0291300000000000000000000000096043804d00dcec238718eedad9ac10719778380
-----Decoded View---------------
Arg [0] : _asset (address): 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913
Arg [1] : _keeper (address): 0x96043804D00DCeC238718EEDaD9ac10719778380
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda02913
Arg [1] : 00000000000000000000000096043804d00dcec238718eedad9ac10719778380
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.