Token
Phinance.Gold (PHIGOLD)
ERC-20
Overview
Max Total Supply
10,000 PHIGOLD
Holders
35
Total Transfers
-
Market
Price
$0.00 @ 0.000000 POL
Onchain Market Cap
$0.00
Circulating Supply Market Cap
-
Other Info
Token Contract (WITH 6 Decimals)
Loading...
Loading
Loading...
Loading
Loading...
Loading
Contract Name:
PhiPay
Compiler Version
v0.8.20+commit.a1b79de6
Optimization Enabled:
Yes with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import '@openzeppelin/contracts/token/ERC20/ERC20.sol'; import '@openzeppelin/contracts/token/ERC20/IERC20.sol'; import '@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol'; import '@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol'; import '@openzeppelin/contracts/token/ERC20/extensions/ERC20Pausable.sol'; import '@openzeppelin/contracts/access/Ownable.sol'; import '@openzeppelin/contracts/token/ERC721/IERC721.sol'; import '@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol'; import '@openzeppelin/contracts/metatx/ERC2771Context.sol'; interface IPhigoldBond is IERC721 { struct Bond { uint256 phigoldAmount; uint256 maturityDate; bool redeemed; uint8 status; bytes32 purchaseOrderHash; bytes32 auditReportHash; } function getBondDetails(uint256 tokenId) external view returns (Bond memory); function setRedeemed(uint256 tokenId) external; function burn(uint256 tokenId) external; } contract PhiPay is ERC20, ERC20Burnable, ERC20Pausable, Ownable, ERC721Holder, ERC2771Context { uint256 phigoldUsdPrice = 70000000; uint256 supportedTokenCount; IPhigoldBond public phigoldBondContract; address private feeAccount; uint256 public phipayFeeRate = 200; mapping(address => TokenInfo) public supportedTokens; mapping(uint256 => string) public mintAuditReports; mapping(address => uint256) public nonces; mapping(address => bool) public isAdmin; modifier onlyAdmins() { require(isAdmin[msg.sender], 'Only admins can call this function'); _; } struct TokenInfo { IERC20 paymentToken; uint256 decimals; uint256 exchangeRate; } event MintEvent(address triggerer, uint256 amount, uint256 timestamp, string auditReportLink); event PurchaseOrderEvent(address triggerer, uint256 amount, uint256 timestamp, string purchaseOrderLink); event VaultDepositEvent(address triggerer, uint256 amount, uint256 timestamp, string auditReportLink); event VaultWithdrawalEvent(address triggerer, uint256 amount, uint256 timestamp, string auditReportLink); event BurnEvent(address triggerer, uint256 amount, uint256 timestamp, string auditReportLink); event PurchaseCompleted(address sender, address recipient, uint256 amount, uint256 timestamp, string sku); event SwapCompleted( address sender, uint256 paidAmount, uint256 receivedAmount, address paymentTokenAddress, string receivedToken, uint256 timestamp ); event FeePaid(address feeAccount, uint256 feeAmount, uint256 timestamp); event BondRedeemed(uint256 tokenId, address redeemer, uint256 amount, uint timestamp); event FeeAccountUpdated(address newFeeAccount, uint256 timestamp); constructor( address trustedForwarder ) ERC20('Phinance.Gold', 'PHIGOLD') Ownable(msg.sender) ERC2771Context(trustedForwarder) { feeAccount = owner(); isAdmin[msg.sender] = true; isAdmin[0x0D58CCB8F40C46AFf980DD7457EE346f92908f29] = true; } modifier onlyTrustedForwarder() { require(msg.sender == trustedForwarder(), 'Caller is not the trusted forwarder'); _; } function _update(address from, address to, uint256 value) internal override(ERC20, ERC20Pausable) { super._update(from, to, value); } function getNonce(address user) public view returns (uint256) { return nonces[user]; } function setFeeAccount(address _feeAccount) public onlyOwner { feeAccount = _feeAccount; emit FeeAccountUpdated(_feeAccount, block.timestamp); } function _transferWithFee( address sender, address recipient, uint256 amount, uint256 _feeRate ) internal returns (bool) { require(recipient != address(0), 'Recipient address must be provided'); require(amount != 0, 'Phigold amount must be greater than 0'); uint256 feeRate = _feeRate != 0 ? _feeRate : phipayFeeRate; uint256 fee = (amount * feeRate) / 10000; uint256 totalAmount = amount + fee; require(balanceOf(sender) >= totalAmount, 'Insufficient balance'); _transfer(sender, recipient, amount); if (fee != 0) { _transfer(sender, feeAccount, fee); emit FeePaid(feeAccount, fee, block.timestamp); } return true; } function forwardedMakePurchase( address sender, address recipient, uint256 amount, string memory sku, uint256 nonce, uint256 _feeRate ) public onlyTrustedForwarder { require(nonces[sender] == nonce, 'Invalid nonce'); nonces[sender]++; require(_transferWithFee(sender, recipient, amount, _feeRate)); emit PurchaseCompleted(sender, recipient, amount, block.timestamp, sku); } function forwardedTransferWithFee( address sender, address recipient, uint256 amount, uint256 nonce, uint256 _feeRate ) public onlyTrustedForwarder { require(nonces[sender] == nonce, 'Invalid nonce'); nonces[sender]++; require(_transferWithFee(sender, recipient, amount, _feeRate)); } function makePurchase(address recipient, uint256 amount, string memory sku, uint256 _feeRate) public { require(_transferWithFee(msg.sender, recipient, amount, _feeRate)); emit PurchaseCompleted(msg.sender, recipient, amount, block.timestamp, sku); } function isValidIPFSAddress(string memory _ipfsAddress) internal pure returns (bool) { bytes memory addressBytes = bytes(_ipfsAddress); if (addressBytes.length == 46 && addressBytes[0] == 'Q' && addressBytes[1] == 'm') { return true; // CIDv0 } if (addressBytes.length == 59 && addressBytes[0] == 'b') { return true; // CIDv1 } return false; } function addSupportedToken(address _tokenAddress, uint256 _tokenDecimals, uint256 _exchangeRate) public onlyOwner { require(_tokenAddress != address(0), 'Token address must be provided'); require(_tokenDecimals != 0, 'Number of decimals must be greater than 0'); require(_exchangeRate != 0, 'Exchange Rate must be greater than 0'); supportedTokens[_tokenAddress] = TokenInfo(IERC20(_tokenAddress), _tokenDecimals, _exchangeRate); supportedTokenCount++; } function removeSupportedToken(address _tokenAddress) public onlyOwner { require(_tokenAddress != address(0), 'Token address must be provided'); require(supportedTokens[_tokenAddress].paymentToken != IERC20(address(0)), 'Token not found'); delete supportedTokens[_tokenAddress]; supportedTokenCount--; } function getSupportedTokenCount() public view returns (uint256) { return supportedTokenCount; } function setUsdExchangeRate(uint256 _newPhigoldUsdPrice) public onlyAdmins { phigoldUsdPrice = _newPhigoldUsdPrice; } function checkIsAdmin(address _adminAccount) public view returns (bool) { return isAdmin[_adminAccount]; } function setAdminAccount(address _adminAccount) public onlyOwner { isAdmin[_adminAccount] = true; } function removeAdminAccount(address _adminAccount) public onlyOwner { isAdmin[_adminAccount] = false; } function setPaymentTokenExchangeRate(address _paymentTokenAddress, uint256 _newExchangeRate) public onlyOwner { supportedTokens[_paymentTokenAddress].exchangeRate = _newExchangeRate; } function getPaymentTokenExchangeRate(address _paymentTokenAddress) public view returns (uint256) { return supportedTokens[_paymentTokenAddress].exchangeRate; } function getUsdExchangeRate() public view returns (uint256) { return phigoldUsdPrice; } function mintPhigoldSupply(uint256 _amount, string memory _ipfsAuditReportLink) public onlyAdmins { require(bytes(_ipfsAuditReportLink).length != 0, 'Audit report IPFS link must be provided'); require(isValidIPFSAddress(_ipfsAuditReportLink), 'Invalid IPFS address format'); _mint(address(this), _amount); emit MintEvent(_msgSender(), _amount, block.timestamp, _ipfsAuditReportLink); } function swapSupportedTokenForPhigold(address _paymentTokenAddress, uint256 _phigoldAmount, bool _isUsd) public { TokenInfo storage tokenInfo = supportedTokens[_paymentTokenAddress]; uint256 phigoldDecimals = decimals(); uint256 exchangeRate = _isUsd ? phigoldUsdPrice : tokenInfo.exchangeRate; uint256 paymentTokenDecimals = tokenInfo.decimals; uint256 paymentTokenAmount; if (paymentTokenDecimals > phigoldDecimals) { uint256 decimalsDifference = paymentTokenDecimals - phigoldDecimals; paymentTokenAmount = (_phigoldAmount * exchangeRate) / (10 ** decimalsDifference) / 1000000; } else { uint256 decimalsDifference = phigoldDecimals - paymentTokenDecimals; paymentTokenAmount = ((_phigoldAmount * exchangeRate) * (10 ** decimalsDifference)) / 1000000; } require(paymentTokenAmount != 0, 'Payment token amount must be greater than 0'); require( tokenInfo.paymentToken.balanceOf(_msgSender()) >= paymentTokenAmount, 'Insufficient payment token balance' ); require( tokenInfo.paymentToken.allowance(_msgSender(), address(this)) >= paymentTokenAmount, 'Insufficient payment token allowance' ); require( tokenInfo.paymentToken.transferFrom(_msgSender(), owner(), paymentTokenAmount), 'Payment token transfer failed' ); _transfer(address(this), _msgSender(), _phigoldAmount); emit SwapCompleted( _msgSender(), paymentTokenAmount, _phigoldAmount, _paymentTokenAddress, this.symbol(), block.timestamp ); } function forwardedSwapWithPermit( address sender, address paymentTokenAddress, uint256 permittedSpendAmount, uint256 phigoldAmount, bool isUsd, uint256 deadline, uint8 v, bytes32 r, bytes32 s, uint256 phipayNonce ) public onlyTrustedForwarder { require(nonces[sender] == phipayNonce, 'Invalid PhiPay nonce'); nonces[sender]++; IERC20Permit(paymentTokenAddress).permit(sender, address(this), permittedSpendAmount, deadline, v, r, s); TokenInfo storage tokenInfo = supportedTokens[paymentTokenAddress]; uint256 phigoldDecimals = decimals(); uint256 exchangeRate = isUsd ? phigoldUsdPrice : tokenInfo.exchangeRate; uint256 paymentTokenDecimals = tokenInfo.decimals; uint256 paymentTokenAmount; if (paymentTokenDecimals > phigoldDecimals) { uint256 decimalsDifference = paymentTokenDecimals - phigoldDecimals; paymentTokenAmount = (phigoldAmount * exchangeRate) / (10 ** decimalsDifference) / 1000000; } else { uint256 decimalsDifference = phigoldDecimals - paymentTokenDecimals; paymentTokenAmount = ((phigoldAmount * exchangeRate) * (10 ** decimalsDifference)) / 1000000; } require(paymentTokenAmount != 0, 'Payment token amount must be greater than 0'); require( IERC20(paymentTokenAddress).balanceOf(sender) >= paymentTokenAmount, 'Insufficient payment token balance' ); require( IERC20(paymentTokenAddress).allowance(sender, address(this)) >= paymentTokenAmount, 'Insufficient payment token allowance' ); require( IERC20(paymentTokenAddress).transferFrom(sender, owner(), paymentTokenAmount), 'Payment token transfer failed' ); _transfer(address(this), sender, phigoldAmount); emit SwapCompleted( sender, paymentTokenAmount, phigoldAmount, paymentTokenAddress, this.symbol(), block.timestamp ); } function redeemPhigold(uint256 _amount, string memory _purchaseId) public { require(_amount != 0, 'Phigold amount must be greater than 0'); _burn(_msgSender(), _amount); emit BurnEvent( _msgSender(), _amount, block.timestamp, string(abi.encodePacked('Phigold Redeemed: ', _purchaseId)) ); } function withdrawERC20Token(address _tokenAddress) public onlyOwner { IERC20 token = IERC20(_tokenAddress); require(token.balanceOf(address(this)) != 0, 'Insufficient payment token balance'); uint256 amount = token.balanceOf(address(this)); token.transfer(_msgSender(), amount); } function decimals() public pure override returns (uint8) { return 6; } function pause() public onlyOwner { _pause(); } function unpause() public onlyOwner { _unpause(); } function setPhigoldBondContract(address _bondContractAddress) public onlyOwner { phigoldBondContract = IPhigoldBond(_bondContractAddress); } function redeemPhigoldBond(uint256 _tokenId) public { require(address(phigoldBondContract) != address(0), 'PhigoldBond contract not set'); require(phigoldBondContract.ownerOf(_tokenId) == _msgSender(), 'Not the bond owner'); IPhigoldBond bondContract = IPhigoldBond(address(phigoldBondContract)); IPhigoldBond.Bond memory bond = bondContract.getBondDetails(_tokenId); require(block.timestamp >= bond.maturityDate, 'Bond not yet matured'); require(!bond.redeemed, 'Bond already redeemed'); require(bond.status == 2, 'Bond must be in the Vaulted status'); require( phigoldBondContract.getApproved(_tokenId) == address(this) || phigoldBondContract.isApprovedForAll(_msgSender(), address(this)), 'PhiPay not approved to transfer bond' ); phigoldBondContract.burn(_tokenId); bondContract.setRedeemed(_tokenId); _transfer(address(this), _msgSender(), bond.phigoldAmount); emit BondRedeemed(_tokenId, _msgSender(), bond.phigoldAmount, block.timestamp); } // Override _msgSender() to support EIP-2771 function _msgSender() internal view override(Context, ERC2771Context) returns (address sender) { return ERC2771Context._msgSender(); } // Override _msgData() to support EIP-2771 function _msgData() internal view override(Context, ERC2771Context) returns (bytes calldata) { return ERC2771Context._msgData(); } function _contextSuffixLength() internal view override(Context, ERC2771Context) returns (uint256) { return ERC2771Context._contextSuffixLength(); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol) pragma solidity ^0.8.20; import {Context} from "../utils/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * The initial owner is set to the address provided by the deployer. This can * later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; /** * @dev The caller account is not authorized to perform an operation. */ error OwnableUnauthorizedAccount(address account); /** * @dev The owner is not a valid owner account. (eg. `address(0)`) */ error OwnableInvalidOwner(address owner); event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the address provided by the deployer as the initial owner. */ constructor(address initialOwner) { if (initialOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(initialOwner); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { if (owner() != _msgSender()) { revert OwnableUnauthorizedAccount(_msgSender()); } } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { if (newOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol) pragma solidity ^0.8.20; /** * @dev Standard ERC20 Errors * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC20 tokens. */ interface IERC20Errors { /** * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. * @param balance Current balance for the interacting account. * @param needed Minimum amount required to perform a transfer. */ error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed); /** * @dev Indicates a failure with the token `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. */ error ERC20InvalidSender(address sender); /** * @dev Indicates a failure with the token `receiver`. Used in transfers. * @param receiver Address to which tokens are being transferred. */ error ERC20InvalidReceiver(address receiver); /** * @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers. * @param spender Address that may be allowed to operate on tokens without being their owner. * @param allowance Amount of tokens a `spender` is allowed to operate with. * @param needed Minimum amount required to perform a transfer. */ error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed); /** * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals. * @param approver Address initiating an approval operation. */ error ERC20InvalidApprover(address approver); /** * @dev Indicates a failure with the `spender` to be approved. Used in approvals. * @param spender Address that may be allowed to operate on tokens without being their owner. */ error ERC20InvalidSpender(address spender); } /** * @dev Standard ERC721 Errors * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC721 tokens. */ interface IERC721Errors { /** * @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in EIP-20. * Used in balance queries. * @param owner Address of the current owner of a token. */ error ERC721InvalidOwner(address owner); /** * @dev Indicates a `tokenId` whose `owner` is the zero address. * @param tokenId Identifier number of a token. */ error ERC721NonexistentToken(uint256 tokenId); /** * @dev Indicates an error related to the ownership over a particular token. Used in transfers. * @param sender Address whose tokens are being transferred. * @param tokenId Identifier number of a token. * @param owner Address of the current owner of a token. */ error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner); /** * @dev Indicates a failure with the token `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. */ error ERC721InvalidSender(address sender); /** * @dev Indicates a failure with the token `receiver`. Used in transfers. * @param receiver Address to which tokens are being transferred. */ error ERC721InvalidReceiver(address receiver); /** * @dev Indicates a failure with the `operator`’s approval. Used in transfers. * @param operator Address that may be allowed to operate on tokens without being their owner. * @param tokenId Identifier number of a token. */ error ERC721InsufficientApproval(address operator, uint256 tokenId); /** * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals. * @param approver Address initiating an approval operation. */ error ERC721InvalidApprover(address approver); /** * @dev Indicates a failure with the `operator` to be approved. Used in approvals. * @param operator Address that may be allowed to operate on tokens without being their owner. */ error ERC721InvalidOperator(address operator); } /** * @dev Standard ERC1155 Errors * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC1155 tokens. */ interface IERC1155Errors { /** * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. * @param balance Current balance for the interacting account. * @param needed Minimum amount required to perform a transfer. * @param tokenId Identifier number of a token. */ error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId); /** * @dev Indicates a failure with the token `sender`. Used in transfers. * @param sender Address whose tokens are being transferred. */ error ERC1155InvalidSender(address sender); /** * @dev Indicates a failure with the token `receiver`. Used in transfers. * @param receiver Address to which tokens are being transferred. */ error ERC1155InvalidReceiver(address receiver); /** * @dev Indicates a failure with the `operator`’s approval. Used in transfers. * @param operator Address that may be allowed to operate on tokens without being their owner. * @param owner Address of the current owner of a token. */ error ERC1155MissingApprovalForAll(address operator, address owner); /** * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals. * @param approver Address initiating an approval operation. */ error ERC1155InvalidApprover(address approver); /** * @dev Indicates a failure with the `operator` to be approved. Used in approvals. * @param operator Address that may be allowed to operate on tokens without being their owner. */ error ERC1155InvalidOperator(address operator); /** * @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation. * Used in batch transfers. * @param idsLength Length of the array of token identifiers * @param valuesLength Length of the array of token amounts */ error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.1) (metatx/ERC2771Context.sol) pragma solidity ^0.8.20; import {Context} from "../utils/Context.sol"; /** * @dev Context variant with ERC2771 support. * * WARNING: Avoid using this pattern in contracts that rely in a specific calldata length as they'll * be affected by any forwarder whose `msg.data` is suffixed with the `from` address according to the ERC2771 * specification adding the address size in bytes (20) to the calldata size. An example of an unexpected * behavior could be an unintended fallback (or another function) invocation while trying to invoke the `receive` * function only accessible if `msg.data.length == 0`. * * WARNING: The usage of `delegatecall` in this contract is dangerous and may result in context corruption. * Any forwarded request to this contract triggering a `delegatecall` to itself will result in an invalid {_msgSender} * recovery. */ abstract contract ERC2771Context is Context { /// @custom:oz-upgrades-unsafe-allow state-variable-immutable address private immutable _trustedForwarder; /** * @dev Initializes the contract with a trusted forwarder, which will be able to * invoke functions on this contract on behalf of other accounts. * * NOTE: The trusted forwarder can be replaced by overriding {trustedForwarder}. */ /// @custom:oz-upgrades-unsafe-allow constructor constructor(address trustedForwarder_) { _trustedForwarder = trustedForwarder_; } /** * @dev Returns the address of the trusted forwarder. */ function trustedForwarder() public view virtual returns (address) { return _trustedForwarder; } /** * @dev Indicates whether any particular address is the trusted forwarder. */ function isTrustedForwarder(address forwarder) public view virtual returns (bool) { return forwarder == trustedForwarder(); } /** * @dev Override for `msg.sender`. Defaults to the original `msg.sender` whenever * a call is not performed by the trusted forwarder or the calldata length is less than * 20 bytes (an address length). */ function _msgSender() internal view virtual override returns (address) { uint256 calldataLength = msg.data.length; uint256 contextSuffixLength = _contextSuffixLength(); if (isTrustedForwarder(msg.sender) && calldataLength >= contextSuffixLength) { return address(bytes20(msg.data[calldataLength - contextSuffixLength:])); } else { return super._msgSender(); } } /** * @dev Override for `msg.data`. Defaults to the original `msg.data` whenever * a call is not performed by the trusted forwarder or the calldata length is less than * 20 bytes (an address length). */ function _msgData() internal view virtual override returns (bytes calldata) { uint256 calldataLength = msg.data.length; uint256 contextSuffixLength = _contextSuffixLength(); if (isTrustedForwarder(msg.sender) && calldataLength >= contextSuffixLength) { return msg.data[:calldataLength - contextSuffixLength]; } else { return super._msgData(); } } /** * @dev ERC-2771 specifies the context as being a single address (20 bytes). */ function _contextSuffixLength() internal view virtual override returns (uint256) { return 20; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/ERC20.sol) pragma solidity ^0.8.20; import {IERC20} from "./IERC20.sol"; import {IERC20Metadata} from "./extensions/IERC20Metadata.sol"; import {Context} from "../../utils/Context.sol"; import {IERC20Errors} from "../../interfaces/draft-IERC6093.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}. * * 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. */ abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors { mapping(address account => uint256) private _balances; mapping(address account => mapping(address spender => 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 returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual 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 returns (uint8) { return 18; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view virtual returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view virtual 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 `value`. */ function transfer(address to, uint256 value) public virtual returns (bool) { address owner = _msgSender(); _transfer(owner, to, value); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * NOTE: If `value` 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 value) public virtual returns (bool) { address owner = _msgSender(); _approve(owner, spender, value); 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 `value`. * - the caller must have allowance for ``from``'s tokens of at least * `value`. */ function transferFrom(address from, address to, uint256 value) public virtual returns (bool) { address spender = _msgSender(); _spendAllowance(from, spender, value); _transfer(from, to, value); return true; } /** * @dev Moves a `value` 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. * * NOTE: This function is not virtual, {_update} should be overridden instead. */ function _transfer(address from, address to, uint256 value) internal { if (from == address(0)) { revert ERC20InvalidSender(address(0)); } if (to == address(0)) { revert ERC20InvalidReceiver(address(0)); } _update(from, to, value); } /** * @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from` * (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding * this function. * * Emits a {Transfer} event. */ function _update(address from, address to, uint256 value) internal virtual { if (from == address(0)) { // Overflow check required: The rest of the code assumes that totalSupply never overflows _totalSupply += value; } else { uint256 fromBalance = _balances[from]; if (fromBalance < value) { revert ERC20InsufficientBalance(from, fromBalance, value); } unchecked { // Overflow not possible: value <= fromBalance <= totalSupply. _balances[from] = fromBalance - value; } } if (to == address(0)) { unchecked { // Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply. _totalSupply -= value; } } else { unchecked { // Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256. _balances[to] += value; } } emit Transfer(from, to, value); } /** * @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0). * Relies on the `_update` mechanism * * Emits a {Transfer} event with `from` set to the zero address. * * NOTE: This function is not virtual, {_update} should be overridden instead. */ function _mint(address account, uint256 value) internal { if (account == address(0)) { revert ERC20InvalidReceiver(address(0)); } _update(address(0), account, value); } /** * @dev Destroys a `value` amount of tokens from `account`, lowering the total supply. * Relies on the `_update` mechanism. * * Emits a {Transfer} event with `to` set to the zero address. * * NOTE: This function is not virtual, {_update} should be overridden instead */ function _burn(address account, uint256 value) internal { if (account == address(0)) { revert ERC20InvalidSender(address(0)); } _update(account, address(0), value); } /** * @dev Sets `value` 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. * * Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument. */ function _approve(address owner, address spender, uint256 value) internal { _approve(owner, spender, value, true); } /** * @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event. * * By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by * `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any * `Approval` event during `transferFrom` operations. * * Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to * true using the following override: * ``` * function _approve(address owner, address spender, uint256 value, bool) internal virtual override { * super._approve(owner, spender, value, true); * } * ``` * * Requirements are the same as {_approve}. */ function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual { if (owner == address(0)) { revert ERC20InvalidApprover(address(0)); } if (spender == address(0)) { revert ERC20InvalidSpender(address(0)); } _allowances[owner][spender] = value; if (emitEvent) { emit Approval(owner, spender, value); } } /** * @dev Updates `owner` s allowance for `spender` based on spent `value`. * * Does not update the allowance value in case of infinite allowance. * Revert if not enough allowance is available. * * Does not emit an {Approval} event. */ function _spendAllowance(address owner, address spender, uint256 value) internal virtual { uint256 currentAllowance = allowance(owner, spender); if (currentAllowance != type(uint256).max) { if (currentAllowance < value) { revert ERC20InsufficientAllowance(spender, currentAllowance, value); } unchecked { _approve(owner, spender, currentAllowance - value, false); } } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC20Burnable.sol) pragma solidity ^0.8.20; import {ERC20} from "../ERC20.sol"; import {Context} from "../../../utils/Context.sol"; /** * @dev Extension of {ERC20} that allows token holders to destroy both their own * tokens and those that they have an allowance for, in a way that can be * recognized off-chain (via event analysis). */ abstract contract ERC20Burnable is Context, ERC20 { /** * @dev Destroys a `value` amount of tokens from the caller. * * See {ERC20-_burn}. */ function burn(uint256 value) public virtual { _burn(_msgSender(), value); } /** * @dev Destroys a `value` amount of tokens from `account`, deducting from * the caller's allowance. * * See {ERC20-_burn} and {ERC20-allowance}. * * Requirements: * * - the caller must have allowance for ``accounts``'s tokens of at least * `value`. */ function burnFrom(address account, uint256 value) public virtual { _spendAllowance(account, _msgSender(), value); _burn(account, value); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC20Pausable.sol) pragma solidity ^0.8.20; import {ERC20} from "../ERC20.sol"; import {Pausable} from "../../../utils/Pausable.sol"; /** * @dev ERC20 token with pausable token transfers, minting and burning. * * Useful for scenarios such as preventing trades until the end of an evaluation * period, or having an emergency switch for freezing all token transfers in the * event of a large bug. * * IMPORTANT: This contract does not include public pause and unpause functions. In * addition to inheriting this contract, you must define both functions, invoking the * {Pausable-_pause} and {Pausable-_unpause} internal functions, with appropriate * access control, e.g. using {AccessControl} or {Ownable}. Not doing so will * make the contract pause mechanism of the contract unreachable, and thus unusable. */ abstract contract ERC20Pausable is ERC20, Pausable { /** * @dev See {ERC20-_update}. * * Requirements: * * - the contract must not be paused. */ function _update(address from, address to, uint256 value) internal virtual override whenNotPaused { super._update(from, to, value); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.20; import {IERC20} from "../IERC20.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. */ 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 v5.0.0) (token/ERC20/extensions/IERC20Permit.sol) pragma solidity ^0.8.20; /** * @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 v5.0.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.20; /** * @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 value of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the value of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves a `value` amount of 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 value) 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 a `value` amount of tokens 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 value) external returns (bool); /** * @dev Moves a `value` amount of tokens from `from` to `to` using the * allowance mechanism. `value` 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 value) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721.sol) pragma solidity ^0.8.20; import {IERC165} from "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC721 compliant contract. */ interface IERC721 is IERC165 { /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon * a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external; /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or * {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon * a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom(address from, address to, uint256 tokenId) external; /** * @dev Transfers `tokenId` token from `from` to `to`. * * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721 * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must * understand this adds an external call which potentially creates a reentrancy vulnerability. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 tokenId) external; /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the zero address clears previous approvals. * * Requirements: * * - The caller must own the token or be an approved operator. * - `tokenId` must exist. * * Emits an {Approval} event. */ function approve(address to, uint256 tokenId) external; /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the address zero. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool approved) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll} */ function isApprovedForAll(address owner, address operator) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721Receiver.sol) pragma solidity ^0.8.20; /** * @title ERC721 token receiver interface * @dev Interface for any contract that wants to support safeTransfers * from ERC721 asset contracts. */ interface IERC721Receiver { /** * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} * by `operator` from `from`, this function is called. * * It must return its Solidity selector to confirm the token transfer. * If any other value is returned or the interface is not implemented by the recipient, the transfer will be * reverted. * * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`. */ function onERC721Received( address operator, address from, uint256 tokenId, bytes calldata data ) external returns (bytes4); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/utils/ERC721Holder.sol) pragma solidity ^0.8.20; import {IERC721Receiver} from "../IERC721Receiver.sol"; /** * @dev Implementation of the {IERC721Receiver} interface. * * Accepts all token transfers. * Make sure the contract is able to use its token with {IERC721-safeTransferFrom}, {IERC721-approve} or * {IERC721-setApprovalForAll}. */ abstract contract ERC721Holder is IERC721Receiver { /** * @dev See {IERC721Receiver-onERC721Received}. * * Always returns `IERC721Receiver.onERC721Received.selector`. */ function onERC721Received(address, address, uint256, bytes memory) public virtual returns (bytes4) { return this.onERC721Received.selector; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol) pragma solidity ^0.8.20; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } function _contextSuffixLength() internal view virtual returns (uint256) { return 0; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/Pausable.sol) pragma solidity ^0.8.20; import {Context} from "../utils/Context.sol"; /** * @dev Contract module which allows children to implement an emergency stop * mechanism that can be triggered by an authorized account. * * This module is used through inheritance. It will make available the * modifiers `whenNotPaused` and `whenPaused`, which can be applied to * the functions of your contract. Note that they will not be pausable by * simply including this module, only once the modifiers are put in place. */ abstract contract Pausable is Context { bool private _paused; /** * @dev Emitted when the pause is triggered by `account`. */ event Paused(address account); /** * @dev Emitted when the pause is lifted by `account`. */ event Unpaused(address account); /** * @dev The operation failed because the contract is paused. */ error EnforcedPause(); /** * @dev The operation failed because the contract is not paused. */ error ExpectedPause(); /** * @dev Initializes the contract in unpaused state. */ constructor() { _paused = false; } /** * @dev Modifier to make a function callable only when the contract is not paused. * * Requirements: * * - The contract must not be paused. */ modifier whenNotPaused() { _requireNotPaused(); _; } /** * @dev Modifier to make a function callable only when the contract is paused. * * Requirements: * * - The contract must be paused. */ modifier whenPaused() { _requirePaused(); _; } /** * @dev Returns true if the contract is paused, and false otherwise. */ function paused() public view virtual returns (bool) { return _paused; } /** * @dev Throws if the contract is paused. */ function _requireNotPaused() internal view virtual { if (paused()) { revert EnforcedPause(); } } /** * @dev Throws if the contract is not paused. */ function _requirePaused() internal view virtual { if (!paused()) { revert ExpectedPause(); } } /** * @dev Triggers stopped state. * * Requirements: * * - The contract must not be paused. */ function _pause() internal virtual whenNotPaused { _paused = true; emit Paused(_msgSender()); } /** * @dev Returns to normal state. * * Requirements: * * - The contract must be paused. */ function _unpause() internal virtual whenPaused { _paused = false; emit Unpaused(_msgSender()); } }
{ "optimizer": { "enabled": true, "runs": 200 }, "viaIR": true, "evmVersion": "paris", "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
[{"inputs":[{"internalType":"address","name":"trustedForwarder","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"allowance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientAllowance","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientBalance","type":"error"},{"inputs":[{"internalType":"address","name":"approver","type":"address"}],"name":"ERC20InvalidApprover","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC20InvalidReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"ERC20InvalidSender","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"}],"name":"ERC20InvalidSpender","type":"error"},{"inputs":[],"name":"EnforcedPause","type":"error"},{"inputs":[],"name":"ExpectedPause","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"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":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"address","name":"redeemer","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"BondRedeemed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"triggerer","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"},{"indexed":false,"internalType":"string","name":"auditReportLink","type":"string"}],"name":"BurnEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newFeeAccount","type":"address"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"FeeAccountUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"feeAccount","type":"address"},{"indexed":false,"internalType":"uint256","name":"feeAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"FeePaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"triggerer","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"},{"indexed":false,"internalType":"string","name":"auditReportLink","type":"string"}],"name":"MintEvent","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":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"},{"indexed":false,"internalType":"string","name":"sku","type":"string"}],"name":"PurchaseCompleted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"triggerer","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"},{"indexed":false,"internalType":"string","name":"purchaseOrderLink","type":"string"}],"name":"PurchaseOrderEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"paidAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"receivedAmount","type":"uint256"},{"indexed":false,"internalType":"address","name":"paymentTokenAddress","type":"address"},{"indexed":false,"internalType":"string","name":"receivedToken","type":"string"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"SwapCompleted","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":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"triggerer","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"},{"indexed":false,"internalType":"string","name":"auditReportLink","type":"string"}],"name":"VaultDepositEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"triggerer","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"},{"indexed":false,"internalType":"string","name":"auditReportLink","type":"string"}],"name":"VaultWithdrawalEvent","type":"event"},{"inputs":[{"internalType":"address","name":"_tokenAddress","type":"address"},{"internalType":"uint256","name":"_tokenDecimals","type":"uint256"},{"internalType":"uint256","name":"_exchangeRate","type":"uint256"}],"name":"addSupportedToken","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":"value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"burnFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_adminAccount","type":"address"}],"name":"checkIsAdmin","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"string","name":"sku","type":"string"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"_feeRate","type":"uint256"}],"name":"forwardedMakePurchase","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"paymentTokenAddress","type":"address"},{"internalType":"uint256","name":"permittedSpendAmount","type":"uint256"},{"internalType":"uint256","name":"phigoldAmount","type":"uint256"},{"internalType":"bool","name":"isUsd","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"},{"internalType":"uint256","name":"phipayNonce","type":"uint256"}],"name":"forwardedSwapWithPermit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"_feeRate","type":"uint256"}],"name":"forwardedTransferWithFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getNonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_paymentTokenAddress","type":"address"}],"name":"getPaymentTokenExchangeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getSupportedTokenCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getUsdExchangeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isAdmin","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"forwarder","type":"address"}],"name":"isTrustedForwarder","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"string","name":"sku","type":"string"},{"internalType":"uint256","name":"_feeRate","type":"uint256"}],"name":"makePurchase","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"mintAuditReports","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"string","name":"_ipfsAuditReportLink","type":"string"}],"name":"mintPhigoldSupply","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"phigoldBondContract","outputs":[{"internalType":"contract IPhigoldBond","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"phipayFeeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"string","name":"_purchaseId","type":"string"}],"name":"redeemPhigold","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"redeemPhigoldBond","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_adminAccount","type":"address"}],"name":"removeAdminAccount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenAddress","type":"address"}],"name":"removeSupportedToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_adminAccount","type":"address"}],"name":"setAdminAccount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_feeAccount","type":"address"}],"name":"setFeeAccount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_paymentTokenAddress","type":"address"},{"internalType":"uint256","name":"_newExchangeRate","type":"uint256"}],"name":"setPaymentTokenExchangeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_bondContractAddress","type":"address"}],"name":"setPhigoldBondContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newPhigoldUsdPrice","type":"uint256"}],"name":"setUsdExchangeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"supportedTokens","outputs":[{"internalType":"contract IERC20","name":"paymentToken","type":"address"},{"internalType":"uint256","name":"decimals","type":"uint256"},{"internalType":"uint256","name":"exchangeRate","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_paymentTokenAddress","type":"address"},{"internalType":"uint256","name":"_phigoldAmount","type":"uint256"},{"internalType":"bool","name":"_isUsd","type":"bool"}],"name":"swapSupportedTokenForPhigold","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":"value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","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":"trustedForwarder","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenAddress","type":"address"}],"name":"withdrawERC20Token","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60a0346200045d57601f19906001600160401b0390601f90620031c738819003838101861683018581118482101762000361578392829160405283396020928391810103126200045d5751926001600160a01b039081851685036200045d576200006862000462565b93600d85526c141a1a5b985b98d94b91dbdb19609a1b848601526200008c62000462565b90600782526614121251d3d31160ca1b85830152855191838311620003615760039283546001988982811c9216801562000452575b898310146200043c578185849311620003e6575b508890858311600114620003835760009262000377575b505060001982861b1c191690881b1783555b8051938411620003615760049889548881811c9116801562000356575b888210146200034157908184879695949311620002e5575b50879285116001146200027d575060009362000271575b505082861b92600019911b1c19161785555b60055493331562000259576001600160a81b0319851633600881811b610100600160a81b031692909217600581905560405197600e96959491939192911c84167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a360805263042c1d8060065560c8600a5560081c1660018060a01b03196009541617600955336000525260406000209060ff19918183825416179055730d58ccb8f40c46aff980dd7457ee346f92908f29600052604060002091825416179055612d4490816200048382396080518181816102c601528181610ae00152818161111b01528181611b1e01528181611bb40152612cb80152f35b604051631e4fbdf760e01b8152600081880152602490fd5b0151915038806200014a565b88959392919316928a600052876000209360005b89828210620002ce5750508511620002b3575b50505050811b0185556200015c565b01519060f884600019921b161c1916905538808080620002a4565b8385015187558b9890960195938401930162000291565b9091929394508a600052876000208480880160051c8201928a891062000337575b918b91899897969594930160051c01915b8281106200032757505062000133565b600081558897508b910162000317565b9250819262000306565b60228b634e487b7160e01b6000525260246000fd5b90607f16906200011b565b634e487b7160e01b600052604160045260246000fd5b015190503880620000ec565b908c8b941691876000528a6000209260005b8c828210620003cf5750508411620003b6575b505050811b018355620000fe565b015160001983881b60f8161c19169055388080620003a8565b8385015186558e9790950194938401930162000395565b90915085600052886000208580850160051c8201928b861062000432575b918c91869594930160051c01915b82811062000422575050620000d5565b600081558594508c910162000412565b9250819262000404565b634e487b7160e01b600052602260045260246000fd5b91607f1691620000c1565b600080fd5b60408051919082016001600160401b03811183821017620003615760405256fe608060408181526004918236101561001657600080fd5b600092833560e01c91826306fdde03146120ed57508163095ea7b31461203b578163150b7a0214611fd457816318160ddd14611fb557816323b872dd14611f7c57816323da140e14611f5d57816324d7806c14610a4c5781632d0335ab146110ce578163313ce56714611f415781633bdebbe114611db05781633f4ba83a14611d4657816342966c6814611d265781634b023cf814611caa5781635219716e14611c6557816356ce8ab814611bdb578163572b6c0514611b895781635761764014611ae85781635c975abb14611ac457816367675ad514611a9b57816367a89a7214611a5b57816368c4ac2614611a095781636e896ac11461195f57816370a0823114611928578163715018a6146118c75781637327d6e6146113c6578163763191901461130357816379cc6790146112c95781637ba147f11461114a5781637da0a877146111065781637ecebe00146110ce5781638456cb59146110605781638a77834814610d7c5781638d6830de14610d3c5781638da5cb5b14610d0f57816395d89b4114610c2c578163a6c3cb8414610c0d578163a9059cbb14610bd5578163ae7fcb1714610ba3578163ce67be2614610b84578163cef2841a14610a8a578163d953689d14610a4c578163dd62ed3e146109fe578163e8ef9f22146109bb578163edd9587b14610848578163f100049014610736578163f2fde38b14610698578163f3851fda14610273575063ff73870b1461023557600080fd5b3461026f57602036600319011261026f5760209160029082906001600160a01b0361025e612212565b168152600b85522001549051908152f35b5080fd5b905034610694576101403660031901126106945761028f612212565b610297612228565b90606435926084359283151584036105c55760c43560ff8116809103610584576001600160a01b03946102ed337f0000000000000000000000000000000000000000000000000000000000000000881614612610565b85851695868a52602091600d8352610124358a8c20540361065a57878b52600d8352898b2061031c81546126a4565b90558a82861694853b1561026f578b519063d505accf60e01b82528a89830152306024830152604435604483015260a4356064830152608482015260e43560a48201526101043560c4820152818160e481838a5af1801561065057610638575b50849052600b8352898b20620f4240911561062b576001600654915b015490600682111561060c576103c36103bd6103b66103c994612a75565b928d612740565b91612a84565b90612753565b04965b6103d7881515612a92565b8951906370a0823160e01b8252868201528281602481875afa80156105d15788908c906105db575b61040b92501015612af2565b8851636eb1769f60e11b81526001600160a01b0387168682019081523060208201529091908390839081906040010381875afa80156105d15788928c91610599575b5093829161046185946104a1971015612b49565b60055460081c168c8c518097819582946323b872dd60e01b84528d8d850160409194939294606082019560018060a01b0380921683521660208201520152565b03925af190811561058f578991610554575b506104be9150612bae565b6104c985843061236f565b86865180936395d89b4160e01b825281305afa91821561054a57907f60cd11ca617b0758c3cc25e1445e01a198b67383b98aa98703fbcbe083ca912b966105209493928993610526575b5051958695429487612c59565b0390a180f35b6105439193503d808b833e61053b8183612268565b810190612bfa565b9138610513565b86513d89823e3d90fd5b905081813d8311610588575b61056a8183612268565b810103126105845761057e6104be91612ba1565b386104b3565b8780fd5b503d610560565b88513d8b823e3d90fd5b80929350848092503d83116105ca575b6105b38183612268565b810103126105c557518791908361044d565b600080fd5b503d6105a9565b8a513d8d823e3d90fd5b50508281813d8311610605575b6105f28183612268565b810103126105c5578761040b91516103ff565b503d6105e8565b61061e6103bd6103b661062494612a67565b90612740565b04966103cc565b6001600282015491610398565b6106419061223e565b61064c578a3861037c565b8a80fd5b8c513d84823e3d90fd5b895162461bcd60e51b81528087018490526014602482015273496e76616c696420506869506179206e6f6e636560601b6044820152606490fd5b8280fd5b905034610694576020366003190112610694576106b3612212565b6106bb61232b565b6001600160a01b0381811693909290841561072057505060058054610100600160a81b03198116600893841b610100600160a81b031617909155901c167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a380f35b51631e4fbdf760e01b8152908101859052602490fd5b828434610845576020908160031936011261084557829084358152600c8352209180519260009080549060019082821c92828116801561083b575b8785108114610828578899509688969785829a5291826000146108015750506001146107be575b5050506107ba92916107ab910385612268565b519282849384528301906121ed565b0390f35b86935060009291925282600020916000925b8284106107e957505050820101816107ab6107ba610798565b8054848a0186015288955087949093019281016107d0565b60ff19168782015293151560051b860190930193508492506107ab91506107ba9050610798565b634e487b7160e01b865260228a52602486fd5b93607f1693610771565b80fd5b83833461026f57606036600319011261026f57610863612212565b6024356044359161087261232b565b6001600160a01b03908116936108898515156128dd565b8215610967578315610919578051946060860186811067ffffffffffffffff821117610904576002969798508252808752602087019384528187019485528752600b60205286209451166bffffffffffffffffffffffff60a01b855416178455516001840155519101556108fe6007546126a4565b60075580f35b604189634e487b7160e01b6000525260246000fd5b5162461bcd60e51b81526020818801526024808201527f45786368616e67652052617465206d75737420626520677265617465722074686044820152630616e20360e41b6064820152608490fd5b5162461bcd60e51b8152602081880152602960248201527f4e756d626572206f6620646563696d616c73206d75737420626520677265617460448201526806572207468616e20360bc1b6064820152608490fd5b50503461026f57602036600319011261026f576109d6612212565b6109de61232b565b6001600160a01b03168252600e6020528120805460ff1916600117905580f35b50503461026f578060031936011261026f57602091610a1b612212565b82610a24612228565b6001600160a01b03928316845260018652922091166000908152908352819020549051908152f35b50503461026f57602036600319011261026f5760209160ff9082906001600160a01b03610a77612212565b168152600e855220541690519015158152f35b9050346106945760c036600319011261069457610aa5612212565b91610aae612228565b90604435926064359067ffffffffffffffff8211610b8057610ad2913691016122dd565b6001600160a01b03610b07337f0000000000000000000000000000000000000000000000000000000000000000831614612610565b8516808752600d602052610b216084358489205414612668565b8652600d602052818620610b3581546126a4565b9055610b4560a435858588612773565b15610b7c577f42bdb50e0f9f5bf372eab7ce6b4ffefc203629ba351ca5be62662afdc4ee628e9461052092519485944292866126b3565b8580fd5b8680fd5b50503461026f578160031936011261026f576020906007549051908152f35b919050346106945760203660031901126106945760ff610bce91338552600e60205284205416612929565b3560065580f35b50503461026f578060031936011261026f57602090610c06610bf5612212565b60243590610c01612cb5565b61236f565b5160018152f35b50503461026f578160031936011261026f57602090600a549051908152f35b82843461084557806003193601126108455750805190600090835491600183811c90808516948515610d05575b6020958684108114610cf2579086889992858a98999a529182600014610801575050600114610c95575050506107ba92916107ab910385612268565b600090815286935091907f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b5b828410610cda57505050820101816107ab6107ba610798565b8054848a018601528895508794909301928101610cc1565b634e487b7160e01b855260228952602485fd5b91607f1691610c59565b50503461026f578160031936011261026f57600554905160089190911c6001600160a01b03168152602090f35b50503461026f578060031936011261026f57610d56612212565b610d5e61232b565b6001600160a01b03168252600b602052812060243560029091015580f35b90503461069457606036600319011261069457610d97612212565b90602435916044359182151583036105c5576001600160a01b038281168752600b602090815286882094156110515781620f42406006545b6001880154906006821115611038576103c36103bd610df0610df794612a75565b928c612740565b04955b610e05871515612a92565b541691610e10612cb5565b88516370a0823160e01b815290821685820152908282602481875afa8015610ff95787928b91611003575b50610e8592610e4b911015612af2565b82610e54612cb5565b8a51636eb1769f60e11b81526001600160a01b03909116878201908152306020820152909384918291604090910190565b0381875afa8015610ff95787928b91610fc6575b50938291610ead8594610ef7971015612b49565b8b610eb6612cb5565b9160055460081c16918c51978895869485936323b872dd60e01b85528c850160409194939294606082019560018060a01b0380921683521660208201520152565b03925af1908115610fbc578891610f85575b50610f149150612bae565b610f2684610f20612cb5565b3061236f565b610f2e612cb5565b9186865180936395d89b4160e01b825281305afa91821561054a57907f60cd11ca617b0758c3cc25e1445e01a198b67383b98aa98703fbcbe083ca912b966105209493928993610526575051958695429487612c59565b905081813d8311610fb5575b610f9b8183612268565b81010312610b8057610faf610f1491612ba1565b38610f09565b503d610f91565b87513d8a823e3d90fd5b80929350848092503d8311610ff2575b610fe08183612268565b810103126105c5575186919083610e99565b503d610fd6565b89513d8c823e3d90fd5b809350848092503d8311611031575b61101c8183612268565b810103126105c5579051869190610e85610e3b565b503d611012565b61061e6103bd610df061104a94612a67565b0495610dfa565b81620f42406002870154610dcf565b50503461026f578160031936011261026f5760207f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2589161109e61232b565b6110a66125f2565b600160ff1960055416176005556110bb612cb5565b90516001600160a01b039091168152a180f35b50503461026f57602036600319011261026f5760209181906001600160a01b036110f6612212565b168152600d845220549051908152f35b50503461026f578160031936011261026f57517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b83833461026f5761115a366122fb565b93338452600e60205261117260ff8486205416612929565b84511561127657611182856129ab565b1561123357301561121c57506105207f9e31786833642f5b8cf977c95ad5e181542fa9238c9c3105757e05b20e2597d893946111bc6125f2565b6111c8836002546125cf565b600255308652856020528386208381540190558351838152867fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60203093a361120f612cb5565b9351938493429185612980565b825163ec442f0560e01b8152908101849052602490fd5b606490602084519162461bcd60e51b8352820152601b60248201527f496e76616c69642049504653206164647265737320666f726d617400000000006044820152fd5b608490602084519162461bcd60e51b8352820152602760248201527f4175646974207265706f72742049504653206c696e6b206d75737420626520706044820152661c9bdd9a59195960ca1b6064820152fd5b50503461026f57366003190112610845576113006112e5612212565b602435906112fb826112f5612cb5565b83612455565b612528565b80f35b919050346106945760203660031901126106945761131f612212565b61132761232b565b6001600160a01b039081169061133e8215156128dd565b818552600b6020528285205416156113915783916002918352600b6020528220828155826001820155015560075490811561137e57506000190160075580f35b634e487b7160e01b835260119052602482fd5b815162461bcd60e51b8152602081850152600f60248201526e151bdad95b881b9bdd08199bdd5b99608a1b6044820152606490fd5b91905034610694576020918260031936011261159757600854813592906001600160a01b0390811680156118845782516331a9108f60e11b815284810186905260249087818381865afa908115611827578991611867575b508380611429612cb5565b1691160361183157835163021b797b60e11b81528581018790529460c0868381865afa958615611827578996611783575b5087860151421061174c578486015161171457600260ff606088015116036116c957845163020604bf60e21b815281810188905288818481875afa9081156115b2578a9161169c575b5084163014801561160c575b156115c057823b156115bc578451630852cd8d60e31b81528181018890528981848183885af180156115b25761159b575b5090829189933b1561159757839188918388519586948593630cd7a19560e41b85528401525af1801561158d57611571575b507fe305dcd5197faa39ababe23510783dbec4f835cfdcc3b347e68bae90f022a3a160808686868a8761154f611546612cb5565b8551903061236f565b611557612cb5565b93519383519586521690840152820152426060820152a180f35b61157f90959493929561223e565b610b7c579091928538611512565b84513d84823e3d90fd5b8380fd5b6115a990999193929961223e565b979091386114e0565b86513d8c823e3d90fd5b8880fd5b6084918886519262461bcd60e51b8452830152808201527f506869506179206e6f7420617070726f76656420746f207472616e7366657220604482015263189bdb9960e21b6064820152fd5b5061164a88611619612cb5565b875163e985e9c560e01b81526001600160a01b03909116848201908152306020820152909283918291604090910190565b0381875afa9081156115b2578a91611663575b506114af565b90508881813d8311611695575b61167a8183612268565b810103126116915761168b90612ba1565b3861165d565b8980fd5b503d611670565b6116bc9150893d8b116116c2575b6116b48183612268565b810190612c96565b386114a3565b503d6116aa565b60226084928987519362461bcd60e51b85528401528201527f426f6e64206d75737420626520696e20746865205661756c7465642073746174604482015261757360f01b6064820152fd5b60156064928987519362461bcd60e51b855284015282015274109bdb9908185b1c9958591e481c995919595b5959605a1b6044820152fd5b60146064928987519362461bcd60e51b855284015282015273109bdb99081b9bdd081e595d081b585d1d5c995960621b6044820152fd5b90955060c0813d821161181f575b8161179e60c09383612268565b810103126115bc5784519060c0820182811067ffffffffffffffff82111761180d5786528051825288810151898301526117d9868201612ba1565b8683015260608101519060ff8216820361064c5760a091606084015260808101516080840152015160a0820152943861145a565b634e487b7160e01b8b5260418852838bfd5b3d9150611791565b85513d8b823e3d90fd5b8460126064928987519362461bcd60e51b8552840152820152712737ba103a3432903137b7321037bbb732b960711b6044820152fd5b61187e9150883d8a116116c2576116b48183612268565b3861141e565b825162461bcd60e51b8152808501879052601c60248201527f506869676f6c64426f6e6420636f6e7472616374206e6f7420736574000000006044820152606490fd5b83346108455780600319360112610845576118e061232b565b60058054610100600160a81b03198116909155819060081c6001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b50503461026f57602036600319011261026f5760209181906001600160a01b03611950612212565b16815280845220549051908152f35b50503461026f577fc136285a46e61d975decf1d79f2b6bc4a858b008859bf182aaa16137e4e255dd90610520611994366122fb565b6119a182939215156126e6565b6119ad836112fb612cb5565b6119b5612cb5565b936119fd603282518094710283434b3b7b632102932b232b2b6b2b21d160751b60208301526119ed81518092602086860191016121ca565b8101036012810185520183612268565b51938493429185612980565b50503461026f57602036600319011261026f576060916001600160a01b0390829082611a33612212565b168152600b602052209081541691600260018301549201549181519384526020840152820152f35b50503461026f57602036600319011261026f57611a76612212565b611a7e61232b565b6001600160a01b03168252600e6020528120805460ff1916905580f35b50503461026f578160031936011261026f5760085490516001600160a01b039091168152602090f35b50503461026f578160031936011261026f5760209060ff6005541690519015158152f35b50503461026f5760a036600319011261026f57611b8190611b07612212565b611b0f612228565b916001600160a01b03611b45337f0000000000000000000000000000000000000000000000000000000000000000831614612610565b8216808652600d602052611b5f6064358388205414612668565b8552600d6020528420611b7281546126a4565b90556084359160443591612773565b156108455780f35b50503461026f57602036600319011261026f57602090611ba7612212565b90519060018060a01b03807f0000000000000000000000000000000000000000000000000000000000000000169116148152f35b90503461069457608036600319011261069457611bf6612212565b90602435906044359067ffffffffffffffff8211610b7c57611c1a913691016122dd565b92611c29606435838533612773565b15611c61577f42bdb50e0f9f5bf372eab7ce6b4ffefc203629ba351ca5be62662afdc4ee628e936105209151938493429133866126b3565b8480fd5b833461084557602036600319011261084557611c7f612212565b611c8761232b565b60018060a01b03166bffffffffffffffffffffffff60a01b600854161760085580f35b50503461026f57602036600319011261026f576105207f9fee46258bf9d123a7d66bbda27a92d2fe75e3bac91217431cf8875396aeae5c91611cea612212565b90611cf361232b565b600980546001600160a01b0319166001600160a01b03939093169283179055519081524260208201529081906040820190565b83903461026f57602036600319011261026f5761130090356112fb612cb5565b905034610694578260031936011261069457611d6061232b565b6005549060ff821615611da2575060ff19166005557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906020906110bb612cb5565b8251638dfc202b60e01b8152fd5b91905034610694576020908160031936011261159757611dce612212565b611dd661232b565b81516370a0823160e01b80825230828701526001600160a01b039290921694908481602481895afa8015611f37578790611f08575b611e1791501515612af2565b825191825230818301528382602481885afa918215611efe578692611ecd575b5090611e7d94849287611e48612cb5565b865163a9059cbb60e01b81526001600160a01b0390911692810192835260208301949094529296879384929091839160400190565b03925af1908115611ec45750611e91578280f35b81813d8311611ebd575b611ea58183612268565b8101031261026f57611eb690612ba1565b5038808280f35b503d611e9b565b513d85823e3d90fd5b91508382813d8311611ef7575b611ee48183612268565b81010312610b7c57905190611e7d611e37565b503d611eda565b83513d88823e3d90fd5b508481813d8311611f30575b611f1e8183612268565b81010312610b8057611e179051611e0b565b503d611f14565b84513d89823e3d90fd5b50503461026f578160031936011261026f576020905160068152f35b50503461026f578160031936011261026f576020906006549051908152f35b50503461026f57606036600319011261026f57602090610c06611f9d612212565b611fa5612228565b60443591610c01836112f5612cb5565b50503461026f578160031936011261026f576020906002549051908152f35b82843461084557608036600319011261084557611fef612212565b50611ff8612228565b506064359067ffffffffffffffff82116108455736602383011215610845575060209281602461202d933693013591016122a6565b5051630a85bd0160e11b8152f35b905034610694578160031936011261069457612055612212565b602435936001600160a01b038061206a612cb5565b169283156120d657169283156120c1575060208581968684867f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925965260018552818120888252855220558551908152a35160018152f35b602491855191634a1406b160e11b8352820152fd5b855163e602df0560e01b8152808601849052602490fd5b84843461026f578160031936011261026f578160035492600184811c918186169586156121c0575b60209687851081146121ad578899509688969785829a529182600014610801575050600114612151575050506107ba92916107ab910385612268565b9190869350600383527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b5b82841061219557505050820101816107ab6107ba610798565b8054848a01860152889550879490930192810161217c565b634e487b7160e01b835260228a52602483fd5b92607f1692612115565b60005b8381106121dd5750506000910152565b81810151838201526020016121cd565b90602091612206815180928185528580860191016121ca565b601f01601f1916010190565b600435906001600160a01b03821682036105c557565b602435906001600160a01b03821682036105c557565b67ffffffffffffffff811161225257604052565b634e487b7160e01b600052604160045260246000fd5b90601f8019910116810190811067ffffffffffffffff82111761225257604052565b67ffffffffffffffff811161225257601f01601f191660200190565b9291926122b28261228a565b916122c06040519384612268565b8294818452818301116105c5578281602093846000960137010152565b9080601f830112156105c5578160206122f8933591016122a6565b90565b9060406003198301126105c557600435916024359067ffffffffffffffff82116105c5576122f8916004016122dd565b6005546001600160a01b039060081c811681612345612cb5565b160361234e5750565b602490612359612cb5565b60405163118cdaa760e01b815291166004820152fd5b916001600160a01b0380841692831561243c5716928315612423576123926125f2565b600090838252816020526040822054908382106123f1575091604082827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef958760209652828652038282205586815220818154019055604051908152a3565b60405163391434e360e21b81526001600160a01b03919091166004820152602481019190915260448101839052606490fd5b60405163ec442f0560e01b815260006004820152602490fd5b604051634b637e8f60e11b815260006004820152602490fd5b9160018060a01b038093169160009383855260016020526040938486209183169182875260205284862054926000198403612494575b50505050505050565b8484106124f8575080156124e05781156124c85785526001602052838520908552602052039120553880808080808061248b565b8451634a1406b160e11b815260048101879052602490fd5b845163e602df0560e01b815260048101879052602490fd5b8551637dc7a0d960e11b81526001600160a01b039190911660048201526024810184905260448101859052606490fd5b906001600160a01b03821690811561243c576125426125f2565b6000928284528360205260408420549082821061259d5750817fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef926020928587528684520360408620558060025403600255604051908152a3565b60405163391434e360e21b81526001600160a01b03919091166004820152602481019190915260448101829052606490fd5b919082018092116125dc57565b634e487b7160e01b600052601160045260246000fd5b60ff600554166125fe57565b60405163d93c066560e01b8152600490fd5b1561261757565b60405162461bcd60e51b815260206004820152602360248201527f43616c6c6572206973206e6f7420746865207472757374656420666f727761726044820152623232b960e91b6064820152608490fd5b1561266f57565b60405162461bcd60e51b815260206004820152600d60248201526c496e76616c6964206e6f6e636560981b6044820152606490fd5b60001981146125dc5760010190565b91926122f895949160a094600180871b0380921685521660208401526040830152606082015281608082015201906121ed565b156126ed57565b60405162461bcd60e51b815260206004820152602560248201527f506869676f6c6420616d6f756e74206d75737420626520677265617465722074604482015264068616e20360dc1b6064820152608490fd5b818102929181159184041417156125dc57565b811561275d570490565b634e487b7160e01b600052601260045260246000fd5b926001600160a01b0391908282161561288d576127918415156126e6565b801561287e576127a5612710915b85612740565b04926127b184826125cf565b838616600052600060205260406000205410612842576127d1918561236f565b816127df575b505050600190565b612810827ff3816d9cce3442fbfe3e4d36ad047b3362efdc9f2e283e77b0ecd768a0a01ef29483600954169061236f565b60095460408051929091166001600160a01b0316825260208201929092524291810191909152606090a13880806127d7565b60405162461bcd60e51b8152602060048201526014602482015273496e73756666696369656e742062616c616e636560601b6044820152606490fd5b506127106127a5600a5461279f565b60405162461bcd60e51b815260206004820152602260248201527f526563697069656e742061646472657373206d7573742062652070726f766964604482015261195960f21b6064820152608490fd5b156128e457565b60405162461bcd60e51b815260206004820152601e60248201527f546f6b656e2061646472657373206d7573742062652070726f766964656400006044820152606490fd5b1561293057565b60405162461bcd60e51b815260206004820152602260248201527f4f6e6c792061646d696e732063616e2063616c6c20746869732066756e63746960448201526137b760f11b6064820152608490fd5b90926080926122f8959460018060a01b031683526020830152604082015281606082015201906121ed565b8051602e81149081612a45575b5080612a20575b612a1a57805190603b821491826129e1575b50506129dc57600090565b600190565b90915015612a0457602001516001600160f81b031916603160f91b1438806129d1565b634e487b7160e01b600052603260045260246000fd5b50600190565b50805160011015612a045760218101516001600160f81b031916606d60f81b146129bf565b905015612a045760208101516001600160f81b031916605160f81b14386129b8565b60060390600682116125dc57565b6005198101919082116125dc57565b604d81116125dc57600a0a90565b15612a9957565b60405162461bcd60e51b815260206004820152602b60248201527f5061796d656e7420746f6b656e20616d6f756e74206d7573742062652067726560448201526a061746572207468616e20360ac1b6064820152608490fd5b15612af957565b60405162461bcd60e51b815260206004820152602260248201527f496e73756666696369656e74207061796d656e7420746f6b656e2062616c616e604482015261636560f01b6064820152608490fd5b15612b5057565b60405162461bcd60e51b8152602060048201526024808201527f496e73756666696369656e74207061796d656e7420746f6b656e20616c6c6f77604482015263616e636560e01b6064820152608490fd5b519081151582036105c557565b15612bb557565b60405162461bcd60e51b815260206004820152601d60248201527f5061796d656e7420746f6b656e207472616e73666572206661696c65640000006044820152606490fd5b6020818303126105c55780519067ffffffffffffffff82116105c5570181601f820112156105c5578051612c2d8161228a565b92612c3b6040519485612268565b818452602082840101116105c5576122f891602080850191016121ca565b9695949193612c919360a095600180881b038094168a5260208a0152604089015216606087015260c0608087015260c08601906121ed565b930152565b908160209103126105c557516001600160a01b03811681036105c55790565b337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03161480612d03575b15612cff5760131936013681116125dc573560601c90565b3390565b506014361015612ce756fea2646970667358221220761afc950b717a7e4358657fd190b6c91f62bb885f7eee91c43d1855b67cc38564736f6c63430008140033000000000000000000000000d297ef4b1291a03027c5d190e251b47b0052f16a
Deployed Bytecode
0x608060408181526004918236101561001657600080fd5b600092833560e01c91826306fdde03146120ed57508163095ea7b31461203b578163150b7a0214611fd457816318160ddd14611fb557816323b872dd14611f7c57816323da140e14611f5d57816324d7806c14610a4c5781632d0335ab146110ce578163313ce56714611f415781633bdebbe114611db05781633f4ba83a14611d4657816342966c6814611d265781634b023cf814611caa5781635219716e14611c6557816356ce8ab814611bdb578163572b6c0514611b895781635761764014611ae85781635c975abb14611ac457816367675ad514611a9b57816367a89a7214611a5b57816368c4ac2614611a095781636e896ac11461195f57816370a0823114611928578163715018a6146118c75781637327d6e6146113c6578163763191901461130357816379cc6790146112c95781637ba147f11461114a5781637da0a877146111065781637ecebe00146110ce5781638456cb59146110605781638a77834814610d7c5781638d6830de14610d3c5781638da5cb5b14610d0f57816395d89b4114610c2c578163a6c3cb8414610c0d578163a9059cbb14610bd5578163ae7fcb1714610ba3578163ce67be2614610b84578163cef2841a14610a8a578163d953689d14610a4c578163dd62ed3e146109fe578163e8ef9f22146109bb578163edd9587b14610848578163f100049014610736578163f2fde38b14610698578163f3851fda14610273575063ff73870b1461023557600080fd5b3461026f57602036600319011261026f5760209160029082906001600160a01b0361025e612212565b168152600b85522001549051908152f35b5080fd5b905034610694576101403660031901126106945761028f612212565b610297612228565b90606435926084359283151584036105c55760c43560ff8116809103610584576001600160a01b03946102ed337f000000000000000000000000d297ef4b1291a03027c5d190e251b47b0052f16a881614612610565b85851695868a52602091600d8352610124358a8c20540361065a57878b52600d8352898b2061031c81546126a4565b90558a82861694853b1561026f578b519063d505accf60e01b82528a89830152306024830152604435604483015260a4356064830152608482015260e43560a48201526101043560c4820152818160e481838a5af1801561065057610638575b50849052600b8352898b20620f4240911561062b576001600654915b015490600682111561060c576103c36103bd6103b66103c994612a75565b928d612740565b91612a84565b90612753565b04965b6103d7881515612a92565b8951906370a0823160e01b8252868201528281602481875afa80156105d15788908c906105db575b61040b92501015612af2565b8851636eb1769f60e11b81526001600160a01b0387168682019081523060208201529091908390839081906040010381875afa80156105d15788928c91610599575b5093829161046185946104a1971015612b49565b60055460081c168c8c518097819582946323b872dd60e01b84528d8d850160409194939294606082019560018060a01b0380921683521660208201520152565b03925af190811561058f578991610554575b506104be9150612bae565b6104c985843061236f565b86865180936395d89b4160e01b825281305afa91821561054a57907f60cd11ca617b0758c3cc25e1445e01a198b67383b98aa98703fbcbe083ca912b966105209493928993610526575b5051958695429487612c59565b0390a180f35b6105439193503d808b833e61053b8183612268565b810190612bfa565b9138610513565b86513d89823e3d90fd5b905081813d8311610588575b61056a8183612268565b810103126105845761057e6104be91612ba1565b386104b3565b8780fd5b503d610560565b88513d8b823e3d90fd5b80929350848092503d83116105ca575b6105b38183612268565b810103126105c557518791908361044d565b600080fd5b503d6105a9565b8a513d8d823e3d90fd5b50508281813d8311610605575b6105f28183612268565b810103126105c5578761040b91516103ff565b503d6105e8565b61061e6103bd6103b661062494612a67565b90612740565b04966103cc565b6001600282015491610398565b6106419061223e565b61064c578a3861037c565b8a80fd5b8c513d84823e3d90fd5b895162461bcd60e51b81528087018490526014602482015273496e76616c696420506869506179206e6f6e636560601b6044820152606490fd5b8280fd5b905034610694576020366003190112610694576106b3612212565b6106bb61232b565b6001600160a01b0381811693909290841561072057505060058054610100600160a81b03198116600893841b610100600160a81b031617909155901c167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a380f35b51631e4fbdf760e01b8152908101859052602490fd5b828434610845576020908160031936011261084557829084358152600c8352209180519260009080549060019082821c92828116801561083b575b8785108114610828578899509688969785829a5291826000146108015750506001146107be575b5050506107ba92916107ab910385612268565b519282849384528301906121ed565b0390f35b86935060009291925282600020916000925b8284106107e957505050820101816107ab6107ba610798565b8054848a0186015288955087949093019281016107d0565b60ff19168782015293151560051b860190930193508492506107ab91506107ba9050610798565b634e487b7160e01b865260228a52602486fd5b93607f1693610771565b80fd5b83833461026f57606036600319011261026f57610863612212565b6024356044359161087261232b565b6001600160a01b03908116936108898515156128dd565b8215610967578315610919578051946060860186811067ffffffffffffffff821117610904576002969798508252808752602087019384528187019485528752600b60205286209451166bffffffffffffffffffffffff60a01b855416178455516001840155519101556108fe6007546126a4565b60075580f35b604189634e487b7160e01b6000525260246000fd5b5162461bcd60e51b81526020818801526024808201527f45786368616e67652052617465206d75737420626520677265617465722074686044820152630616e20360e41b6064820152608490fd5b5162461bcd60e51b8152602081880152602960248201527f4e756d626572206f6620646563696d616c73206d75737420626520677265617460448201526806572207468616e20360bc1b6064820152608490fd5b50503461026f57602036600319011261026f576109d6612212565b6109de61232b565b6001600160a01b03168252600e6020528120805460ff1916600117905580f35b50503461026f578060031936011261026f57602091610a1b612212565b82610a24612228565b6001600160a01b03928316845260018652922091166000908152908352819020549051908152f35b50503461026f57602036600319011261026f5760209160ff9082906001600160a01b03610a77612212565b168152600e855220541690519015158152f35b9050346106945760c036600319011261069457610aa5612212565b91610aae612228565b90604435926064359067ffffffffffffffff8211610b8057610ad2913691016122dd565b6001600160a01b03610b07337f000000000000000000000000d297ef4b1291a03027c5d190e251b47b0052f16a831614612610565b8516808752600d602052610b216084358489205414612668565b8652600d602052818620610b3581546126a4565b9055610b4560a435858588612773565b15610b7c577f42bdb50e0f9f5bf372eab7ce6b4ffefc203629ba351ca5be62662afdc4ee628e9461052092519485944292866126b3565b8580fd5b8680fd5b50503461026f578160031936011261026f576020906007549051908152f35b919050346106945760203660031901126106945760ff610bce91338552600e60205284205416612929565b3560065580f35b50503461026f578060031936011261026f57602090610c06610bf5612212565b60243590610c01612cb5565b61236f565b5160018152f35b50503461026f578160031936011261026f57602090600a549051908152f35b82843461084557806003193601126108455750805190600090835491600183811c90808516948515610d05575b6020958684108114610cf2579086889992858a98999a529182600014610801575050600114610c95575050506107ba92916107ab910385612268565b600090815286935091907f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b5b828410610cda57505050820101816107ab6107ba610798565b8054848a018601528895508794909301928101610cc1565b634e487b7160e01b855260228952602485fd5b91607f1691610c59565b50503461026f578160031936011261026f57600554905160089190911c6001600160a01b03168152602090f35b50503461026f578060031936011261026f57610d56612212565b610d5e61232b565b6001600160a01b03168252600b602052812060243560029091015580f35b90503461069457606036600319011261069457610d97612212565b90602435916044359182151583036105c5576001600160a01b038281168752600b602090815286882094156110515781620f42406006545b6001880154906006821115611038576103c36103bd610df0610df794612a75565b928c612740565b04955b610e05871515612a92565b541691610e10612cb5565b88516370a0823160e01b815290821685820152908282602481875afa8015610ff95787928b91611003575b50610e8592610e4b911015612af2565b82610e54612cb5565b8a51636eb1769f60e11b81526001600160a01b03909116878201908152306020820152909384918291604090910190565b0381875afa8015610ff95787928b91610fc6575b50938291610ead8594610ef7971015612b49565b8b610eb6612cb5565b9160055460081c16918c51978895869485936323b872dd60e01b85528c850160409194939294606082019560018060a01b0380921683521660208201520152565b03925af1908115610fbc578891610f85575b50610f149150612bae565b610f2684610f20612cb5565b3061236f565b610f2e612cb5565b9186865180936395d89b4160e01b825281305afa91821561054a57907f60cd11ca617b0758c3cc25e1445e01a198b67383b98aa98703fbcbe083ca912b966105209493928993610526575051958695429487612c59565b905081813d8311610fb5575b610f9b8183612268565b81010312610b8057610faf610f1491612ba1565b38610f09565b503d610f91565b87513d8a823e3d90fd5b80929350848092503d8311610ff2575b610fe08183612268565b810103126105c5575186919083610e99565b503d610fd6565b89513d8c823e3d90fd5b809350848092503d8311611031575b61101c8183612268565b810103126105c5579051869190610e85610e3b565b503d611012565b61061e6103bd610df061104a94612a67565b0495610dfa565b81620f42406002870154610dcf565b50503461026f578160031936011261026f5760207f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2589161109e61232b565b6110a66125f2565b600160ff1960055416176005556110bb612cb5565b90516001600160a01b039091168152a180f35b50503461026f57602036600319011261026f5760209181906001600160a01b036110f6612212565b168152600d845220549051908152f35b50503461026f578160031936011261026f57517f000000000000000000000000d297ef4b1291a03027c5d190e251b47b0052f16a6001600160a01b03168152602090f35b83833461026f5761115a366122fb565b93338452600e60205261117260ff8486205416612929565b84511561127657611182856129ab565b1561123357301561121c57506105207f9e31786833642f5b8cf977c95ad5e181542fa9238c9c3105757e05b20e2597d893946111bc6125f2565b6111c8836002546125cf565b600255308652856020528386208381540190558351838152867fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60203093a361120f612cb5565b9351938493429185612980565b825163ec442f0560e01b8152908101849052602490fd5b606490602084519162461bcd60e51b8352820152601b60248201527f496e76616c69642049504653206164647265737320666f726d617400000000006044820152fd5b608490602084519162461bcd60e51b8352820152602760248201527f4175646974207265706f72742049504653206c696e6b206d75737420626520706044820152661c9bdd9a59195960ca1b6064820152fd5b50503461026f57366003190112610845576113006112e5612212565b602435906112fb826112f5612cb5565b83612455565b612528565b80f35b919050346106945760203660031901126106945761131f612212565b61132761232b565b6001600160a01b039081169061133e8215156128dd565b818552600b6020528285205416156113915783916002918352600b6020528220828155826001820155015560075490811561137e57506000190160075580f35b634e487b7160e01b835260119052602482fd5b815162461bcd60e51b8152602081850152600f60248201526e151bdad95b881b9bdd08199bdd5b99608a1b6044820152606490fd5b91905034610694576020918260031936011261159757600854813592906001600160a01b0390811680156118845782516331a9108f60e11b815284810186905260249087818381865afa908115611827578991611867575b508380611429612cb5565b1691160361183157835163021b797b60e11b81528581018790529460c0868381865afa958615611827578996611783575b5087860151421061174c578486015161171457600260ff606088015116036116c957845163020604bf60e21b815281810188905288818481875afa9081156115b2578a9161169c575b5084163014801561160c575b156115c057823b156115bc578451630852cd8d60e31b81528181018890528981848183885af180156115b25761159b575b5090829189933b1561159757839188918388519586948593630cd7a19560e41b85528401525af1801561158d57611571575b507fe305dcd5197faa39ababe23510783dbec4f835cfdcc3b347e68bae90f022a3a160808686868a8761154f611546612cb5565b8551903061236f565b611557612cb5565b93519383519586521690840152820152426060820152a180f35b61157f90959493929561223e565b610b7c579091928538611512565b84513d84823e3d90fd5b8380fd5b6115a990999193929961223e565b979091386114e0565b86513d8c823e3d90fd5b8880fd5b6084918886519262461bcd60e51b8452830152808201527f506869506179206e6f7420617070726f76656420746f207472616e7366657220604482015263189bdb9960e21b6064820152fd5b5061164a88611619612cb5565b875163e985e9c560e01b81526001600160a01b03909116848201908152306020820152909283918291604090910190565b0381875afa9081156115b2578a91611663575b506114af565b90508881813d8311611695575b61167a8183612268565b810103126116915761168b90612ba1565b3861165d565b8980fd5b503d611670565b6116bc9150893d8b116116c2575b6116b48183612268565b810190612c96565b386114a3565b503d6116aa565b60226084928987519362461bcd60e51b85528401528201527f426f6e64206d75737420626520696e20746865205661756c7465642073746174604482015261757360f01b6064820152fd5b60156064928987519362461bcd60e51b855284015282015274109bdb9908185b1c9958591e481c995919595b5959605a1b6044820152fd5b60146064928987519362461bcd60e51b855284015282015273109bdb99081b9bdd081e595d081b585d1d5c995960621b6044820152fd5b90955060c0813d821161181f575b8161179e60c09383612268565b810103126115bc5784519060c0820182811067ffffffffffffffff82111761180d5786528051825288810151898301526117d9868201612ba1565b8683015260608101519060ff8216820361064c5760a091606084015260808101516080840152015160a0820152943861145a565b634e487b7160e01b8b5260418852838bfd5b3d9150611791565b85513d8b823e3d90fd5b8460126064928987519362461bcd60e51b8552840152820152712737ba103a3432903137b7321037bbb732b960711b6044820152fd5b61187e9150883d8a116116c2576116b48183612268565b3861141e565b825162461bcd60e51b8152808501879052601c60248201527f506869676f6c64426f6e6420636f6e7472616374206e6f7420736574000000006044820152606490fd5b83346108455780600319360112610845576118e061232b565b60058054610100600160a81b03198116909155819060081c6001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b50503461026f57602036600319011261026f5760209181906001600160a01b03611950612212565b16815280845220549051908152f35b50503461026f577fc136285a46e61d975decf1d79f2b6bc4a858b008859bf182aaa16137e4e255dd90610520611994366122fb565b6119a182939215156126e6565b6119ad836112fb612cb5565b6119b5612cb5565b936119fd603282518094710283434b3b7b632102932b232b2b6b2b21d160751b60208301526119ed81518092602086860191016121ca565b8101036012810185520183612268565b51938493429185612980565b50503461026f57602036600319011261026f576060916001600160a01b0390829082611a33612212565b168152600b602052209081541691600260018301549201549181519384526020840152820152f35b50503461026f57602036600319011261026f57611a76612212565b611a7e61232b565b6001600160a01b03168252600e6020528120805460ff1916905580f35b50503461026f578160031936011261026f5760085490516001600160a01b039091168152602090f35b50503461026f578160031936011261026f5760209060ff6005541690519015158152f35b50503461026f5760a036600319011261026f57611b8190611b07612212565b611b0f612228565b916001600160a01b03611b45337f000000000000000000000000d297ef4b1291a03027c5d190e251b47b0052f16a831614612610565b8216808652600d602052611b5f6064358388205414612668565b8552600d6020528420611b7281546126a4565b90556084359160443591612773565b156108455780f35b50503461026f57602036600319011261026f57602090611ba7612212565b90519060018060a01b03807f000000000000000000000000d297ef4b1291a03027c5d190e251b47b0052f16a169116148152f35b90503461069457608036600319011261069457611bf6612212565b90602435906044359067ffffffffffffffff8211610b7c57611c1a913691016122dd565b92611c29606435838533612773565b15611c61577f42bdb50e0f9f5bf372eab7ce6b4ffefc203629ba351ca5be62662afdc4ee628e936105209151938493429133866126b3565b8480fd5b833461084557602036600319011261084557611c7f612212565b611c8761232b565b60018060a01b03166bffffffffffffffffffffffff60a01b600854161760085580f35b50503461026f57602036600319011261026f576105207f9fee46258bf9d123a7d66bbda27a92d2fe75e3bac91217431cf8875396aeae5c91611cea612212565b90611cf361232b565b600980546001600160a01b0319166001600160a01b03939093169283179055519081524260208201529081906040820190565b83903461026f57602036600319011261026f5761130090356112fb612cb5565b905034610694578260031936011261069457611d6061232b565b6005549060ff821615611da2575060ff19166005557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906020906110bb612cb5565b8251638dfc202b60e01b8152fd5b91905034610694576020908160031936011261159757611dce612212565b611dd661232b565b81516370a0823160e01b80825230828701526001600160a01b039290921694908481602481895afa8015611f37578790611f08575b611e1791501515612af2565b825191825230818301528382602481885afa918215611efe578692611ecd575b5090611e7d94849287611e48612cb5565b865163a9059cbb60e01b81526001600160a01b0390911692810192835260208301949094529296879384929091839160400190565b03925af1908115611ec45750611e91578280f35b81813d8311611ebd575b611ea58183612268565b8101031261026f57611eb690612ba1565b5038808280f35b503d611e9b565b513d85823e3d90fd5b91508382813d8311611ef7575b611ee48183612268565b81010312610b7c57905190611e7d611e37565b503d611eda565b83513d88823e3d90fd5b508481813d8311611f30575b611f1e8183612268565b81010312610b8057611e179051611e0b565b503d611f14565b84513d89823e3d90fd5b50503461026f578160031936011261026f576020905160068152f35b50503461026f578160031936011261026f576020906006549051908152f35b50503461026f57606036600319011261026f57602090610c06611f9d612212565b611fa5612228565b60443591610c01836112f5612cb5565b50503461026f578160031936011261026f576020906002549051908152f35b82843461084557608036600319011261084557611fef612212565b50611ff8612228565b506064359067ffffffffffffffff82116108455736602383011215610845575060209281602461202d933693013591016122a6565b5051630a85bd0160e11b8152f35b905034610694578160031936011261069457612055612212565b602435936001600160a01b038061206a612cb5565b169283156120d657169283156120c1575060208581968684867f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925965260018552818120888252855220558551908152a35160018152f35b602491855191634a1406b160e11b8352820152fd5b855163e602df0560e01b8152808601849052602490fd5b84843461026f578160031936011261026f578160035492600184811c918186169586156121c0575b60209687851081146121ad578899509688969785829a529182600014610801575050600114612151575050506107ba92916107ab910385612268565b9190869350600383527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b5b82841061219557505050820101816107ab6107ba610798565b8054848a01860152889550879490930192810161217c565b634e487b7160e01b835260228a52602483fd5b92607f1692612115565b60005b8381106121dd5750506000910152565b81810151838201526020016121cd565b90602091612206815180928185528580860191016121ca565b601f01601f1916010190565b600435906001600160a01b03821682036105c557565b602435906001600160a01b03821682036105c557565b67ffffffffffffffff811161225257604052565b634e487b7160e01b600052604160045260246000fd5b90601f8019910116810190811067ffffffffffffffff82111761225257604052565b67ffffffffffffffff811161225257601f01601f191660200190565b9291926122b28261228a565b916122c06040519384612268565b8294818452818301116105c5578281602093846000960137010152565b9080601f830112156105c5578160206122f8933591016122a6565b90565b9060406003198301126105c557600435916024359067ffffffffffffffff82116105c5576122f8916004016122dd565b6005546001600160a01b039060081c811681612345612cb5565b160361234e5750565b602490612359612cb5565b60405163118cdaa760e01b815291166004820152fd5b916001600160a01b0380841692831561243c5716928315612423576123926125f2565b600090838252816020526040822054908382106123f1575091604082827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef958760209652828652038282205586815220818154019055604051908152a3565b60405163391434e360e21b81526001600160a01b03919091166004820152602481019190915260448101839052606490fd5b60405163ec442f0560e01b815260006004820152602490fd5b604051634b637e8f60e11b815260006004820152602490fd5b9160018060a01b038093169160009383855260016020526040938486209183169182875260205284862054926000198403612494575b50505050505050565b8484106124f8575080156124e05781156124c85785526001602052838520908552602052039120553880808080808061248b565b8451634a1406b160e11b815260048101879052602490fd5b845163e602df0560e01b815260048101879052602490fd5b8551637dc7a0d960e11b81526001600160a01b039190911660048201526024810184905260448101859052606490fd5b906001600160a01b03821690811561243c576125426125f2565b6000928284528360205260408420549082821061259d5750817fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef926020928587528684520360408620558060025403600255604051908152a3565b60405163391434e360e21b81526001600160a01b03919091166004820152602481019190915260448101829052606490fd5b919082018092116125dc57565b634e487b7160e01b600052601160045260246000fd5b60ff600554166125fe57565b60405163d93c066560e01b8152600490fd5b1561261757565b60405162461bcd60e51b815260206004820152602360248201527f43616c6c6572206973206e6f7420746865207472757374656420666f727761726044820152623232b960e91b6064820152608490fd5b1561266f57565b60405162461bcd60e51b815260206004820152600d60248201526c496e76616c6964206e6f6e636560981b6044820152606490fd5b60001981146125dc5760010190565b91926122f895949160a094600180871b0380921685521660208401526040830152606082015281608082015201906121ed565b156126ed57565b60405162461bcd60e51b815260206004820152602560248201527f506869676f6c6420616d6f756e74206d75737420626520677265617465722074604482015264068616e20360dc1b6064820152608490fd5b818102929181159184041417156125dc57565b811561275d570490565b634e487b7160e01b600052601260045260246000fd5b926001600160a01b0391908282161561288d576127918415156126e6565b801561287e576127a5612710915b85612740565b04926127b184826125cf565b838616600052600060205260406000205410612842576127d1918561236f565b816127df575b505050600190565b612810827ff3816d9cce3442fbfe3e4d36ad047b3362efdc9f2e283e77b0ecd768a0a01ef29483600954169061236f565b60095460408051929091166001600160a01b0316825260208201929092524291810191909152606090a13880806127d7565b60405162461bcd60e51b8152602060048201526014602482015273496e73756666696369656e742062616c616e636560601b6044820152606490fd5b506127106127a5600a5461279f565b60405162461bcd60e51b815260206004820152602260248201527f526563697069656e742061646472657373206d7573742062652070726f766964604482015261195960f21b6064820152608490fd5b156128e457565b60405162461bcd60e51b815260206004820152601e60248201527f546f6b656e2061646472657373206d7573742062652070726f766964656400006044820152606490fd5b1561293057565b60405162461bcd60e51b815260206004820152602260248201527f4f6e6c792061646d696e732063616e2063616c6c20746869732066756e63746960448201526137b760f11b6064820152608490fd5b90926080926122f8959460018060a01b031683526020830152604082015281606082015201906121ed565b8051602e81149081612a45575b5080612a20575b612a1a57805190603b821491826129e1575b50506129dc57600090565b600190565b90915015612a0457602001516001600160f81b031916603160f91b1438806129d1565b634e487b7160e01b600052603260045260246000fd5b50600190565b50805160011015612a045760218101516001600160f81b031916606d60f81b146129bf565b905015612a045760208101516001600160f81b031916605160f81b14386129b8565b60060390600682116125dc57565b6005198101919082116125dc57565b604d81116125dc57600a0a90565b15612a9957565b60405162461bcd60e51b815260206004820152602b60248201527f5061796d656e7420746f6b656e20616d6f756e74206d7573742062652067726560448201526a061746572207468616e20360ac1b6064820152608490fd5b15612af957565b60405162461bcd60e51b815260206004820152602260248201527f496e73756666696369656e74207061796d656e7420746f6b656e2062616c616e604482015261636560f01b6064820152608490fd5b15612b5057565b60405162461bcd60e51b8152602060048201526024808201527f496e73756666696369656e74207061796d656e7420746f6b656e20616c6c6f77604482015263616e636560e01b6064820152608490fd5b519081151582036105c557565b15612bb557565b60405162461bcd60e51b815260206004820152601d60248201527f5061796d656e7420746f6b656e207472616e73666572206661696c65640000006044820152606490fd5b6020818303126105c55780519067ffffffffffffffff82116105c5570181601f820112156105c5578051612c2d8161228a565b92612c3b6040519485612268565b818452602082840101116105c5576122f891602080850191016121ca565b9695949193612c919360a095600180881b038094168a5260208a0152604089015216606087015260c0608087015260c08601906121ed565b930152565b908160209103126105c557516001600160a01b03811681036105c55790565b337f000000000000000000000000d297ef4b1291a03027c5d190e251b47b0052f16a6001600160a01b03161480612d03575b15612cff5760131936013681116125dc573560601c90565b3390565b506014361015612ce756fea2646970667358221220761afc950b717a7e4358657fd190b6c91f62bb885f7eee91c43d1855b67cc38564736f6c63430008140033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000d297ef4b1291a03027c5d190e251b47b0052f16a
-----Decoded View---------------
Arg [0] : trustedForwarder (address): 0xd297EF4b1291a03027c5d190e251B47B0052F16A
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000d297ef4b1291a03027c5d190e251b47b0052f16a
[ Download: CSV Export ]
[ Download: CSV Export ]
A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.