Feature Tip: Add private address tag to any address under My Name Tag !
Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 1 from a total of 1 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
0x60806040 | 19337461 | 267 days ago | IN | 0 ETH | 0.21952784 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
PlxTAO
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: UNLICENSED pragma solidity 0.8.20; import { Initializable } from "openzeppelin-contracts-upgradeable/proxy/utils/Initializable.sol"; import { ERC20Upgradeable } from "openzeppelin-contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; import { Ownable2StepUpgradeable } from "openzeppelin-contracts-upgradeable/access/Ownable2StepUpgradeable.sol"; import { wTAO } from "./wTAO.sol"; import { ReentrancyGuardUpgradeable } from "openzeppelin-contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol"; import { AccessControlUpgradeable } from "openzeppelin-contracts-upgradeable/access/AccessControlUpgradeable.sol"; import { SafeERC20} from "openzeppelin-contracts/token/ERC20/utils/SafeERC20.sol"; import "openzeppelin-contracts/token/ERC20/IERC20.sol"; contract PlxTAO is Initializable, ERC20Upgradeable, Ownable2StepUpgradeable, ReentrancyGuardUpgradeable, AccessControlUpgradeable { using SafeERC20 for IERC20; struct UnstakeRequest { uint256 amount; uint256 taoAmt; bool isReadyForUnstake; address wrappedToken; uint256 timestamp; } /* * set the exchange rate of wTAO:plxTAO. * exchange rate is in 10^18 */ uint256 public exchangeRate; // 1 * 10^18 /* * How much TAO it cost to unstake. This is to account for bridging cost from finney to eth */ uint256 public unstakingFee; /* * How much TAO it cost to stake. This is to account for bridging cost from eth to finney */ uint256 public stakingFee; /* * How much TAO it cost to bridge. */ uint256 public bridgingFee; /* * How much is needed to be staked to be able to perform staking in 1 txn */ uint256 public minStakingAmt; /* * Underlying token */ address public wrappedToken; /* * Set the max amount of wTAO that can be deposited at once */ uint256 public maxDepositPerRequest; /* * Determine if the contract is paused */ bool public isPaused; /* * finney wallet that will receive the wTAO after wrap() * NOTE: it must be at least 48 chars so validation shall * be done to ensure that it is true */ string public nativeWalletReceiver; /* * Set the max amount of unstake request for a given user */ uint256 public maxUnstakeRequests; /* * Mapping from address to current active UnstakeRequest[] */ mapping(address => UnstakeRequest[]) public unstakeRequests; /* * The address that can be allowed to withdraw */ address public withdrawalManager; /* * The service fee that is charged for each unstake request in ETH * This is to pay for the gas fees for the withdrawal manager */ uint256 public serviceFee; /* * * Defines maxSupply for plxTAO * * */ uint256 public maxSupply; /* * Defines both the upper bound and lower bound of the exchange rate */ uint256 public lowerExchangeRateBound; uint256 public upperExchangeRateBound; address public protocolVault; bytes32 public constant PAUSE_ROLE = keccak256("PAUSE_ROLE"); bytes32 public constant EXCHANGE_UPDATE_ROLE = keccak256("EXCHANGE_UPDATE_ROLE"); bytes32 public constant MANAGE_STAKING_CONFIG_ROLE = keccak256("MANAGE_STAKING_CONFIG_ROLE"); bytes32 public constant TOKEN_SAFE_PULL_ROLE = keccak256("TOKEN_SAFE_PULL_ROLE"); bytes32 public constant APPROVE_WITHDRAWAL_ROLE = keccak256("APPROVE_WITHDRAWAL_ROLE"); modifier canPauseRole() { require(hasRole(PAUSE_ROLE, msg.sender), "Caller does not have PAUSE_ROLE"); _; } modifier hasExchangeUpdateRole() { require( hasRole(EXCHANGE_UPDATE_ROLE, msg.sender), "Caller does not have EXCHANGE_UPDATE_ROLE" ); _; } modifier hasManageStakingConfigRole() { require( hasRole(MANAGE_STAKING_CONFIG_ROLE, msg.sender), "Caller does not have MANAGE_STAKING_UPDATE_ROLE" ); _; } modifier hasTokenSafePullRole() { require( hasRole(TOKEN_SAFE_PULL_ROLE, msg.sender), "Caller does not have TOKEN_SAFE_PULL_ROLE" ); _; } modifier hasApproveWithdrawalRole() { require( hasRole(APPROVE_WITHDRAWAL_ROLE, msg.sender), "Caller does not have APPROVE_WITHDRAWAL_ROLE" ); _; } struct UserRequest { address user; uint256 requestIndex; } // Keep counter of the amouht of wTAO to batch uint256 public batchTAOAmt; // Declaration of all events event UserUnstakeRequested( address indexed user, uint256 idx, uint256 requestTimestamp, uint256 wstAmount, uint256 outTaoAmt, address wrappedToken ); event AdminUnstakeApproved( address indexed user, uint256 idx, uint256 approvedTimestamp ); event UserUnstake( address indexed user, uint256 idx, uint256 unstakeTimestamp ); event UserStake( address indexed user, uint256 stakeTimestamp, uint256 inTaoAmt, uint256 wstAmount ); event UpdateProtocolVault(address newProtocolVault); event UpdateMaxSupply(uint256 newMaxSupply); event UpdateServiceFee(uint256 serviceFee); event UpdateWithdrawalManager(address withdrawalManager); event UpdateMinStakingAmt(uint256 minStakingAmt); event UpdateStakingFee(uint256 stakingFee); event UpdateBridgeFee(uint256 bridgingFee); event UpdateMaxDepositPerRequest(uint256 maxDepositPerRequest); event UpdateMaxUnstakeRequest(uint256 maxUnstakeRequests); event UpdateExchangeRate(uint256 newRate); event LowerBoundUpdated(uint256 newLowerBound); event UpperBoundUpdated(uint256 newUpperBound); event ContractPaused(bool paused); event UpdateWTao(address newWTAO); event UpdateUnstakingFee(uint256 newUnstakingFee); event UpdateNativeFinneyReceiver(string newNativeWalletReceiver); event ERC20TokenPulled(address tokenAddress, address to, uint256 amount); event NativeTokenPulled(address to, uint256 amount); // End of Declaration of all events constructor() { _disableInitializers(); } /* * * In this initialization function, we initialize and * set the intiailOwner as the owner of plxTAO * * Initial supply must be more than 0. If initialSupply is 10^9 * that means initial supply is 1 TAO * * */ function initialize(address initialOwner, uint256 initialSupply) public initializer { require(initialOwner != address(0), "Owner cannot be null"); require(initialSupply > 0, "Initial supply must be more than 0"); __ERC20_init("Tensorplex Staked TAO", "stTAO"); __Ownable_init(initialOwner); __AccessControl_init(); __ReentrancyGuard_init(); _setRoleAdmin(DEFAULT_ADMIN_ROLE, DEFAULT_ADMIN_ROLE); _transferOwnership(initialOwner); _grantRole(DEFAULT_ADMIN_ROLE, initialOwner); maxSupply = initialSupply; } /* * Common setters for the contract * */ /* * * Function to update the current ETH service fee to support gas transactions for unstaking. * * Value Boundary: serviceFee can be 0 ETH * */ function setServiceFee(uint256 _serviceFee) public hasManageStakingConfigRole { require(_serviceFee <= 0.01 ether, "Service fee cannot be more than 0.01 ETH"); serviceFee = _serviceFee; emit UpdateServiceFee(serviceFee); } /* * * Function to set the withdrawal manager address that will receive the ETH service fee * * Value boundary: withdrawalManager cannot be address(0) * */ function setWithdrawalManager(address _withdrawalManager) public hasManageStakingConfigRole { require(_withdrawalManager != address(0), "Withdrawal manager cannot be null"); withdrawalManager = _withdrawalManager; emit UpdateWithdrawalManager(withdrawalManager); } /* * * This function sets the protocol vault address that * shall be responsible for receiving the staking fees. * * Boundary: address cannot be address(0) * */ function setProtocolVault(address _protocolVault) public hasManageStakingConfigRole { require(_protocolVault != address(0), "Protocol vault cannot be null"); protocolVault = _protocolVault; emit UpdateProtocolVault(protocolVault); } /* * * This methood sets the new max supply of plxTAO * * Value Boundary: maxSupply cannot be less than the current total supply. * * E.g. if total supply is 1000, new max supply must be more than 1000. _maxSupply provided cannot be 1000. * */ function setMaxSupply(uint256 _maxSupply) public hasManageStakingConfigRole { require(_maxSupply > totalSupply(), "Max supply must be greater than the current total supply"); maxSupply = _maxSupply; emit UpdateMaxSupply(maxSupply); } /* * * This method sets the min staking amount required to perform staking * * Value Boundary: minStakingAmt can be any value even 0 in the event that minStakingAmt by taobridge changes in the future * */ function setMinStakingAmt(uint256 _minStakingAmt) public hasManageStakingConfigRole { require(_minStakingAmt > bridgingFee, "Min staking amount must be more than bridging fee"); minStakingAmt = _minStakingAmt; emit UpdateMinStakingAmt(minStakingAmt); } /* * * Value Boundary: stakingFee can be between 0-999 (0% to 99.9%) * * 0% can be set in case stakingFee is disabled in the future. * */ function setStakingFee(uint256 _stakingFee) public hasManageStakingConfigRole { // Staking fee cannot be equivalent to 2% staking fee. Max it can go is 19 (1.9%) require(_stakingFee < 20, "Staking fee cannot be more than equal to 20"); stakingFee = _stakingFee; emit UpdateStakingFee(stakingFee); } /* * * This function sets the bridging fee that is used to bridge from eth to finney * * Value Boundary: bridgingFee can be any value even 0 in the event that bridgingFee by taobridge changes in the future * */ function setBridgingFee(uint256 _bridgingFee) public hasManageStakingConfigRole { require(_bridgingFee <= 0.2 gwei, "Bridging fee cannot be more than 0.2 TAO"); bridgingFee = _bridgingFee; // Assuming _bridgingFee is passed in mwei emit UpdateBridgeFee(bridgingFee); } /* * * Set the maximum number of deposit per request for a given user * * Value Boundary: maxDepositPerRequest must be more than 0 * */ function setMaxDepositPerRequest(uint256 _maxDepositPerRequest) public hasManageStakingConfigRole { require(_maxDepositPerRequest > 0, "Max deposit per request must be more than 0"); maxDepositPerRequest = _maxDepositPerRequest; emit UpdateMaxDepositPerRequest(maxDepositPerRequest); } /* * * Set maximum unstake request * * Value Boundary: maxUnstakeRequests must be more than 0 * */ function setMaxUnstakeRequest(uint256 _maxUnstakeRequests) public hasManageStakingConfigRole { require(_maxUnstakeRequests > 0, "Max unstake requests must be more than 0"); maxUnstakeRequests = _maxUnstakeRequests; emit UpdateMaxUnstakeRequest(maxUnstakeRequests); } function renounceOwnership() public override onlyOwner {} // Ensure that the lower bound is less than upper bound function setLowerExchangeRateBound(uint256 _newLowerBound) public hasExchangeUpdateRole { require(_newLowerBound > 0, "New lower bound must be more than 0"); require( _newLowerBound < upperExchangeRateBound, "New lower bound must be less than current upper bound" ); lowerExchangeRateBound = _newLowerBound; emit LowerBoundUpdated(_newLowerBound); } // Ensure that the upper bound is more than lower bound function setUpperExchangeRateBound(uint256 _newUpperBound) public hasExchangeUpdateRole { require(_newUpperBound > 0, "New upper bound must be more than 0"); require( _newUpperBound > lowerExchangeRateBound, "New upper bound must be greater than current lower bound" ); upperExchangeRateBound = _newUpperBound; emit UpperBoundUpdated(_newUpperBound); } /* * Our decimal places follow tao 9 decimal place. */ function decimals() public view virtual override returns (uint8) { return 9; } function setPaused(bool _isPaused) public canPauseRole { isPaused = _isPaused; emit ContractPaused(isPaused); } /* * * This function determines the unstaking fee that is charged to the user * * The value is in gwei so if _unstakingFee is 1 gwei, it means 1 TAO is charged as unstaking fee * * Value Boundary: UnstakingFee can be any value even 0 in the event that unstakingFee is not longer charged. * */ function setUnstakingFee(uint256 _unstakingFee) public hasManageStakingConfigRole { require(_unstakingFee <= 0.2 gwei, "Unstaking fee cannot be more than 0.2 TAO"); unstakingFee = _unstakingFee; emit UpdateUnstakingFee(unstakingFee); } /* * * This function sets to wtao address that will be used to wrap and unwrap * * Value boundary: wTAO cannot be address(0) * */ function setWTAO(address _wTAO) public hasManageStakingConfigRole nonReentrant { // Check to ensure _wTAO is not null _requireNonZeroAddress(_wTAO, "wTAO address cannot be null"); address oldWTAO = wrappedToken; wrappedToken = _wTAO; if(batchTAOAmt > 0) { _checkValidFinneyWallet(nativeWalletReceiver); uint256 amountToBridgeBack = batchTAOAmt; batchTAOAmt = 0; bool success = wTAO(oldWTAO).bridgeBack( amountToBridgeBack, nativeWalletReceiver ); require(success, "Bridge back failed"); } emit UpdateWTao(_wTAO); } /* * Function to set the natvive token receiver. Validation performed to determine if 48 characters */ function setNativeTokenReceiver(string memory _nativeWalletReceiver) public hasManageStakingConfigRole { // Ensure it is a valid finney wallet before updating. _checkValidFinneyWallet(_nativeWalletReceiver); nativeWalletReceiver = _nativeWalletReceiver; emit UpdateNativeFinneyReceiver(_nativeWalletReceiver); } /* * * These those methods shall help to calculate the exchange rate * of wstTAO given wTAO input and vice versa * * Note that there would be precision loss that would be rounded down * so the user will get less than expected to a precision of up to 1 wei if the rounding * down happens. * */ function getWstTAObyWTAO(uint256 wtaoAmount) public view returns (uint256) { return (wtaoAmount * exchangeRate) / 1 ether; } function getWTAOByWstTAO(uint256 wstTaoAmount) public view returns (uint256) { return (wstTaoAmount * 1 ether) / exchangeRate; } function getWTAOByWstTAOAfterFee(uint256 wstTaoAmount) public view returns (uint256) { return ((wstTaoAmount - unstakingFee) * 1 ether) / exchangeRate; } /* * * Here we add utility functions so that * we can perform checks using DRY principles * */ /* * * */ function _transferToVault(uint256 _feeAmt) internal { IERC20(wrappedToken).safeTransferFrom(msg.sender, address(protocolVault), _feeAmt); } function _transferToContract(uint256 _wrapAmt) internal { IERC20(wrappedToken).safeTransferFrom(msg.sender, address(this), _wrapAmt); } // Check if the address is a non null address // @param _address The address to check // @param errorMessage The error message to display if the address is null function _requireNonZeroAddress(address _address, string memory errorMessage) internal pure { require(_address != address(0), errorMessage); } /* * * this method is used to check if the native wallet receiver is valid * finney walllet must be 48 characters * * @param _nativeWalletReceiver The native wallet receiver to check * */ function _checkValidFinneyWallet(string memory _nativeWalletReceiver) internal pure { require( bytes(_nativeWalletReceiver).length == 48, "nativeWalletReceiver must be of length 48" ); } /* * * Mints only if the max supply is exceeded * */ function _mintWithSupplyCap(address account, uint256 amount) internal { require(totalSupply() + amount <= maxSupply, "Max supply exceeded"); _mint(account, amount); } // Check if the contract is paused modifier checkPaused() { require(!isPaused, "Contract is paused"); _; } /* * This function is used for users to request for unstaking * When users request for unstaking, they will need to pay a fee * The fee will be used to pay for the gas fees for the withdrawal manager * * After user successfully request for unstake, the withdrawal manage will * need to approve the request before the user can unstake * * @params wstTAOAmt The amount of wstTAO to unstake * * */ function requestUnstake(uint256 wstTAOAmt) public payable nonReentrant checkPaused { // Check that wrappedToken and withdrawalManager is a valid address _requireNonZeroAddress( address(wrappedToken), "wrappedToken address is invalid" ); _requireNonZeroAddress( address(withdrawalManager), "withdrawal address cannot be null" ); // Ensure that the fee amount is sufficient require(msg.value >= serviceFee, "Fee amount is not sufficient"); require(wstTAOAmt > unstakingFee, "Invalid wstTAO amount"); // Check if enough balance require(balanceOf(msg.sender) >= wstTAOAmt, "Insufficient wstTAO balance"); uint256 outWTaoAmt = getWTAOByWstTAOAfterFee(wstTAOAmt); uint256 length = unstakeRequests[msg.sender].length; bool added = false; // Loop throught the list of existing unstake requests for (uint256 i = 0; i < length; i++) { uint256 currAmt = unstakeRequests[msg.sender][i].amount; if (currAmt > 0) { continue; } else { // If the curr amt is zero, it means // we can add the unstake request in this index unstakeRequests[msg.sender][i] = UnstakeRequest({ amount: wstTAOAmt, taoAmt: outWTaoAmt, isReadyForUnstake: false, timestamp: block.timestamp, wrappedToken: wrappedToken }); added = true; emit UserUnstakeRequested( msg.sender, i, block.timestamp, wstTAOAmt, outWTaoAmt, wrappedToken ); break; } } // If we have not added the unstake request, it means that // we need to push a new unstake request into the array if (!added) { require( unstakeRequests[msg.sender].length < maxUnstakeRequests, "Maximum unstake requests exceeded" ); unstakeRequests[msg.sender].push( UnstakeRequest({ amount: wstTAOAmt, taoAmt: outWTaoAmt, isReadyForUnstake: false, timestamp: block.timestamp, wrappedToken: wrappedToken }) ); emit UserUnstakeRequested( msg.sender, length, block.timestamp, wstTAOAmt, outWTaoAmt, wrappedToken ); } // Perform burn _burn(msg.sender, wstTAOAmt); // transfer the service fee to the withdrawal manager // withdrawalManager have already been checked to be a non zero address // in the guard condition at start of function bool success = payable(withdrawalManager).send(serviceFee); require(success, "Service fee transfer failed"); } function getUnstakeRequestByUser(address user) public view returns (UnstakeRequest[] memory) { return unstakeRequests[user]; } /* * * This method shall be used to approve withdrawals by the user * The withdrawal manager will need to approve the withdrawal. * * Note that multiple requests can be approved at once * * @params requests The list of requests to approve * * */ function approveMultipleUnstakes(UserRequest[] calldata requests) public hasApproveWithdrawalRole nonReentrant checkPaused { uint256 totalRequiredTaoAmt = 0; require(requests.length > 0, "Requests array is empty"); require( requests[0].requestIndex < unstakeRequests[requests[0].user].length, "First request index out of bounds" ); // There might be cases that the underlying token might be different // so we need to add checks to ensure that the unstaking is the same token // across all indexes in the current requests UserRequest[] array // If there is 2 different tokens underlying in the requests, we return the // error as system is not designed to handle such a scenario. // In that scenario, the user needs to unstake the tokens separately // in two separate request address commonWrappedToken = unstakeRequests[requests[0].user][requests[0].requestIndex].wrappedToken; // Loop through each request to unstake and check if the request is valid for (uint256 i = 0; i < requests.length; i++) { UserRequest calldata request = requests[i]; require( request.requestIndex < unstakeRequests[request.user].length, "Invalid request index" ); require( unstakeRequests[request.user][request.requestIndex].amount > 0, "Request is invalid" ); require( !unstakeRequests[request.user][request.requestIndex].isReadyForUnstake, "Request is already approved" ); // Check if wrappedToken is the same for all requests require( unstakeRequests[request.user][request.requestIndex].wrappedToken == commonWrappedToken, "Wrapped token is not the same across all unstake requests" ); totalRequiredTaoAmt += unstakeRequests[request.user][request.requestIndex] .taoAmt; } // Check if the sender has allowed the contract to spend enough tokens require( IERC20(commonWrappedToken).allowance(msg.sender, address(this)) >= totalRequiredTaoAmt, "Insufficient token allowance" ); for (uint256 i = 0; i < requests.length; i++) { UserRequest calldata request = requests[i]; unstakeRequests[request.user][request.requestIndex] .isReadyForUnstake = true; } // Transfer the tao from the withdrawal manager to this contract IERC20(commonWrappedToken).safeTransferFrom( msg.sender, address(this), totalRequiredTaoAmt ); // Emit events after state changes and external interactions for (uint256 i = 0; i < requests.length; i++) { UserRequest calldata request = requests[i]; emit AdminUnstakeApproved( request.user, request.requestIndex, block.timestamp ); } } /* * * This method shall be used by the user to unstake and withdraw the * redeemed tao to their wallet * * @params requestIndex The index of the request to unstake * */ function unstake(uint256 requestIndex) public nonReentrant checkPaused { require( requestIndex < unstakeRequests[msg.sender].length, "Invalid request index" ); UnstakeRequest memory request = unstakeRequests[msg.sender][requestIndex]; require(request.amount > 0, "No unstake request found"); require(request.isReadyForUnstake, "Unstake not approved yet"); // Transfer wTAO tokens back to the user uint256 amountToTransfer = request.taoAmt; // Update state to false delete unstakeRequests[msg.sender][requestIndex]; // Perform ERC20 transfer IERC20(request.wrappedToken).safeTransfer( msg.sender, amountToTransfer ); // Process the unstake event emit UserUnstake(msg.sender, requestIndex, block.timestamp); } /* * * This method shall be used by the admin to exchange the market rate * and the value of wTAO:plxTAO. * * Owner shall be multisignature wallet * * @params newRate The new exchange rate * */ function updateExchangeRate(uint256 newRate) public hasExchangeUpdateRole { require(newRate > 0, "New rate must be more than 0"); require( newRate >= lowerExchangeRateBound && newRate <= upperExchangeRateBound, "New rate must be within bounds" ); // This also checks for newRate > 0 since lowerExchangeRateBound is always more than 0 // Recommended min lower and upper bound is define upon initialization require( lowerExchangeRateBound > 0 && upperExchangeRateBound > 0, "Bounds must be more than 0" ); exchangeRate = newRate; emit UpdateExchangeRate(newRate); } /* * This method calculates the amount of wTAO after deducting both * the bridging fee and the staking fee * * In this calculation: * 1. We first deduct the bridging fee from the wTAO amount * 2. We then calculate the staking fee based on the amountAfterBridgingFee * 3. We then deduct the staking fee from the amountAfterBridgingFee * * Note: * 1. wTAOAmont must be bigger than bridgingFee * 2. amountAfterTotalFees much be more than 0 * */ function calculateAmtAfterFee(uint256 wtaoAmount) public view returns (uint256, uint256) { require( wtaoAmount > bridgingFee, "wTAO amount must be more than bridging fee" ); uint256 amountAfterBridgingFee = wtaoAmount - bridgingFee; // Apply the staking fee as a percentage (e.g., 0.1%) // Note: Multiply by 1000 to convert the decimal percentage to an integer uint256 feeAmount = 0; if(stakingFee > 0) { /* * * Formula to calculate feeAmount. Note that there might be precision loss of * 1 wei due to the division which is approx 4e-7 if TAO is $400 which is negliglbe * So we can accept this precision loss * */ feeAmount = (amountAfterBridgingFee * stakingFee) / 1000; } // Subtract the percentage-based staking fee from the amount after bridging fee uint256 amountAfterTotalFees = amountAfterBridgingFee - feeAmount; require(amountAfterTotalFees > 0, "Wrap amount after fee must be more than 0"); return (amountAfterTotalFees, feeAmount); } /* * * How to calculate the max TAO that we can wrap given the current supply. * * In this case, we need to reverse calculation used for calculateAmtAfterFee * * */ function maxTaoForWrap() public view returns (uint256) { uint256 availablePlxTAOSupply = maxSupply - totalSupply(); if (availablePlxTAOSupply == 0) { return 0; } uint256 equivalentTaoAmount = (availablePlxTAOSupply * 1 ether) / exchangeRate; uint256 grossTaoAmount; // Adjust for the staking fee and bridging fee if(stakingFee > 0) { grossTaoAmount = (equivalentTaoAmount * 1000) / (1000 - stakingFee); } else { grossTaoAmount = equivalentTaoAmount; } uint256 maxTaoToWrap = grossTaoAmount + bridgingFee; // Ensure the result does not exceed availablePlxTAOSupply return maxTaoToWrap; } /* * This function shall be used by the user to wrap their wTAO tokens * and get plxTAO in return * * Note that stakingFee cna be 0% (0) so we do need to check for that * */ function wrap(uint256 wtaoAmount) public nonReentrant checkPaused { // Deposit cap amount require( maxDepositPerRequest >= wtaoAmount, "Deposit amount exceeds maximum" ); string memory _nativeWalletReceiver = nativeWalletReceiver; IERC20 _wrappedToken = IERC20(wrappedToken); // Check that the nativeWalletReceiver is not an empty string _checkValidFinneyWallet(_nativeWalletReceiver); _requireNonZeroAddress( address(_wrappedToken), "wrappedToken address is invalid" ); require( _wrappedToken.balanceOf(msg.sender) >= wtaoAmount, "Insufficient wTAO balance" ); // Check to ensure that the protocol vault address is not zero _requireNonZeroAddress( address(protocolVault), "Protocol vault address cannot be 0" ); // Ensure that at least 0.125 TAO is being bridged // based on the smart contract require(wtaoAmount > minStakingAmt, "Does not meet minimum staking amount"); // Ensure that the wrap amount after free is more than 0 (uint256 wrapAmountAfterFee, uint256 feeAmt) = calculateAmtAfterFee(wtaoAmount); uint256 wstTAOAmount = getWstTAObyWTAO(wrapAmountAfterFee); // Perform token transfers _mintWithSupplyCap(msg.sender, wstTAOAmount); _transferToVault(feeAmt); uint256 amtToBridge = wrapAmountAfterFee + bridgingFee; _transferToContract(amtToBridge); // We add this to the total amount we would like to batch together. batchTAOAmt += amtToBridge; emit UserStake(msg.sender, block.timestamp, wtaoAmount, wstTAOAmount); } /* * * This function shall be responsible for batch transfer of the wTAO * to the taobridge * * withdrawal wallet shall be responsible for performing this task * * */ function batchTransferBridgeBack() public hasApproveWithdrawalRole nonReentrant { // ensure both wrappedToken and nativeWalletReceiver is a valid address _requireNonZeroAddress( address(wrappedToken), "wrappedToken address is invalid" ); _checkValidFinneyWallet(nativeWalletReceiver); require(batchTAOAmt > 0, "No TAO to bridge back"); uint256 amountToBridgeBack = batchTAOAmt; batchTAOAmt = 0; // Call the bridge back to send the TAO to the taobridge and indicate the finney wallet that // will receive it bool success = wTAO(wrappedToken).bridgeBack( amountToBridgeBack, nativeWalletReceiver ); // reset the batchTAOAmt to 0 so that we are able to keep track of the next batch require(success, "Bridge back failed"); } function safePullERC20( address tokenAddress, address to, uint256 amount ) public hasTokenSafePullRole checkPaused { _requireNonZeroAddress(to, "Recipient address cannot be null address"); require(amount > 0, "Amount must be greater than 0"); IERC20 token = IERC20(tokenAddress); uint256 balance = token.balanceOf(address(this)); require(balance >= amount, "Not enough tokens in contract"); // Deduct the amount from the batchTAOAmt if the token is wTAO if(tokenAddress == wrappedToken) { if(amount >= batchTAOAmt) { batchTAOAmt = 0; } else { batchTAOAmt -= amount; } } // "to" have been checked to be a non zero address token.safeTransfer(to, amount); emit ERC20TokenPulled(tokenAddress, to, amount); } function pullNativeToken(address to, uint256 amount) public hasTokenSafePullRole checkPaused { _requireNonZeroAddress(to, "Recipient address cannot be null address"); require(amount > 0, "Amount must be greater than 0"); uint256 balance = address(this).balance; require(balance >= amount, "Not enough native tokens in contract"); // "to" have been checked to be a non zero address (bool success, ) = to.call{ value: amount }(""); require(success, "Native token transfer failed"); emit NativeTokenPulled(to, amount); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.20; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ```solidity * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Storage of the initializable contract. * * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions * when using with upgradeable contracts. * * @custom:storage-location erc7201:openzeppelin.storage.Initializable */ struct InitializableStorage { /** * @dev Indicates that the contract has been initialized. */ uint64 _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool _initializing; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00; /** * @dev The contract is already initialized. */ error InvalidInitialization(); /** * @dev The contract is not initializing. */ error NotInitializing(); /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint64 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. * * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in * production. * * Emits an {Initialized} event. */ modifier initializer() { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); // Cache values to avoid duplicated sloads bool isTopLevelCall = !$._initializing; uint64 initialized = $._initialized; // Allowed calls: // - initialSetup: the contract is not in the initializing state and no previous version was // initialized // - construction: the contract is initialized at version 1 (no reininitialization) and the // current contract is just being deployed bool initialSetup = initialized == 0 && isTopLevelCall; bool construction = initialized == 1 && address(this).code.length == 0; if (!initialSetup && !construction) { revert InvalidInitialization(); } $._initialized = 1; if (isTopLevelCall) { $._initializing = true; } _; if (isTopLevelCall) { $._initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * A reinitializer may be used after the original initialization step. This is essential to configure modules that * are added through upgrades and that require initialization. * * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` * cannot be nested. If one is invoked in the context of another, execution will revert. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. * * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint64 version) { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); if ($._initializing || $._initialized >= version) { revert InvalidInitialization(); } $._initialized = version; $._initializing = true; _; $._initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { _checkInitializing(); _; } /** * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}. */ function _checkInitializing() internal view virtual { if (!_isInitializing()) { revert NotInitializing(); } } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); if ($._initializing) { revert InvalidInitialization(); } if ($._initialized != type(uint64).max) { $._initialized = type(uint64).max; emit Initialized(type(uint64).max); } } /** * @dev Returns the highest version that has been initialized. See {reinitializer}. */ function _getInitializedVersion() internal view returns (uint64) { return _getInitializableStorage()._initialized; } /** * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. */ function _isInitializing() internal view returns (bool) { return _getInitializableStorage()._initializing; } /** * @dev Returns a pointer to the storage namespace. */ // solhint-disable-next-line var-name-mixedcase function _getInitializableStorage() private pure returns (InitializableStorage storage $) { assembly { $.slot := INITIALIZABLE_STORAGE } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/ERC20.sol) pragma solidity ^0.8.20; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import {ContextUpgradeable} from "../../utils/ContextUpgradeable.sol"; import {IERC20Errors} from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol"; import {Initializable} from "../../proxy/utils/Initializable.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 ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20, IERC20Metadata, IERC20Errors { /// @custom:storage-location erc7201:openzeppelin.storage.ERC20 struct ERC20Storage { mapping(address account => uint256) _balances; mapping(address account => mapping(address spender => uint256)) _allowances; uint256 _totalSupply; string _name; string _symbol; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ERC20")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant ERC20StorageLocation = 0x52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace00; function _getERC20Storage() private pure returns (ERC20Storage storage $) { assembly { $.slot := ERC20StorageLocation } } /** * @dev Sets the values for {name} and {symbol}. * * All two of these values are immutable: they can only be set once during * construction. */ function __ERC20_init(string memory name_, string memory symbol_) internal onlyInitializing { __ERC20_init_unchained(name_, symbol_); } function __ERC20_init_unchained(string memory name_, string memory symbol_) internal onlyInitializing { ERC20Storage storage $ = _getERC20Storage(); $._name = name_; $._symbol = symbol_; } /** * @dev Returns the name of the token. */ function name() public view virtual returns (string memory) { ERC20Storage storage $ = _getERC20Storage(); return $._name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual returns (string memory) { ERC20Storage storage $ = _getERC20Storage(); 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) { ERC20Storage storage $ = _getERC20Storage(); return $._totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view virtual returns (uint256) { ERC20Storage storage $ = _getERC20Storage(); 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) { ERC20Storage storage $ = _getERC20Storage(); 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 { ERC20Storage storage $ = _getERC20Storage(); 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 { ERC20Storage storage $ = _getERC20Storage(); 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) (access/Ownable2Step.sol) pragma solidity ^0.8.20; import {OwnableUpgradeable} from "./OwnableUpgradeable.sol"; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Contract module which provides access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * The initial owner is specified at deployment time in the constructor for `Ownable`. This * can later be changed with {transferOwnership} and {acceptOwnership}. * * This module is used through inheritance. It will make available all functions * from parent (Ownable). */ abstract contract Ownable2StepUpgradeable is Initializable, OwnableUpgradeable { /// @custom:storage-location erc7201:openzeppelin.storage.Ownable2Step struct Ownable2StepStorage { address _pendingOwner; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Ownable2Step")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant Ownable2StepStorageLocation = 0x237e158222e3e6968b72b9db0d8043aacf074ad9f650f0d1606b4d82ee432c00; function _getOwnable2StepStorage() private pure returns (Ownable2StepStorage storage $) { assembly { $.slot := Ownable2StepStorageLocation } } event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner); function __Ownable2Step_init() internal onlyInitializing { } function __Ownable2Step_init_unchained() internal onlyInitializing { } /** * @dev Returns the address of the pending owner. */ function pendingOwner() public view virtual returns (address) { Ownable2StepStorage storage $ = _getOwnable2StepStorage(); return $._pendingOwner; } /** * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one. * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual override onlyOwner { Ownable2StepStorage storage $ = _getOwnable2StepStorage(); $._pendingOwner = newOwner; emit OwnershipTransferStarted(owner(), newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner. * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual override { Ownable2StepStorage storage $ = _getOwnable2StepStorage(); delete $._pendingOwner; super._transferOwnership(newOwner); } /** * @dev The new owner accepts the ownership transfer. */ function acceptOwnership() public virtual { address sender = _msgSender(); if (pendingOwner() != sender) { revert OwnableUnauthorizedAccount(sender); } _transferOwnership(sender); } }
// import openzeppelin-solidity/contracts/token/ERC20/ERC20.sol; // import openzeppelin-solidity/contracts/math/SafeMath.sol; // import ownable as well // import access controls pragma solidity ^0.8.0; import "lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol"; import "lib/openzeppelin-contracts/contracts/access/Ownable.sol"; import "lib/openzeppelin-contracts/contracts/access/AccessControl.sol"; contract wTAO is ERC20, Ownable, AccessControl { // Roles // access role to call bridgedTo bytes32 public constant BRIDGE_ROLE = keccak256("BRIDGE_ROLE"); uint256 public _nonce = 0; uint256 public BITTENSOR_FEE = 25000145; // 0.1251 wTAO uint256 public cumulative_bridged = 0; uint256 public cumulative_bridged_back = 0; bool public paused; bool public transferPaused; // events event Mint(address indexed to, uint256 amount); event BridgedTo( string from, address indexed to, uint256 amount, uint256 nonce ); // burn events include a signed message of where to bridge funds to event BridgedBack( address indexed from, uint256 amount, string to, uint256 nonce ); event BridgeSet(address indexed bridge); constructor() ERC20("Token", "Token") Ownable(msg.sender) { // _setupRole(DEFAULT_ADMIN_ROLE, _msgSender()); // set owner as admin paused = false; transferPaused = false; } // constructor() ERC20("Wrapped TAO", "wTAO") { // // set owner as admin // } function test() public {} function transfer(address to, uint256 amount) public virtual override returns (bool) { if (transferPaused) { return false; } address owner = _msgSender(); _transfer(owner, to, amount); return true; } function transferFrom( address from, address to, uint256 amount ) public virtual override returns (bool) { address spender = _msgSender(); if (transferPaused) { return false; } _spendAllowance(from, spender, amount); _transfer(from, to, amount); return true; } function decimals() public view virtual override returns (uint8) { return 9; } // function setBridge(address _bridge) public onlyOwner returns (bool) { // _setupRole(BRIDGE_ROLE, _bridge); // return true; // } function mint(address _to, uint256 _amount) public onlyOwner returns (bool) { _mint(_to, _amount); emit Mint(_to, _amount); return true; } function bridgedTo(string[] memory _froms, address[] memory _tos, uint256[] memory _amounts) public returns(bool) { // require all arrays are the same length require(_froms.length == _tos.length && _froms.length == _amounts.length, "Arrays are not the same length"); // loop through arrays and mint for (uint256 i = 0; i < _froms.length; i++) { _mint(_tos[i], _amounts[i]); emit BridgedTo(_froms[i], _tos[i], _amounts[i], _nonce); _nonce++; } return true; } function setPaused(bool _paused) public onlyOwner returns (bool) { paused = _paused; } function setTransferPaused(bool _paused) public onlyOwner returns (bool) { transferPaused = _paused; } function bridgeBack(uint256 _amount, string memory _to) public returns (bool) { if (paused) { return false; } require(_amount <= balanceOf(_msgSender()), "Not enough balance"); // require greater than 0.1251 wTAO for gas purposes. require( _amount > BITTENSOR_FEE, "Does not meet minimum amount for gas (0.125000144 wTAO)" ); _burn(msg.sender, _amount); _nonce++; // cumulative_bridged_back = cumulative_bridged_back.add(_amount); emit BridgedBack(_msgSender(), _amount, _to, _nonce); return true; } function deployer() public view returns (address) { return owner(); } // reclaim stuck sent tokens function reclaimToken(address _token) public onlyOwner { ERC20 token = ERC20(_token); uint256 balance = token.balanceOf(address(this)); token.transfer(owner(), balance); payable(owner()).transfer(address(this).balance); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol) pragma solidity ^0.8.20; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuardUpgradeable is Initializable { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant NOT_ENTERED = 1; uint256 private constant ENTERED = 2; /// @custom:storage-location erc7201:openzeppelin.storage.ReentrancyGuard struct ReentrancyGuardStorage { uint256 _status; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant ReentrancyGuardStorageLocation = 0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00; function _getReentrancyGuardStorage() private pure returns (ReentrancyGuardStorage storage $) { assembly { $.slot := ReentrancyGuardStorageLocation } } /** * @dev Unauthorized reentrant call. */ error ReentrancyGuardReentrantCall(); function __ReentrancyGuard_init() internal onlyInitializing { __ReentrancyGuard_init_unchained(); } function __ReentrancyGuard_init_unchained() internal onlyInitializing { ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage(); $._status = NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { _nonReentrantBefore(); _; _nonReentrantAfter(); } function _nonReentrantBefore() private { ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage(); // On the first call to nonReentrant, _status will be NOT_ENTERED if ($._status == ENTERED) { revert ReentrancyGuardReentrantCall(); } // Any calls to nonReentrant after this point will fail $._status = ENTERED; } function _nonReentrantAfter() private { ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage(); // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) $._status = NOT_ENTERED; } /** * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a * `nonReentrant` function in the call stack. */ function _reentrancyGuardEntered() internal view returns (bool) { ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage(); return $._status == ENTERED; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol) pragma solidity ^0.8.20; import {IAccessControl} from "@openzeppelin/contracts/access/IAccessControl.sol"; import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol"; import {ERC165Upgradeable} from "../utils/introspection/ERC165Upgradeable.sol"; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Contract module that allows children to implement role-based access * control mechanisms. This is a lightweight version that doesn't allow enumerating role * members except through off-chain means by accessing the contract event logs. Some * applications may benefit from on-chain enumerability, for those cases see * {AccessControlEnumerable}. * * Roles are referred to by their `bytes32` identifier. These should be exposed * in the external API and be unique. The best way to achieve this is by * using `public constant` hash digests: * * ```solidity * bytes32 public constant MY_ROLE = keccak256("MY_ROLE"); * ``` * * Roles can be used to represent a set of permissions. To restrict access to a * function call, use {hasRole}: * * ```solidity * function foo() public { * require(hasRole(MY_ROLE, msg.sender)); * ... * } * ``` * * Roles can be granted and revoked dynamically via the {grantRole} and * {revokeRole} functions. Each role has an associated admin role, and only * accounts that have a role's admin role can call {grantRole} and {revokeRole}. * * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means * that only accounts with this role will be able to grant or revoke other * roles. More complex role relationships can be created by using * {_setRoleAdmin}. * * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to * grant and revoke this role. Extra precautions should be taken to secure * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules} * to enforce additional security measures for this role. */ abstract contract AccessControlUpgradeable is Initializable, ContextUpgradeable, IAccessControl, ERC165Upgradeable { struct RoleData { mapping(address account => bool) hasRole; bytes32 adminRole; } bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00; /// @custom:storage-location erc7201:openzeppelin.storage.AccessControl struct AccessControlStorage { mapping(bytes32 role => RoleData) _roles; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.AccessControl")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant AccessControlStorageLocation = 0x02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800; function _getAccessControlStorage() private pure returns (AccessControlStorage storage $) { assembly { $.slot := AccessControlStorageLocation } } /** * @dev Modifier that checks that an account has a specific role. Reverts * with an {AccessControlUnauthorizedAccount} error including the required role. */ modifier onlyRole(bytes32 role) { _checkRole(role); _; } function __AccessControl_init() internal onlyInitializing { } function __AccessControl_init_unchained() internal onlyInitializing { } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId); } /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) public view virtual returns (bool) { AccessControlStorage storage $ = _getAccessControlStorage(); return $._roles[role].hasRole[account]; } /** * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()` * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier. */ function _checkRole(bytes32 role) internal view virtual { _checkRole(role, _msgSender()); } /** * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account` * is missing `role`. */ function _checkRole(bytes32 role, address account) internal view virtual { if (!hasRole(role, account)) { revert AccessControlUnauthorizedAccount(account, role); } } /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) { AccessControlStorage storage $ = _getAccessControlStorage(); return $._roles[role].adminRole; } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. * * May emit a {RoleGranted} event. */ function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) { _grantRole(role, account); } /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. * * May emit a {RoleRevoked} event. */ function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) { _revokeRole(role, account); } /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been revoked `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `callerConfirmation`. * * May emit a {RoleRevoked} event. */ function renounceRole(bytes32 role, address callerConfirmation) public virtual { if (callerConfirmation != _msgSender()) { revert AccessControlBadConfirmation(); } _revokeRole(role, callerConfirmation); } /** * @dev Sets `adminRole` as ``role``'s admin role. * * Emits a {RoleAdminChanged} event. */ function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual { AccessControlStorage storage $ = _getAccessControlStorage(); bytes32 previousAdminRole = getRoleAdmin(role); $._roles[role].adminRole = adminRole; emit RoleAdminChanged(role, previousAdminRole, adminRole); } /** * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted. * * Internal function without access restriction. * * May emit a {RoleGranted} event. */ function _grantRole(bytes32 role, address account) internal virtual returns (bool) { AccessControlStorage storage $ = _getAccessControlStorage(); if (!hasRole(role, account)) { $._roles[role].hasRole[account] = true; emit RoleGranted(role, account, _msgSender()); return true; } else { return false; } } /** * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked. * * Internal function without access restriction. * * May emit a {RoleRevoked} event. */ function _revokeRole(bytes32 role, address account) internal virtual returns (bool) { AccessControlStorage storage $ = _getAccessControlStorage(); if (hasRole(role, account)) { $._roles[role].hasRole[account] = false; emit RoleRevoked(role, account, _msgSender()); return true; } else { return false; } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.20; import {IERC20} from "../IERC20.sol"; import {IERC20Permit} from "../extensions/IERC20Permit.sol"; import {Address} from "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; /** * @dev An operation with an ERC20 token failed. */ error SafeERC20FailedOperation(address token); /** * @dev Indicates a failed `decreaseAllowance` request. */ error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease); /** * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value))); } /** * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful. */ function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value))); } /** * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 oldAllowance = token.allowance(address(this), spender); forceApprove(token, spender, oldAllowance + value); } /** * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no * value, non-reverting calls are assumed to be successful. */ function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal { unchecked { uint256 currentAllowance = token.allowance(address(this), spender); if (currentAllowance < requestedDecrease) { revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease); } forceApprove(token, spender, currentAllowance - requestedDecrease); } } /** * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval * to be set to zero before setting it to a non-zero value, such as USDT. */ function forceApprove(IERC20 token, address spender, uint256 value) internal { bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value)); if (!_callOptionalReturnBool(token, approvalCall)) { _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0))); _callOptionalReturn(token, approvalCall); } } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data); if (returndata.length != 0 && !abi.decode(returndata, (bool))) { revert SafeERC20FailedOperation(address(token)); } } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). * * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead. */ function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false // and not revert is the subcall reverts. (bool success, bytes memory returndata) = address(token).call(data); return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0; } }
// 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/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) (utils/Context.sol) pragma solidity ^0.8.20; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract ContextUpgradeable is Initializable { function __Context_init() internal onlyInitializing { } function __Context_init_unchained() internal onlyInitializing { } function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
// 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.0) (access/Ownable.sol) pragma solidity ^0.8.20; import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol"; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * 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 OwnableUpgradeable is Initializable, ContextUpgradeable { /// @custom:storage-location erc7201:openzeppelin.storage.Ownable struct OwnableStorage { address _owner; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Ownable")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant OwnableStorageLocation = 0x9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300; function _getOwnableStorage() private pure returns (OwnableStorage storage $) { assembly { $.slot := OwnableStorageLocation } } /** * @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. */ function __Ownable_init(address initialOwner) internal onlyInitializing { __Ownable_init_unchained(initialOwner); } function __Ownable_init_unchained(address initialOwner) internal onlyInitializing { 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) { OwnableStorage storage $ = _getOwnableStorage(); 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 { OwnableStorage storage $ = _getOwnableStorage(); address oldOwner = $._owner; $._owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// 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) (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) (access/AccessControl.sol) pragma solidity ^0.8.20; import {IAccessControl} from "./IAccessControl.sol"; import {Context} from "../utils/Context.sol"; import {ERC165} from "../utils/introspection/ERC165.sol"; /** * @dev Contract module that allows children to implement role-based access * control mechanisms. This is a lightweight version that doesn't allow enumerating role * members except through off-chain means by accessing the contract event logs. Some * applications may benefit from on-chain enumerability, for those cases see * {AccessControlEnumerable}. * * Roles are referred to by their `bytes32` identifier. These should be exposed * in the external API and be unique. The best way to achieve this is by * using `public constant` hash digests: * * ```solidity * bytes32 public constant MY_ROLE = keccak256("MY_ROLE"); * ``` * * Roles can be used to represent a set of permissions. To restrict access to a * function call, use {hasRole}: * * ```solidity * function foo() public { * require(hasRole(MY_ROLE, msg.sender)); * ... * } * ``` * * Roles can be granted and revoked dynamically via the {grantRole} and * {revokeRole} functions. Each role has an associated admin role, and only * accounts that have a role's admin role can call {grantRole} and {revokeRole}. * * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means * that only accounts with this role will be able to grant or revoke other * roles. More complex role relationships can be created by using * {_setRoleAdmin}. * * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to * grant and revoke this role. Extra precautions should be taken to secure * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules} * to enforce additional security measures for this role. */ abstract contract AccessControl is Context, IAccessControl, ERC165 { struct RoleData { mapping(address account => bool) hasRole; bytes32 adminRole; } mapping(bytes32 role => RoleData) private _roles; bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00; /** * @dev Modifier that checks that an account has a specific role. Reverts * with an {AccessControlUnauthorizedAccount} error including the required role. */ modifier onlyRole(bytes32 role) { _checkRole(role); _; } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId); } /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) public view virtual returns (bool) { return _roles[role].hasRole[account]; } /** * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()` * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier. */ function _checkRole(bytes32 role) internal view virtual { _checkRole(role, _msgSender()); } /** * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account` * is missing `role`. */ function _checkRole(bytes32 role, address account) internal view virtual { if (!hasRole(role, account)) { revert AccessControlUnauthorizedAccount(account, role); } } /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) { return _roles[role].adminRole; } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. * * May emit a {RoleGranted} event. */ function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) { _grantRole(role, account); } /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. * * May emit a {RoleRevoked} event. */ function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) { _revokeRole(role, account); } /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been revoked `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `callerConfirmation`. * * May emit a {RoleRevoked} event. */ function renounceRole(bytes32 role, address callerConfirmation) public virtual { if (callerConfirmation != _msgSender()) { revert AccessControlBadConfirmation(); } _revokeRole(role, callerConfirmation); } /** * @dev Sets `adminRole` as ``role``'s admin role. * * Emits a {RoleAdminChanged} event. */ function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual { bytes32 previousAdminRole = getRoleAdmin(role); _roles[role].adminRole = adminRole; emit RoleAdminChanged(role, previousAdminRole, adminRole); } /** * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted. * * Internal function without access restriction. * * May emit a {RoleGranted} event. */ function _grantRole(bytes32 role, address account) internal virtual returns (bool) { if (!hasRole(role, account)) { _roles[role].hasRole[account] = true; emit RoleGranted(role, account, _msgSender()); return true; } else { return false; } } /** * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked. * * Internal function without access restriction. * * May emit a {RoleRevoked} event. */ function _revokeRole(bytes32 role, address account) internal virtual returns (bool) { if (hasRole(role, account)) { _roles[role].hasRole[account] = false; emit RoleRevoked(role, account, _msgSender()); return true; } else { return false; } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol) pragma solidity ^0.8.20; /** * @dev External interface of AccessControl declared to support ERC165 detection. */ interface IAccessControl { /** * @dev The `account` is missing a role. */ error AccessControlUnauthorizedAccount(address account, bytes32 neededRole); /** * @dev The caller of a function is not the expected one. * * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}. */ error AccessControlBadConfirmation(); /** * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` * * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite * {RoleAdminChanged} not being emitted signaling this. */ event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); /** * @dev Emitted when `account` is granted `role`. * * `sender` is the account that originated the contract call, an admin role * bearer except when using {AccessControl-_setupRole}. */ event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Emitted when `account` is revoked `role`. * * `sender` is the account that originated the contract call: * - if using `revokeRole`, it is the admin role bearer * - if using `renounceRole`, it is the role bearer (i.e. `account`) */ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) external view returns (bool); /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {AccessControl-_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) external view returns (bytes32); /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function grantRole(bytes32 role, address account) external; /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function revokeRole(bytes32 role, address account) external; /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been granted `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `callerConfirmation`. */ function renounceRole(bytes32 role, address callerConfirmation) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol) pragma solidity ^0.8.20; import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; import {Initializable} from "../../proxy/utils/Initializable.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check * for the additional interface id that will be supported. For example: * * ```solidity * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); * } * ``` */ abstract contract ERC165Upgradeable is Initializable, IERC165 { function __ERC165_init() internal onlyInitializing { } function __ERC165_init_unchained() internal onlyInitializing { } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) { return interfaceId == type(IERC165).interfaceId; } }
// 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) (utils/Address.sol) pragma solidity ^0.8.20; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev The ETH balance of the account is not enough to perform the operation. */ error AddressInsufficientBalance(address account); /** * @dev There's no code at `target` (it is not a contract). */ error AddressEmptyCode(address target); /** * @dev A call to an address target failed. The target may have reverted. */ error FailedInnerCall(); /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { if (address(this).balance < amount) { revert AddressInsufficientBalance(address(this)); } (bool success, ) = recipient.call{value: amount}(""); if (!success) { revert FailedInnerCall(); } } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason or custom error, it is bubbled * up by this function (like regular Solidity function calls). However, if * the call reverted with no returned reason, this function reverts with a * {FailedInnerCall} error. * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { if (address(this).balance < value) { revert AddressInsufficientBalance(address(this)); } (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an * unsuccessful call. */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata ) internal view returns (bytes memory) { if (!success) { _revert(returndata); } else { // only check if target is a contract if the call was successful and the return data is empty // otherwise we already know that it was a contract if (returndata.length == 0 && target.code.length == 0) { revert AddressEmptyCode(target); } return returndata; } } /** * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the * revert reason or with a default {FailedInnerCall} error. */ function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) { if (!success) { _revert(returndata); } else { return returndata; } } /** * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}. */ function _revert(bytes memory returndata) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert FailedInnerCall(); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (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; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol) pragma solidity ^0.8.20; import {IERC165} from "./IERC165.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check * for the additional interface id that will be supported. For example: * * ```solidity * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); * } * ``` */ abstract contract ERC165 is IERC165 { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) { return interfaceId == type(IERC165).interfaceId; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
{ "remappings": [ "forge-std/=lib/forge-std/src/", "openzeppelin-contracts/=lib/openzeppelin-contracts/contracts/", "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/", "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/", "@ensdomains/=node_modules/@ensdomains/", "@layerzerolabs/=node_modules/@layerzerolabs/", "@openzeppelin-3/=node_modules/@openzeppelin-3/", "@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/", "ds-test/=lib/forge-std/lib/ds-test/src/", "erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/", "erc721a/=node_modules/erc721a/", "eth-gas-reporter/=node_modules/eth-gas-reporter/", "hardhat-deploy/=node_modules/hardhat-deploy/", "hardhat/=node_modules/hardhat/" ], "optimizer": { "enabled": true, "runs": 200 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "paris", "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"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":"FailedInnerCall","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"idx","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"approvedTimestamp","type":"uint256"}],"name":"AdminUnstakeApproved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"paused","type":"bool"}],"name":"ContractPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"tokenAddress","type":"address"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ERC20TokenPulled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newLowerBound","type":"uint256"}],"name":"LowerBoundUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"NativeTokenPulled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","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":"uint256","name":"bridgingFee","type":"uint256"}],"name":"UpdateBridgeFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newRate","type":"uint256"}],"name":"UpdateExchangeRate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"maxDepositPerRequest","type":"uint256"}],"name":"UpdateMaxDepositPerRequest","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newMaxSupply","type":"uint256"}],"name":"UpdateMaxSupply","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"maxUnstakeRequests","type":"uint256"}],"name":"UpdateMaxUnstakeRequest","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"minStakingAmt","type":"uint256"}],"name":"UpdateMinStakingAmt","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"newNativeWalletReceiver","type":"string"}],"name":"UpdateNativeFinneyReceiver","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newProtocolVault","type":"address"}],"name":"UpdateProtocolVault","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"serviceFee","type":"uint256"}],"name":"UpdateServiceFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"stakingFee","type":"uint256"}],"name":"UpdateStakingFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newUnstakingFee","type":"uint256"}],"name":"UpdateUnstakingFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newWTAO","type":"address"}],"name":"UpdateWTao","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"withdrawalManager","type":"address"}],"name":"UpdateWithdrawalManager","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newUpperBound","type":"uint256"}],"name":"UpperBoundUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"stakeTimestamp","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"inTaoAmt","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"wstAmount","type":"uint256"}],"name":"UserStake","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"idx","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"unstakeTimestamp","type":"uint256"}],"name":"UserUnstake","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"idx","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"requestTimestamp","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"wstAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"outTaoAmt","type":"uint256"},{"indexed":false,"internalType":"address","name":"wrappedToken","type":"address"}],"name":"UserUnstakeRequested","type":"event"},{"inputs":[],"name":"APPROVE_WITHDRAWAL_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EXCHANGE_UPDATE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MANAGE_STAKING_CONFIG_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PAUSE_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TOKEN_SAFE_PULL_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"requestIndex","type":"uint256"}],"internalType":"struct PlxTAO.UserRequest[]","name":"requests","type":"tuple[]"}],"name":"approveMultipleUnstakes","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"batchTAOAmt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"batchTransferBridgeBack","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"bridgingFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"wtaoAmount","type":"uint256"}],"name":"calculateAmtAfterFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"exchangeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getUnstakeRequestByUser","outputs":[{"components":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"taoAmt","type":"uint256"},{"internalType":"bool","name":"isReadyForUnstake","type":"bool"},{"internalType":"address","name":"wrappedToken","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"}],"internalType":"struct PlxTAO.UnstakeRequest[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"wstTaoAmount","type":"uint256"}],"name":"getWTAOByWstTAO","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"wstTaoAmount","type":"uint256"}],"name":"getWTAOByWstTAOAfterFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"wtaoAmount","type":"uint256"}],"name":"getWstTAObyWTAO","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"initialOwner","type":"address"},{"internalType":"uint256","name":"initialSupply","type":"uint256"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lowerExchangeRateBound","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxDepositPerRequest","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxTaoForWrap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxUnstakeRequests","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minStakingAmt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nativeWalletReceiver","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolVault","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"pullNativeToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"wstTAOAmt","type":"uint256"}],"name":"requestUnstake","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"safePullERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"serviceFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_bridgingFee","type":"uint256"}],"name":"setBridgingFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newLowerBound","type":"uint256"}],"name":"setLowerExchangeRateBound","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxDepositPerRequest","type":"uint256"}],"name":"setMaxDepositPerRequest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxSupply","type":"uint256"}],"name":"setMaxSupply","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxUnstakeRequests","type":"uint256"}],"name":"setMaxUnstakeRequest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_minStakingAmt","type":"uint256"}],"name":"setMinStakingAmt","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_nativeWalletReceiver","type":"string"}],"name":"setNativeTokenReceiver","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_isPaused","type":"bool"}],"name":"setPaused","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_protocolVault","type":"address"}],"name":"setProtocolVault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_serviceFee","type":"uint256"}],"name":"setServiceFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_stakingFee","type":"uint256"}],"name":"setStakingFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_unstakingFee","type":"uint256"}],"name":"setUnstakingFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newUpperBound","type":"uint256"}],"name":"setUpperExchangeRateBound","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wTAO","type":"address"}],"name":"setWTAO","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_withdrawalManager","type":"address"}],"name":"setWithdrawalManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stakingFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","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":[{"internalType":"uint256","name":"requestIndex","type":"uint256"}],"name":"unstake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"unstakeRequests","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"taoAmt","type":"uint256"},{"internalType":"bool","name":"isReadyForUnstake","type":"bool"},{"internalType":"address","name":"wrappedToken","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unstakingFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"newRate","type":"uint256"}],"name":"updateExchangeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"upperExchangeRateBound","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdrawalManager","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"wtaoAmount","type":"uint256"}],"name":"wrap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"wrappedToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
60806040523480156200001157600080fd5b506200001c62000022565b620000d6565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000900460ff1615620000735760405163f92ee8a960e01b815260040160405180910390fd5b80546001600160401b0390811614620000d35780546001600160401b0319166001600160401b0390811782556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50565b6153a380620000e66000396000f3fe6080604052600436106104315760003560e01c80636f8b44b011610229578063a9059cbb1161012e578063d8990b66116100b6578063ef434e1c1161007a578063ef434e1c14610cc4578063eff9884314610cda578063f2fde38b14610cf0578063fb8363b614610d10578063fc72ed5b14610d3d57600080fd5b8063d8990b6614610c18578063dd62ed3e14610c3a578063e30c397814610c5a578063e6c8a5f314610c6f578063ea598cb014610ca457600080fd5b8063cc23e3a2116100fd578063cc23e3a214610b82578063cc4eedc914610ba2578063cd6dc68714610bc2578063d547741f14610be2578063d5abeb0114610c0257600080fd5b8063a9059cbb14610b12578063b187bd2614610b32578063b9e205ae14610b4c578063be2b9cd514610b6c57600080fd5b806389067c5e116101b157806395d89b411161018057806395d89b4114610a92578063996c6cc314610aa7578063a1e8028014610ac7578063a217fddf14610ae7578063a7602c7e14610afc57600080fd5b806389067c5e14610a315780638abdf5aa14610a475780638da5cb5b14610a5d57806391d1485414610a7257600080fd5b806379ba5097116101f857806379ba5097146109a75780637b9fe087146109bc5780637e203c8b146109dc578063829c1c57146109f157806382fe535a14610a1157600080fd5b80636f8b44b01461093257806370a0823114610952578063715018a61461097257806372a1f67d1461098757600080fd5b8063313ce5671161033a5780634772daef116102c25780635cdf76f8116102865780635cdf76f8146108645780635cf4cde01461088457806366442a061461089a57806368cd79b3146108f05780636f6c35291461091057600080fd5b80634772daef146107b65780634e44e82a146107d65780635148e961146107f657806358e3b5ec146108165780635a9249e61461082c57600080fd5b80633ba0b9a9116103095780633ba0b9a9146106f8578063410dbf7e1461070e578063420fa47e1461072e5780634310d1281461076257806344be04041461079657600080fd5b8063313ce5671461066857806336568abe14610684578063389ed267146106a457806339c5dec7146106d857600080fd5b806321c30855116103bd5780632680f5cd1161038c5780632680f5cd146105c8578063295a3af0146105e85780632d1ede9a146106085780632e17de78146106285780632f2ff15d1461064857600080fd5b806321c3085514610560578063230957211461057557806323b872dd14610588578063248a9ca3146105a857600080fd5b80630fbdc677116104045780630fbdc677146104d057806316c38b3c146104f25780631723be121461051257806318160ddd1461052857806320ba56981461054a57600080fd5b806301ffc9a71461043657806306fdde031461046b578063095ea7b31461048d5780630e238894146104ad575b600080fd5b34801561044257600080fd5b50610456610451366004614aab565b610d5d565b60405190151581526020015b60405180910390f35b34801561047757600080fd5b50610480610d94565b6040516104629190614af9565b34801561049957600080fd5b506104566104a8366004614b48565b610e57565b3480156104b957600080fd5b506104c2610e6f565b604051908152602001610462565b3480156104dc57600080fd5b506104f06104eb366004614b72565b610f1d565b005b3480156104fe57600080fd5b506104f061050d366004614b99565b610ff7565b34801561051e57600080fd5b506104c2600f5481565b34801561053457600080fd5b506000805160206152a6833981519152546104c2565b34801561055657600080fd5b506104c260015481565b34801561056c57600080fd5b506104f06110b4565b6104f0610583366004614b72565b61130b565b34801561059457600080fd5b506104566105a3366004614bb6565b611868565b3480156105b457600080fd5b506104c26105c3366004614b72565b61188e565b3480156105d457600080fd5b506104f06105e3366004614b72565b6118b0565b3480156105f457600080fd5b506104c2610603366004614b72565b6119ec565b34801561061457600080fd5b506104f0610623366004614bb6565b611a0c565b34801561063457600080fd5b506104f0610643366004614b72565b611c4d565b34801561065457600080fd5b506104f0610663366004614bf2565b611eaf565b34801561067457600080fd5b5060405160098152602001610462565b34801561069057600080fd5b506104f061069f366004614bf2565b611ed1565b3480156106b057600080fd5b506104c27f139c2898040ef16910dc9f44dc697df79363da767d8bc92f2e310312b816e46d81565b3480156106e457600080fd5b506104f06106f3366004614c1e565b611f09565b34801561070457600080fd5b506104c260005481565b34801561071a57600080fd5b506104f0610729366004614b72565b611fe1565b34801561073a57600080fd5b506104c27f9e3114703ec4a93cd6bc7e2610274229541e8ba5acacf7825f26bce4fae601e081565b34801561076e57600080fd5b506104c27f7e21c1f853a961caf8adc0c26c941d090de97558d402e0fe1d0eea44495dee7d81565b3480156107a257600080fd5b506104f06107b1366004614b72565b6120ae565b3480156107c257600080fd5b506104f06107d1366004614c4f565b61217b565b3480156107e257600080fd5b506104c26107f1366004614b72565b6121f4565b34801561080257600080fd5b506104f0610811366004614c1e565b61220d565b34801561082257600080fd5b506104c2600e5481565b34801561083857600080fd5b5060105461084c906001600160a01b031681565b6040516001600160a01b039091168152602001610462565b34801561087057600080fd5b506104f061087f366004614b72565b6123db565b34801561089057600080fd5b506104c260045481565b3480156108a657600080fd5b506108ba6108b5366004614b48565b6124ac565b604080519586526020860194909452911515928401929092526001600160a01b039091166060830152608082015260a001610462565b3480156108fc57600080fd5b506104f061090b366004614b72565b612506565b34801561091c57600080fd5b506104c260008051602061534e83398151915281565b34801561093e57600080fd5b506104f061094d366004614b72565b6125da565b34801561095e57600080fd5b506104c261096d366004614c1e565b6126c7565b34801561097e57600080fd5b506104f06126ef565b34801561099357600080fd5b506104c26109a2366004614b72565b6126f7565b3480156109b357600080fd5b506104f061271a565b3480156109c857600080fd5b506104f06109d7366004614b48565b61275f565b3480156109e857600080fd5b50610480612982565b3480156109fd57600080fd5b506104f0610a0c366004614b72565b612a10565b348015610a1d57600080fd5b50600b5461084c906001600160a01b031681565b348015610a3d57600080fd5b506104c260035481565b348015610a5357600080fd5b506104c2600c5481565b348015610a6957600080fd5b5061084c612adf565b348015610a7e57600080fd5b50610456610a8d366004614bf2565b612b14565b348015610a9e57600080fd5b50610480612b4c565b348015610ab357600080fd5b5060055461084c906001600160a01b031681565b348015610ad357600080fd5b506104f0610ae2366004614d00565b612b8b565b348015610af357600080fd5b506104c2600081565b348015610b0857600080fd5b506104c260095481565b348015610b1e57600080fd5b50610456610b2d366004614b48565b613320565b348015610b3e57600080fd5b506007546104569060ff1681565b348015610b5857600080fd5b506104f0610b67366004614b72565b61332e565b348015610b7857600080fd5b506104c260065481565b348015610b8e57600080fd5b506104f0610b9d366004614b72565b6134a7565b348015610bae57600080fd5b506104f0610bbd366004614b72565b613575565b348015610bce57600080fd5b506104f0610bdd366004614b48565b6136a9565b348015610bee57600080fd5b506104f0610bfd366004614bf2565b6138eb565b348015610c0e57600080fd5b506104c2600d5481565b348015610c2457600080fd5b506104c26000805160206152c683398151915281565b348015610c4657600080fd5b506104c2610c55366004614d75565b613907565b348015610c6657600080fd5b5061084c613951565b348015610c7b57600080fd5b50610c8f610c8a366004614b72565b61397a565b60408051928352602083019190915201610462565b348015610cb057600080fd5b506104f0610cbf366004614b72565b613a97565b348015610cd057600080fd5b506104c260115481565b348015610ce657600080fd5b506104c260025481565b348015610cfc57600080fd5b506104f0610d0b366004614c1e565b613e02565b348015610d1c57600080fd5b50610d30610d2b366004614c1e565b613e87565b6040516104629190614d9f565b348015610d4957600080fd5b506104f0610d58366004614c1e565b613f38565b60006001600160e01b03198216637965db0b60e01b1480610d8e57506301ffc9a760e01b6001600160e01b03198316145b92915050565b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace03805460609160008051602061528683398151915291610dd390614e18565b80601f0160208091040260200160405190810160405280929190818152602001828054610dff90614e18565b8015610e4c5780601f10610e2157610100808354040283529160200191610e4c565b820191906000526020600020905b815481529060010190602001808311610e2f57829003601f168201915b505050505091505090565b600033610e6581858561401a565b5060019392505050565b600080610e886000805160206152a68339815191525490565b600d54610e959190614e68565b905080600003610ea757600091505090565b60008054610ebd83670de0b6b3a7640000614e7b565b610ec79190614e92565b90506000806002541115610f0157600254610ee4906103e8614e68565b610ef0836103e8614e7b565b610efa9190614e92565b9050610f04565b50805b600060035482610f149190614eb4565b95945050505050565b610f356000805160206152c683398151915233612b14565b610f5a5760405162461bcd60e51b8152600401610f5190614ec7565b60405180910390fd5b60008111610fbb5760405162461bcd60e51b815260206004820152602860248201527f4d617820756e7374616b65207265717565737473206d757374206265206d6f72604482015267065207468616e20360c41b6064820152608401610f51565b60098190556040518181527f3822db87795eff9f96c9dca0cd5bc25a68f62c46e0bc261b5f67bbd5a598c495906020015b60405180910390a150565b6110217f139c2898040ef16910dc9f44dc697df79363da767d8bc92f2e310312b816e46d33612b14565b61106d5760405162461bcd60e51b815260206004820152601f60248201527f43616c6c657220646f6573206e6f7420686176652050415553455f524f4c45006044820152606401610f51565b6007805460ff191682151590811790915560405160ff909116151581527f752d7e161ff5146f80e3820893176eb40532811e5e20400dfdde57455213706a90602001610fec565b6110de7f7e21c1f853a961caf8adc0c26c941d090de97558d402e0fe1d0eea44495dee7d33612b14565b6110fa5760405162461bcd60e51b8152600401610f5190614f16565b611102614027565b60055460408051808201909152601f81527f77726170706564546f6b656e206164647265737320697320696e76616c696400602082015261114c916001600160a01b03169061405f565b6111df6008805461115c90614e18565b80601f016020809104026020016040519081016040528092919081815260200182805461118890614e18565b80156111d55780601f106111aa576101008083540402835291602001916111d5565b820191906000526020600020905b8154815290600101906020018083116111b857829003601f168201915b5050505050614087565b6000601154116112295760405162461bcd60e51b81526020600482015260156024820152744e6f2054414f20746f20627269646765206261636b60581b6044820152606401610f51565b601180546000918290556005546040516302a3830960e41b81529192916001600160a01b0390911690632a38309090611269908590600890600401614f62565b6020604051808303816000875af1158015611288573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112ac9190614ff5565b9050806112f05760405162461bcd60e51b8152602060048201526012602482015271109c9a5919d948189858dac819985a5b195960721b6044820152606401610f51565b5050611309600160008051602061532e83398151915255565b565b611313614027565b60075460ff16156113365760405162461bcd60e51b8152600401610f5190615012565b60055460408051808201909152601f81527f77726170706564546f6b656e206164647265737320697320696e76616c6964006020820152611380916001600160a01b03169061405f565b600b54604080516060810190915260218082526113af926001600160a01b03169190615265602083013961405f565b600c543410156114015760405162461bcd60e51b815260206004820152601c60248201527f46656520616d6f756e74206973206e6f742073756666696369656e74000000006044820152606401610f51565b600154811161144a5760405162461bcd60e51b8152602060048201526015602482015274125b9d985b1a59081ddcdd151053c8185b5bdd5b9d605a1b6044820152606401610f51565b80611454336126c7565b10156114a25760405162461bcd60e51b815260206004820152601b60248201527f496e73756666696369656e742077737454414f2062616c616e636500000000006044820152606401610f51565b60006114ad826126f7565b336000908152600a6020526040812054919250805b8281101561164157336000908152600a602052604081208054839081106114eb576114eb61503e565b60009182526020909120600490910201549050801561150a575061162f565b6040805160a081018252878152602080820188905260008284018190526005546001600160a01b03166060840152426080840152338152600a9091529190912080548490811061155c5761155c61503e565b6000918252602091829020835160049290920201908155828201516001808301919091556040808501516002840180546060808901516001600160a81b0319909216931515610100600160a81b031916939093176101006001600160a01b039283160217909155608096870151600390950194909455600554825189815242968101969096529185018c905284018a90529091169282019290925290935033907fbacf71ad475b68e36b9cd14cedd8cf7d1f098c65f4c59255d2ade1ceae5782529060a00160405180910390a250611641565b8061163981615054565b9150506114c2565b50806117c757600954336000908152600a6020526040902054106116b15760405162461bcd60e51b815260206004820152602160248201527f4d6178696d756d20756e7374616b6520726571756573747320657863656564656044820152601960fa1b6064820152608401610f51565b336000818152600a60209081526040808320815160a081018352898152808401898152818401868152600580546001600160a01b03908116606086019081524260808701818152885460018181018b55998d529a909b2096516004909a0290960198895593519588019590955590516002870180549351861661010002610100600160a81b0319921515929092166001600160a81b031990941693909317179091559451600390940193909355925490517fbacf71ad475b68e36b9cd14cedd8cf7d1f098c65f4c59255d2ade1ceae578252936117be93889390928b928b9216909485526020850193909352604084019190915260608301526001600160a01b0316608082015260a00190565b60405180910390a25b6117d133856140fe565b600b54600c546040516000926001600160a01b03169180156108fc029184818181858888f1935050505090508061184a5760405162461bcd60e51b815260206004820152601b60248201527f5365727669636520666565207472616e73666572206661696c656400000000006044820152606401610f51565b50505050611865600160008051602061532e83398151915255565b50565b600033611876858285614134565b611881858585614194565b60019150505b9392505050565b600090815260008051602061530e833981519152602052604090206001015490565b6118c860008051602061534e83398151915233612b14565b6118e45760405162461bcd60e51b8152600401610f519061506d565b600081116119405760405162461bcd60e51b815260206004820152602360248201527f4e657720757070657220626f756e64206d757374206265206d6f72652074686160448201526206e20360ec1b6064820152608401610f51565b600e5481116119b75760405162461bcd60e51b815260206004820152603860248201527f4e657720757070657220626f756e64206d75737420626520677265617465722060448201527f7468616e2063757272656e74206c6f77657220626f756e6400000000000000006064820152608401610f51565b600f8190556040518181527f4091f60ba6c7aad614db78570cc879e0c6c771deb4738653a4e5acda9cf3b24f90602001610fec565b60008054611a0283670de0b6b3a7640000614e7b565b610d8e9190614e92565b611a367f9e3114703ec4a93cd6bc7e2610274229541e8ba5acacf7825f26bce4fae601e033612b14565b611a525760405162461bcd60e51b8152600401610f51906150b6565b60075460ff1615611a755760405162461bcd60e51b8152600401610f5190615012565b611a97826040518060600160405280602881526020016152e66028913961405f565b60008111611ae75760405162461bcd60e51b815260206004820152601d60248201527f416d6f756e74206d7573742062652067726561746572207468616e20300000006044820152606401610f51565b6040516370a0823160e01b815230600482015283906000906001600160a01b038316906370a0823190602401602060405180830381865afa158015611b30573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b5491906150ff565b905082811015611ba65760405162461bcd60e51b815260206004820152601d60248201527f4e6f7420656e6f75676820746f6b656e7320696e20636f6e74726163740000006044820152606401610f51565b6005546001600160a01b0390811690861603611be7576011548310611bcf576000601155611be7565b8260116000828254611be19190614e68565b90915550505b611bfb6001600160a01b03831685856141f3565b604080516001600160a01b038088168252861660208201529081018490527fcf343f8f9fbc18b83ca8ace5a1d7f60b823933d6fd1e58458dad0d5f210caae99060600160405180910390a15050505050565b611c55614027565b60075460ff1615611c785760405162461bcd60e51b8152600401610f5190615012565b336000908152600a60205260409020548110611cce5760405162461bcd60e51b8152602060048201526015602482015274092dcecc2d8d2c840e4cae2eacae6e840d2dcc8caf605b1b6044820152606401610f51565b336000908152600a60205260408120805483908110611cef57611cef61503e565b60009182526020918290206040805160a0810182526004939093029091018054808452600182015494840194909452600281015460ff81161515928401929092526101009091046001600160a01b031660608301526003015460808201529150611d9b5760405162461bcd60e51b815260206004820152601860248201527f4e6f20756e7374616b65207265717565737420666f756e6400000000000000006044820152606401610f51565b8060400151611dec5760405162461bcd60e51b815260206004820152601860248201527f556e7374616b65206e6f7420617070726f7665642079657400000000000000006044820152606401610f51565b602080820151336000908152600a9092526040909120805484908110611e1457611e1461503e565b600091825260208220600490910201818155600181018290556002810180546001600160a81b0319169055600301556060820151611e5c906001600160a01b031633836141f3565b6040805184815242602082015233917ff60fc3345e4a664f6362b5b4012f91076079b5510d9d05200c7bb2dfa42527a1910160405180910390a25050611865600160008051602061532e83398151915255565b611eb88261188e565b611ec181614252565b611ecb838361425c565b50505050565b6001600160a01b0381163314611efa5760405163334bd91960e11b815260040160405180910390fd5b611f048282614301565b505050565b611f216000805160206152c683398151915233612b14565b611f3d5760405162461bcd60e51b8152600401610f5190614ec7565b6001600160a01b038116611f935760405162461bcd60e51b815260206004820152601d60248201527f50726f746f636f6c207661756c742063616e6e6f74206265206e756c6c0000006044820152606401610f51565b601080546001600160a01b0319166001600160a01b0383169081179091556040519081527fc951a375519c58813e1685228d8f3e6598feb2b4b983bf8c884d75ec66df4e7690602001610fec565b611ff96000805160206152c683398151915233612b14565b6120155760405162461bcd60e51b8152600401610f5190614ec7565b601481106120795760405162461bcd60e51b815260206004820152602b60248201527f5374616b696e67206665652063616e6e6f74206265206d6f7265207468616e2060448201526a0657175616c20746f2032360ac1b6064820152608401610f51565b60028190556040518181527f14b8f3121162b96e557f0b6b5ec1ca50101edca232c06fe45c5050b18ed7f5c690602001610fec565b6120c66000805160206152c683398151915233612b14565b6120e25760405162461bcd60e51b8152600401610f5190614ec7565b600081116121465760405162461bcd60e51b815260206004820152602b60248201527f4d6178206465706f736974207065722072657175657374206d7573742062652060448201526a06d6f7265207468616e20360ac1b6064820152608401610f51565b60068190556040518181527f8ae9492f6d2f8c6b1e56cf2abf5f30b8678b0411dedc80a9a26bd32ddb9f1df990602001610fec565b6121936000805160206152c683398151915233612b14565b6121af5760405162461bcd60e51b8152600401610f5190614ec7565b6121b881614087565b60086121c48282615166565b507f02d968275bdee5bacef97681e75f14615a23ba3ded42b18c68054038d6d5ba4881604051610fec9190614af9565b6000670de0b6b3a764000060005483611a029190614e7b565b6122256000805160206152c683398151915233612b14565b6122415760405162461bcd60e51b8152600401610f5190614ec7565b612249614027565b612288816040518060400160405280601b81526020017f7754414f20616464726573732063616e6e6f74206265206e756c6c000000000081525061405f565b600580546001600160a01b038381166001600160a01b031983161790925560115491169015612387576122c16008805461115c90614e18565b601180546000918290556040516302a3830960e41b81529091906001600160a01b03841690632a383090906122fd908590600890600401614f62565b6020604051808303816000875af115801561231c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123409190614ff5565b9050806123845760405162461bcd60e51b8152602060048201526012602482015271109c9a5919d948189858dac819985a5b195960721b6044820152606401610f51565b50505b6040516001600160a01b03831681527f1cbc653ef44270e1e1b12585f3b14b78e00ca641597db4aa843efd87ce838b5c9060200160405180910390a150611865600160008051602061532e83398151915255565b6123f36000805160206152c683398151915233612b14565b61240f5760405162461bcd60e51b8152600401610f5190614ec7565b662386f26fc100008111156124775760405162461bcd60e51b815260206004820152602860248201527f53657276696365206665652063616e6e6f74206265206d6f7265207468616e206044820152670605c6062408aa8960c31b6064820152608401610f51565b600c8190556040518181527f8b38756fb556c8c4a497c16769c97c5da0bd2caafd23456b1b1c9ab4206fba5090602001610fec565b600a60205281600052604060002081815481106124c857600080fd5b60009182526020909120600490910201805460018201546002830154600390930154919450925060ff82169161010090046001600160a01b03169085565b61251e6000805160206152c683398151915233612b14565b61253a5760405162461bcd60e51b8152600401610f5190614ec7565b60035481116125a55760405162461bcd60e51b815260206004820152603160248201527f4d696e207374616b696e6720616d6f756e74206d757374206265206d6f7265206044820152707468616e206272696467696e672066656560781b6064820152608401610f51565b60048190556040518181527f61e72f410bf254d0a4e3ae5404b6179ce38ae766eff8f767dc5a122ee4a1653d90602001610fec565b6125f26000805160206152c683398151915233612b14565b61260e5760405162461bcd60e51b8152600401610f5190614ec7565b6000805160206152a68339815191525481116126925760405162461bcd60e51b815260206004820152603860248201527f4d617820737570706c79206d7573742062652067726561746572207468616e2060448201527f7468652063757272656e7420746f74616c20737570706c7900000000000000006064820152608401610f51565b600d8190556040518181527fe493ec45ddd3a76acef0c00e0a4cc1e449100df6158b37ca497ed787681cbb5b90602001610fec565b6001600160a01b03166000908152600080516020615286833981519152602052604090205490565b61130961437d565b600080546001546127089084614e68565b611a0290670de0b6b3a7640000614e7b565b3380612724613951565b6001600160a01b0316146127565760405163118cdaa760e01b81526001600160a01b0382166004820152602401610f51565b611865816143af565b6127897f9e3114703ec4a93cd6bc7e2610274229541e8ba5acacf7825f26bce4fae601e033612b14565b6127a55760405162461bcd60e51b8152600401610f51906150b6565b60075460ff16156127c85760405162461bcd60e51b8152600401610f5190615012565b6127ea826040518060600160405280602881526020016152e66028913961405f565b6000811161283a5760405162461bcd60e51b815260206004820152601d60248201527f416d6f756e74206d7573742062652067726561746572207468616e20300000006044820152606401610f51565b47818110156128975760405162461bcd60e51b8152602060048201526024808201527f4e6f7420656e6f756768206e617469766520746f6b656e7320696e20636f6e746044820152631c9858dd60e21b6064820152608401610f51565b6000836001600160a01b03168360405160006040518083038185875af1925050503d80600081146128e4576040519150601f19603f3d011682016040523d82523d6000602084013e6128e9565b606091505b505090508061293a5760405162461bcd60e51b815260206004820152601c60248201527f4e617469766520746f6b656e207472616e73666572206661696c6564000000006044820152606401610f51565b604080516001600160a01b0386168152602081018590527fbf5083663e042fcc8c207dc7c302c797ab721761e0d1ab346cf343341b67f583910160405180910390a150505050565b6008805461298f90614e18565b80601f01602080910402602001604051908101604052809291908181526020018280546129bb90614e18565b8015612a085780601f106129dd57610100808354040283529160200191612a08565b820191906000526020600020905b8154815290600101906020018083116129eb57829003601f168201915b505050505081565b612a286000805160206152c683398151915233612b14565b612a445760405162461bcd60e51b8152600401610f5190614ec7565b630bebc200811115612aaa5760405162461bcd60e51b815260206004820152602960248201527f556e7374616b696e67206665652063616e6e6f74206265206d6f7265207468616044820152686e20302e322054414f60b81b6064820152608401610f51565b60018190556040518181527f671bd930a19e6b5b8ff84de6230a7b8a922829f8b7581df2e39d50d71f92987490602001610fec565b6000807f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c1993005b546001600160a01b031692915050565b600091825260008051602061530e833981519152602090815260408084206001600160a01b0393909316845291905290205460ff1690565b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace04805460609160008051602061528683398151915291610dd390614e18565b612bb57f7e21c1f853a961caf8adc0c26c941d090de97558d402e0fe1d0eea44495dee7d33612b14565b612bd15760405162461bcd60e51b8152600401610f5190614f16565b612bd9614027565b60075460ff1615612bfc5760405162461bcd60e51b8152600401610f5190615012565b600081612c4b5760405162461bcd60e51b815260206004820152601760248201527f526571756573747320617272617920697320656d7074790000000000000000006044820152606401610f51565b600a600084846000818110612c6257612c6261503e565b612c789260206040909202019081019150614c1e565b6001600160a01b03166001600160a01b031681526020019081526020016000208054905083836000818110612caf57612caf61503e565b9050604002016020013510612d105760405162461bcd60e51b815260206004820152602160248201527f4669727374207265717565737420696e646578206f7574206f6620626f756e646044820152607360f81b6064820152608401610f51565b6000600a600085856000818110612d2957612d2961503e565b612d3f9260206040909202019081019150614c1e565b6001600160a01b03166001600160a01b0316815260200190815260200160002084846000818110612d7257612d7261503e565b9050604002016020013581548110612d8c57612d8c61503e565b600091825260208220600260049092020101546001600160a01b036101009091041691505b838110156130ef5736858583818110612dcc57612dcc61503e565b604002919091019150600a90506000612de86020840184614c1e565b6001600160a01b03168152602080820192909252604001600020549082013510612e4c5760405162461bcd60e51b8152602060048201526015602482015274092dcecc2d8d2c840e4cae2eacae6e840d2dcc8caf605b1b6044820152606401610f51565b6000600a81612e5e6020850185614c1e565b6001600160a01b03166001600160a01b03168152602001908152602001600020826020013581548110612e9357612e9361503e565b90600052602060002090600402016000015411612ee75760405162461bcd60e51b815260206004820152601260248201527114995c5d595cdd081a5cc81a5b9d985b1a5960721b6044820152606401610f51565b600a6000612ef86020840184614c1e565b6001600160a01b03166001600160a01b03168152602001908152602001600020816020013581548110612f2d57612f2d61503e565b600091825260209091206002600490920201015460ff1615612f915760405162461bcd60e51b815260206004820152601b60248201527f5265717565737420697320616c726561647920617070726f76656400000000006044820152606401610f51565b6001600160a01b038316600a6000612fac6020850185614c1e565b6001600160a01b03166001600160a01b03168152602001908152602001600020826020013581548110612fe157612fe161503e565b600091825260209091206004909102016002015461010090046001600160a01b0316146130765760405162461bcd60e51b815260206004820152603960248201527f5772617070656420746f6b656e206973206e6f74207468652073616d6520616360448201527f726f737320616c6c20756e7374616b65207265717565737473000000000000006064820152608401610f51565b600a60006130876020840184614c1e565b6001600160a01b03166001600160a01b031681526020019081526020016000208160200135815481106130bc576130bc61503e565b906000526020600020906004020160010154846130d99190614eb4565b93505080806130e790615054565b915050612db1565b50604051636eb1769f60e11b815233600482015230602482015282906001600160a01b0383169063dd62ed3e90604401602060405180830381865afa15801561313c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061316091906150ff565b10156131ae5760405162461bcd60e51b815260206004820152601c60248201527f496e73756666696369656e7420746f6b656e20616c6c6f77616e6365000000006044820152606401610f51565b60005b8381101561325457368585838181106131cc576131cc61503e565b60400291909101915060019050600a60006131ea6020850185614c1e565b6001600160a01b03166001600160a01b0316815260200190815260200160002082602001358154811061321f5761321f61503e565b60009182526020909120600490910201600201805460ff1916911515919091179055508061324c81615054565b9150506131b1565b5061326a6001600160a01b0382163330856143e7565b60005b8381101561330257368585838181106132885761328861503e565b6040029190910191506132a090506020820182614c1e565b6001600160a01b03167f6989ab5544b7750d8fd06869e7fc1852b2f28bf9d75e9fa272405986fd263a648260200135426040516132e7929190918252602082015260400190565b60405180910390a250806132fa81615054565b91505061326d565b50505061331c600160008051602061532e83398151915255565b5050565b600033610e65818585614194565b61334660008051602061534e83398151915233612b14565b6133625760405162461bcd60e51b8152600401610f519061506d565b600081116133b25760405162461bcd60e51b815260206004820152601c60248201527f4e65772072617465206d757374206265206d6f7265207468616e2030000000006044820152606401610f51565b600e5481101580156133c65750600f548111155b6134125760405162461bcd60e51b815260206004820152601e60248201527f4e65772072617465206d7573742062652077697468696e20626f756e647300006044820152606401610f51565b6000600e5411801561342657506000600f54115b6134725760405162461bcd60e51b815260206004820152601a60248201527f426f756e6473206d757374206265206d6f7265207468616e20300000000000006044820152606401610f51565b60008190556040518181527f4fc1b45960547ee95894b08a284c3c066cf5aca706a7420639c42c3ec2e118a490602001610fec565b6134bf6000805160206152c683398151915233612b14565b6134db5760405162461bcd60e51b8152600401610f5190614ec7565b630bebc2008111156135405760405162461bcd60e51b815260206004820152602860248201527f4272696467696e67206665652063616e6e6f74206265206d6f7265207468616e60448201526720302e322054414f60c01b6064820152608401610f51565b60038190556040518181527f04d485944ec6b81a573c140fc8ea83b6738f1bbb036d17d185027a5c4107cdf990602001610fec565b61358d60008051602061534e83398151915233612b14565b6135a95760405162461bcd60e51b8152600401610f519061506d565b600081116136055760405162461bcd60e51b815260206004820152602360248201527f4e6577206c6f77657220626f756e64206d757374206265206d6f72652074686160448201526206e20360ec1b6064820152608401610f51565b600f5481106136745760405162461bcd60e51b815260206004820152603560248201527f4e6577206c6f77657220626f756e64206d757374206265206c657373207468616044820152741b8818dd5c9c995b9d081d5c1c195c88189bdd5b99605a1b6064820152608401610f51565b600e8190556040518181527ff995fb2f30f70b5dacab19046768ab20d01b477e6a3a0075a2fb2fad3872b77690602001610fec565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff16159067ffffffffffffffff166000811580156136ef5750825b905060008267ffffffffffffffff16600114801561370c5750303b155b90508115801561371a575080155b156137385760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff19166001178555831561376257845460ff60401b1916600160401b1785555b6001600160a01b0387166137af5760405162461bcd60e51b815260206004820152601460248201527313dddb995c8818d85b9b9bdd081899481b9d5b1b60621b6044820152606401610f51565b6000861161380a5760405162461bcd60e51b815260206004820152602260248201527f496e697469616c20737570706c79206d757374206265206d6f7265207468616e604482015261020360f41b6064820152608401610f51565b61385e6040518060400160405280601581526020017454656e736f72706c6578205374616b65642054414f60581b81525060405180604001604052806005815260200164737454414f60d81b815250614420565b61386787614432565b61386f614443565b61387761444b565b61388260008061445b565b61388b876143af565b61389660008861425c565b50600d86905583156138e257845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50505050505050565b6138f48261188e565b6138fd81614252565b611ecb8383614301565b6001600160a01b0391821660009081527f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace016020908152604080832093909416825291909152205490565b6000807f237e158222e3e6968b72b9db0d8043aacf074ad9f650f0d1606b4d82ee432c00612b04565b60008060035483116139e15760405162461bcd60e51b815260206004820152602a60248201527f7754414f20616d6f756e74206d757374206265206d6f7265207468616e206272604482015269696467696e672066656560b01b6064820152608401610f51565b6000600354846139f19190614e68565b90506000806002541115613a1d576103e860025483613a109190614e7b565b613a1a9190614e92565b90505b6000613a298284614e68565b905060008111613a8d5760405162461bcd60e51b815260206004820152602960248201527f5772617020616d6f756e7420616674657220666565206d757374206265206d6f60448201526807265207468616e20360bc1b6064820152608401610f51565b9590945092505050565b613a9f614027565b60075460ff1615613ac25760405162461bcd60e51b8152600401610f5190615012565b806006541015613b145760405162461bcd60e51b815260206004820152601e60248201527f4465706f73697420616d6f756e742065786365656473206d6178696d756d00006044820152606401610f51565b600060088054613b2390614e18565b80601f0160208091040260200160405190810160405280929190818152602001828054613b4f90614e18565b8015613b9c5780601f10613b7157610100808354040283529160200191613b9c565b820191906000526020600020905b815481529060010190602001808311613b7f57829003601f168201915b5050600554939450506001600160a01b039092169150613bbd905082614087565b613bfc816040518060400160405280601f81526020017f77726170706564546f6b656e206164647265737320697320696e76616c69640081525061405f565b6040516370a0823160e01b815233600482015283906001600160a01b038316906370a0823190602401602060405180830381865afa158015613c42573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c6691906150ff565b1015613cb45760405162461bcd60e51b815260206004820152601960248201527f496e73756666696369656e74207754414f2062616c616e6365000000000000006044820152606401610f51565b60105460408051606081019091526022808252613ce3926001600160a01b03169190615243602083013961405f565b6004548311613d405760405162461bcd60e51b8152602060048201526024808201527f446f6573206e6f74206d656574206d696e696d756d207374616b696e6720616d6044820152631bdd5b9d60e21b6064820152608401610f51565b600080613d4c8561397a565b915091506000613d5b836121f4565b9050613d6733826144be565b613d7082614530565b600060035484613d809190614eb4565b9050613d8b8161454f565b8060116000828254613d9d9190614eb4565b9091555050604080514281526020810189905290810183905233907f445b6299c386d845a282565eba224a183ae1062133e1b062b35d93f855fd59bd9060600160405180910390a2505050505050611865600160008051602061532e83398151915255565b613e0a61437d565b7f237e158222e3e6968b72b9db0d8043aacf074ad9f650f0d1606b4d82ee432c0080546001600160a01b0319166001600160a01b0383169081178255613e4e612adf565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a35050565b6001600160a01b0381166000908152600a60209081526040808320805482518185028101850190935280835260609492939192909184015b82821015613f2d5760008481526020908190206040805160a081018252600486029092018054835260018082015484860152600282015460ff81161515938501939093526101009092046001600160a01b031660608401526003015460808301529083529092019101613ebf565b505050509050919050565b613f506000805160206152c683398151915233612b14565b613f6c5760405162461bcd60e51b8152600401610f5190614ec7565b6001600160a01b038116613fcc5760405162461bcd60e51b815260206004820152602160248201527f5769746864726177616c206d616e616765722063616e6e6f74206265206e756c6044820152601b60fa1b6064820152608401610f51565b600b80546001600160a01b0319166001600160a01b0383169081179091556040519081527fd85a538f003fe4c6d5aaff33960bcc7bcf9f994d5a6ddda17b8e8901b57bf7df90602001610fec565b611f048383836001614567565b60008051602061532e83398151915280546001190161405957604051633ee5aeb560e01b815260040160405180910390fd5b60029055565b806001600160a01b038316611f045760405162461bcd60e51b8152600401610f519190614af9565b80516030146118655760405162461bcd60e51b815260206004820152602960248201527f6e617469766557616c6c65745265636569766572206d757374206265206f66206044820152680d8cadccee8d04068760bb1b6064820152608401610f51565b600160008051602061532e83398151915255565b6001600160a01b03821661412857604051634b637e8f60e11b815260006004820152602401610f51565b61331c8260008361464f565b60006141408484613907565b90506000198114611ecb578181101561418557604051637dc7a0d960e11b81526001600160a01b03841660048201526024810182905260448101839052606401610f51565b611ecb84848484036000614567565b6001600160a01b0383166141be57604051634b637e8f60e11b815260006004820152602401610f51565b6001600160a01b0382166141e85760405163ec442f0560e01b815260006004820152602401610f51565b611f0483838361464f565b6040516001600160a01b03838116602483015260448201839052611f0491859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180516001600160e01b03838183161783525050505061478d565b61186581336147f0565b600060008051602061530e8339815191526142778484612b14565b6142f7576000848152602082815260408083206001600160a01b03871684529091529020805460ff191660011790556142ad3390565b6001600160a01b0316836001600160a01b0316857f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a46001915050610d8e565b6000915050610d8e565b600060008051602061530e83398151915261431c8484612b14565b156142f7576000848152602082815260408083206001600160a01b0387168085529252808320805460ff1916905551339287917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a46001915050610d8e565b33614386612adf565b6001600160a01b0316146113095760405163118cdaa760e01b8152336004820152602401610f51565b7f237e158222e3e6968b72b9db0d8043aacf074ad9f650f0d1606b4d82ee432c0080546001600160a01b031916815561331c82614829565b6040516001600160a01b038481166024830152838116604483015260648201839052611ecb9186918216906323b872dd90608401614220565b61442861489a565b61331c82826148e3565b61443a61489a565b61186581614934565b61130961489a565b61445361489a565b611309614966565b60008051602061530e83398151915260006144758461188e565b600085815260208490526040808220600101869055519192508491839187917fbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff9190a450505050565b600d54816144d86000805160206152a68339815191525490565b6144e29190614eb4565b11156145265760405162461bcd60e51b815260206004820152601360248201527213585e081cdd5c1c1b1e48195e18d959591959606a1b6044820152606401610f51565b61331c828261496e565b601054600554611865916001600160a01b0391821691339116846143e7565b600554611865906001600160a01b03163330846143e7565b6000805160206152868339815191526001600160a01b0385166145a05760405163e602df0560e01b815260006004820152602401610f51565b6001600160a01b0384166145ca57604051634a1406b160e11b815260006004820152602401610f51565b6001600160a01b0380861660009081526001830160209081526040808320938816835292905220839055811561464857836001600160a01b0316856001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258560405161463f91815260200190565b60405180910390a35b5050505050565b6000805160206152868339815191526001600160a01b03841661468b57818160020160008282546146809190614eb4565b909155506146fd9050565b6001600160a01b038416600090815260208290526040902054828110156146de5760405163391434e360e21b81526001600160a01b03861660048201526024810182905260448101849052606401610f51565b6001600160a01b03851660009081526020839052604090209083900390555b6001600160a01b03831661471b57600281018054839003905561473a565b6001600160a01b03831660009081526020829052604090208054830190555b826001600160a01b0316846001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161477f91815260200190565b60405180910390a350505050565b60006147a26001600160a01b038416836149a4565b905080516000141580156147c75750808060200190518101906147c59190614ff5565b155b15611f0457604051635274afe760e01b81526001600160a01b0384166004820152602401610f51565b6147fa8282612b14565b61331c5760405163e2517d3f60e01b81526001600160a01b038216600482015260248101839052604401610f51565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930080546001600160a01b031981166001600160a01b03848116918217845560405192169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3505050565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054600160401b900460ff1661130957604051631afcd79f60e31b815260040160405180910390fd5b6148eb61489a565b6000805160206152868339815191527f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace036149258482615166565b5060048101611ecb8382615166565b61493c61489a565b6001600160a01b03811661275657604051631e4fbdf760e01b815260006004820152602401610f51565b6140ea61489a565b6001600160a01b0382166149985760405163ec442f0560e01b815260006004820152602401610f51565b61331c6000838361464f565b60606118878383600084600080856001600160a01b031684866040516149ca9190615226565b60006040518083038185875af1925050503d8060008114614a07576040519150601f19603f3d011682016040523d82523d6000602084013e614a0c565b606091505b5091509150614a1c868383614a26565b9695505050505050565b606082614a3b57614a3682614a82565b611887565b8151158015614a5257506001600160a01b0384163b155b15614a7b57604051639996b31560e01b81526001600160a01b0385166004820152602401610f51565b5080611887565b805115614a925780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b600060208284031215614abd57600080fd5b81356001600160e01b03198116811461188757600080fd5b60005b83811015614af0578181015183820152602001614ad8565b50506000910152565b6020815260008251806020840152614b18816040850160208701614ad5565b601f01601f19169190910160400192915050565b80356001600160a01b0381168114614b4357600080fd5b919050565b60008060408385031215614b5b57600080fd5b614b6483614b2c565b946020939093013593505050565b600060208284031215614b8457600080fd5b5035919050565b801515811461186557600080fd5b600060208284031215614bab57600080fd5b813561188781614b8b565b600080600060608486031215614bcb57600080fd5b614bd484614b2c565b9250614be260208501614b2c565b9150604084013590509250925092565b60008060408385031215614c0557600080fd5b82359150614c1560208401614b2c565b90509250929050565b600060208284031215614c3057600080fd5b61188782614b2c565b634e487b7160e01b600052604160045260246000fd5b600060208284031215614c6157600080fd5b813567ffffffffffffffff80821115614c7957600080fd5b818401915084601f830112614c8d57600080fd5b813581811115614c9f57614c9f614c39565b604051601f8201601f19908116603f01168101908382118183101715614cc757614cc7614c39565b81604052828152876020848701011115614ce057600080fd5b826020860160208301376000928101602001929092525095945050505050565b60008060208385031215614d1357600080fd5b823567ffffffffffffffff80821115614d2b57600080fd5b818501915085601f830112614d3f57600080fd5b813581811115614d4e57600080fd5b8660208260061b8501011115614d6357600080fd5b60209290920196919550909350505050565b60008060408385031215614d8857600080fd5b614d9183614b2c565b9150614c1560208401614b2c565b602080825282518282018190526000919060409081850190868401855b82811015614e0b578151805185528681015187860152858101511515868601526060808201516001600160a01b0316908601526080908101519085015260a09093019290850190600101614dbc565b5091979650505050505050565b600181811c90821680614e2c57607f821691505b602082108103614e4c57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b81810381811115610d8e57610d8e614e52565b8082028115828204841417610d8e57610d8e614e52565b600082614eaf57634e487b7160e01b600052601260045260246000fd5b500490565b80820180821115610d8e57610d8e614e52565b6020808252602f908201527f43616c6c657220646f6573206e6f742068617665204d414e4147455f5354414b60408201526e494e475f5550444154455f524f4c4560881b606082015260800190565b6020808252602c908201527f43616c6c657220646f6573206e6f74206861766520415050524f56455f57495460408201526b4844524157414c5f524f4c4560a01b606082015260800190565b8281526000602060408184015260008454614f7c81614e18565b8060408701526060600180841660008114614f9e5760018114614fb857614fe6565b60ff1985168984015283151560051b890183019550614fe6565b896000528660002060005b85811015614fde5781548b8201860152908301908801614fc3565b8a0184019650505b50939998505050505050505050565b60006020828403121561500757600080fd5b815161188781614b8b565b60208082526012908201527110dbdb9d1c9858dd081a5cc81c185d5cd95960721b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b60006001820161506657615066614e52565b5060010190565b60208082526029908201527f43616c6c657220646f6573206e6f7420686176652045584348414e47455f5550604082015268444154455f524f4c4560b81b606082015260800190565b60208082526029908201527f43616c6c657220646f6573206e6f74206861766520544f4b454e5f534146455f60408201526850554c4c5f524f4c4560b81b606082015260800190565b60006020828403121561511157600080fd5b5051919050565b601f821115611f0457600081815260208120601f850160051c8101602086101561513f5750805b601f850160051c820191505b8181101561515e5782815560010161514b565b505050505050565b815167ffffffffffffffff81111561518057615180614c39565b6151948161518e8454614e18565b84615118565b602080601f8311600181146151c957600084156151b15750858301515b600019600386901b1c1916600185901b17855561515e565b600085815260208120601f198616915b828110156151f8578886015182559484019460019091019084016151d9565b50858210156152165787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60008251615238818460208701614ad5565b919091019291505056fe50726f746f636f6c207661756c7420616464726573732063616e6e6f7420626520307769746864726177616c20616464726573732063616e6e6f74206265206e756c6c52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0052c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace02cdc459158320f1e5dc6a2790e6223a1fae30e193e0b9c0c623cd787aee91ddd3526563697069656e7420616464726573732063616e6e6f74206265206e756c6c206164647265737302dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b6268009b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f008265d83785d3287e7d7481132632b4a43778b737fb1aeb3bb294f9e9984de840a2646970667358221220dd41f63694bb59f6f2256623877b7e29e430813330260281949b7805d80f30eb64736f6c63430008140033
Deployed Bytecode
0x6080604052600436106104315760003560e01c80636f8b44b011610229578063a9059cbb1161012e578063d8990b66116100b6578063ef434e1c1161007a578063ef434e1c14610cc4578063eff9884314610cda578063f2fde38b14610cf0578063fb8363b614610d10578063fc72ed5b14610d3d57600080fd5b8063d8990b6614610c18578063dd62ed3e14610c3a578063e30c397814610c5a578063e6c8a5f314610c6f578063ea598cb014610ca457600080fd5b8063cc23e3a2116100fd578063cc23e3a214610b82578063cc4eedc914610ba2578063cd6dc68714610bc2578063d547741f14610be2578063d5abeb0114610c0257600080fd5b8063a9059cbb14610b12578063b187bd2614610b32578063b9e205ae14610b4c578063be2b9cd514610b6c57600080fd5b806389067c5e116101b157806395d89b411161018057806395d89b4114610a92578063996c6cc314610aa7578063a1e8028014610ac7578063a217fddf14610ae7578063a7602c7e14610afc57600080fd5b806389067c5e14610a315780638abdf5aa14610a475780638da5cb5b14610a5d57806391d1485414610a7257600080fd5b806379ba5097116101f857806379ba5097146109a75780637b9fe087146109bc5780637e203c8b146109dc578063829c1c57146109f157806382fe535a14610a1157600080fd5b80636f8b44b01461093257806370a0823114610952578063715018a61461097257806372a1f67d1461098757600080fd5b8063313ce5671161033a5780634772daef116102c25780635cdf76f8116102865780635cdf76f8146108645780635cf4cde01461088457806366442a061461089a57806368cd79b3146108f05780636f6c35291461091057600080fd5b80634772daef146107b65780634e44e82a146107d65780635148e961146107f657806358e3b5ec146108165780635a9249e61461082c57600080fd5b80633ba0b9a9116103095780633ba0b9a9146106f8578063410dbf7e1461070e578063420fa47e1461072e5780634310d1281461076257806344be04041461079657600080fd5b8063313ce5671461066857806336568abe14610684578063389ed267146106a457806339c5dec7146106d857600080fd5b806321c30855116103bd5780632680f5cd1161038c5780632680f5cd146105c8578063295a3af0146105e85780632d1ede9a146106085780632e17de78146106285780632f2ff15d1461064857600080fd5b806321c3085514610560578063230957211461057557806323b872dd14610588578063248a9ca3146105a857600080fd5b80630fbdc677116104045780630fbdc677146104d057806316c38b3c146104f25780631723be121461051257806318160ddd1461052857806320ba56981461054a57600080fd5b806301ffc9a71461043657806306fdde031461046b578063095ea7b31461048d5780630e238894146104ad575b600080fd5b34801561044257600080fd5b50610456610451366004614aab565b610d5d565b60405190151581526020015b60405180910390f35b34801561047757600080fd5b50610480610d94565b6040516104629190614af9565b34801561049957600080fd5b506104566104a8366004614b48565b610e57565b3480156104b957600080fd5b506104c2610e6f565b604051908152602001610462565b3480156104dc57600080fd5b506104f06104eb366004614b72565b610f1d565b005b3480156104fe57600080fd5b506104f061050d366004614b99565b610ff7565b34801561051e57600080fd5b506104c2600f5481565b34801561053457600080fd5b506000805160206152a6833981519152546104c2565b34801561055657600080fd5b506104c260015481565b34801561056c57600080fd5b506104f06110b4565b6104f0610583366004614b72565b61130b565b34801561059457600080fd5b506104566105a3366004614bb6565b611868565b3480156105b457600080fd5b506104c26105c3366004614b72565b61188e565b3480156105d457600080fd5b506104f06105e3366004614b72565b6118b0565b3480156105f457600080fd5b506104c2610603366004614b72565b6119ec565b34801561061457600080fd5b506104f0610623366004614bb6565b611a0c565b34801561063457600080fd5b506104f0610643366004614b72565b611c4d565b34801561065457600080fd5b506104f0610663366004614bf2565b611eaf565b34801561067457600080fd5b5060405160098152602001610462565b34801561069057600080fd5b506104f061069f366004614bf2565b611ed1565b3480156106b057600080fd5b506104c27f139c2898040ef16910dc9f44dc697df79363da767d8bc92f2e310312b816e46d81565b3480156106e457600080fd5b506104f06106f3366004614c1e565b611f09565b34801561070457600080fd5b506104c260005481565b34801561071a57600080fd5b506104f0610729366004614b72565b611fe1565b34801561073a57600080fd5b506104c27f9e3114703ec4a93cd6bc7e2610274229541e8ba5acacf7825f26bce4fae601e081565b34801561076e57600080fd5b506104c27f7e21c1f853a961caf8adc0c26c941d090de97558d402e0fe1d0eea44495dee7d81565b3480156107a257600080fd5b506104f06107b1366004614b72565b6120ae565b3480156107c257600080fd5b506104f06107d1366004614c4f565b61217b565b3480156107e257600080fd5b506104c26107f1366004614b72565b6121f4565b34801561080257600080fd5b506104f0610811366004614c1e565b61220d565b34801561082257600080fd5b506104c2600e5481565b34801561083857600080fd5b5060105461084c906001600160a01b031681565b6040516001600160a01b039091168152602001610462565b34801561087057600080fd5b506104f061087f366004614b72565b6123db565b34801561089057600080fd5b506104c260045481565b3480156108a657600080fd5b506108ba6108b5366004614b48565b6124ac565b604080519586526020860194909452911515928401929092526001600160a01b039091166060830152608082015260a001610462565b3480156108fc57600080fd5b506104f061090b366004614b72565b612506565b34801561091c57600080fd5b506104c260008051602061534e83398151915281565b34801561093e57600080fd5b506104f061094d366004614b72565b6125da565b34801561095e57600080fd5b506104c261096d366004614c1e565b6126c7565b34801561097e57600080fd5b506104f06126ef565b34801561099357600080fd5b506104c26109a2366004614b72565b6126f7565b3480156109b357600080fd5b506104f061271a565b3480156109c857600080fd5b506104f06109d7366004614b48565b61275f565b3480156109e857600080fd5b50610480612982565b3480156109fd57600080fd5b506104f0610a0c366004614b72565b612a10565b348015610a1d57600080fd5b50600b5461084c906001600160a01b031681565b348015610a3d57600080fd5b506104c260035481565b348015610a5357600080fd5b506104c2600c5481565b348015610a6957600080fd5b5061084c612adf565b348015610a7e57600080fd5b50610456610a8d366004614bf2565b612b14565b348015610a9e57600080fd5b50610480612b4c565b348015610ab357600080fd5b5060055461084c906001600160a01b031681565b348015610ad357600080fd5b506104f0610ae2366004614d00565b612b8b565b348015610af357600080fd5b506104c2600081565b348015610b0857600080fd5b506104c260095481565b348015610b1e57600080fd5b50610456610b2d366004614b48565b613320565b348015610b3e57600080fd5b506007546104569060ff1681565b348015610b5857600080fd5b506104f0610b67366004614b72565b61332e565b348015610b7857600080fd5b506104c260065481565b348015610b8e57600080fd5b506104f0610b9d366004614b72565b6134a7565b348015610bae57600080fd5b506104f0610bbd366004614b72565b613575565b348015610bce57600080fd5b506104f0610bdd366004614b48565b6136a9565b348015610bee57600080fd5b506104f0610bfd366004614bf2565b6138eb565b348015610c0e57600080fd5b506104c2600d5481565b348015610c2457600080fd5b506104c26000805160206152c683398151915281565b348015610c4657600080fd5b506104c2610c55366004614d75565b613907565b348015610c6657600080fd5b5061084c613951565b348015610c7b57600080fd5b50610c8f610c8a366004614b72565b61397a565b60408051928352602083019190915201610462565b348015610cb057600080fd5b506104f0610cbf366004614b72565b613a97565b348015610cd057600080fd5b506104c260115481565b348015610ce657600080fd5b506104c260025481565b348015610cfc57600080fd5b506104f0610d0b366004614c1e565b613e02565b348015610d1c57600080fd5b50610d30610d2b366004614c1e565b613e87565b6040516104629190614d9f565b348015610d4957600080fd5b506104f0610d58366004614c1e565b613f38565b60006001600160e01b03198216637965db0b60e01b1480610d8e57506301ffc9a760e01b6001600160e01b03198316145b92915050565b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace03805460609160008051602061528683398151915291610dd390614e18565b80601f0160208091040260200160405190810160405280929190818152602001828054610dff90614e18565b8015610e4c5780601f10610e2157610100808354040283529160200191610e4c565b820191906000526020600020905b815481529060010190602001808311610e2f57829003601f168201915b505050505091505090565b600033610e6581858561401a565b5060019392505050565b600080610e886000805160206152a68339815191525490565b600d54610e959190614e68565b905080600003610ea757600091505090565b60008054610ebd83670de0b6b3a7640000614e7b565b610ec79190614e92565b90506000806002541115610f0157600254610ee4906103e8614e68565b610ef0836103e8614e7b565b610efa9190614e92565b9050610f04565b50805b600060035482610f149190614eb4565b95945050505050565b610f356000805160206152c683398151915233612b14565b610f5a5760405162461bcd60e51b8152600401610f5190614ec7565b60405180910390fd5b60008111610fbb5760405162461bcd60e51b815260206004820152602860248201527f4d617820756e7374616b65207265717565737473206d757374206265206d6f72604482015267065207468616e20360c41b6064820152608401610f51565b60098190556040518181527f3822db87795eff9f96c9dca0cd5bc25a68f62c46e0bc261b5f67bbd5a598c495906020015b60405180910390a150565b6110217f139c2898040ef16910dc9f44dc697df79363da767d8bc92f2e310312b816e46d33612b14565b61106d5760405162461bcd60e51b815260206004820152601f60248201527f43616c6c657220646f6573206e6f7420686176652050415553455f524f4c45006044820152606401610f51565b6007805460ff191682151590811790915560405160ff909116151581527f752d7e161ff5146f80e3820893176eb40532811e5e20400dfdde57455213706a90602001610fec565b6110de7f7e21c1f853a961caf8adc0c26c941d090de97558d402e0fe1d0eea44495dee7d33612b14565b6110fa5760405162461bcd60e51b8152600401610f5190614f16565b611102614027565b60055460408051808201909152601f81527f77726170706564546f6b656e206164647265737320697320696e76616c696400602082015261114c916001600160a01b03169061405f565b6111df6008805461115c90614e18565b80601f016020809104026020016040519081016040528092919081815260200182805461118890614e18565b80156111d55780601f106111aa576101008083540402835291602001916111d5565b820191906000526020600020905b8154815290600101906020018083116111b857829003601f168201915b5050505050614087565b6000601154116112295760405162461bcd60e51b81526020600482015260156024820152744e6f2054414f20746f20627269646765206261636b60581b6044820152606401610f51565b601180546000918290556005546040516302a3830960e41b81529192916001600160a01b0390911690632a38309090611269908590600890600401614f62565b6020604051808303816000875af1158015611288573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112ac9190614ff5565b9050806112f05760405162461bcd60e51b8152602060048201526012602482015271109c9a5919d948189858dac819985a5b195960721b6044820152606401610f51565b5050611309600160008051602061532e83398151915255565b565b611313614027565b60075460ff16156113365760405162461bcd60e51b8152600401610f5190615012565b60055460408051808201909152601f81527f77726170706564546f6b656e206164647265737320697320696e76616c6964006020820152611380916001600160a01b03169061405f565b600b54604080516060810190915260218082526113af926001600160a01b03169190615265602083013961405f565b600c543410156114015760405162461bcd60e51b815260206004820152601c60248201527f46656520616d6f756e74206973206e6f742073756666696369656e74000000006044820152606401610f51565b600154811161144a5760405162461bcd60e51b8152602060048201526015602482015274125b9d985b1a59081ddcdd151053c8185b5bdd5b9d605a1b6044820152606401610f51565b80611454336126c7565b10156114a25760405162461bcd60e51b815260206004820152601b60248201527f496e73756666696369656e742077737454414f2062616c616e636500000000006044820152606401610f51565b60006114ad826126f7565b336000908152600a6020526040812054919250805b8281101561164157336000908152600a602052604081208054839081106114eb576114eb61503e565b60009182526020909120600490910201549050801561150a575061162f565b6040805160a081018252878152602080820188905260008284018190526005546001600160a01b03166060840152426080840152338152600a9091529190912080548490811061155c5761155c61503e565b6000918252602091829020835160049290920201908155828201516001808301919091556040808501516002840180546060808901516001600160a81b0319909216931515610100600160a81b031916939093176101006001600160a01b039283160217909155608096870151600390950194909455600554825189815242968101969096529185018c905284018a90529091169282019290925290935033907fbacf71ad475b68e36b9cd14cedd8cf7d1f098c65f4c59255d2ade1ceae5782529060a00160405180910390a250611641565b8061163981615054565b9150506114c2565b50806117c757600954336000908152600a6020526040902054106116b15760405162461bcd60e51b815260206004820152602160248201527f4d6178696d756d20756e7374616b6520726571756573747320657863656564656044820152601960fa1b6064820152608401610f51565b336000818152600a60209081526040808320815160a081018352898152808401898152818401868152600580546001600160a01b03908116606086019081524260808701818152885460018181018b55998d529a909b2096516004909a0290960198895593519588019590955590516002870180549351861661010002610100600160a81b0319921515929092166001600160a81b031990941693909317179091559451600390940193909355925490517fbacf71ad475b68e36b9cd14cedd8cf7d1f098c65f4c59255d2ade1ceae578252936117be93889390928b928b9216909485526020850193909352604084019190915260608301526001600160a01b0316608082015260a00190565b60405180910390a25b6117d133856140fe565b600b54600c546040516000926001600160a01b03169180156108fc029184818181858888f1935050505090508061184a5760405162461bcd60e51b815260206004820152601b60248201527f5365727669636520666565207472616e73666572206661696c656400000000006044820152606401610f51565b50505050611865600160008051602061532e83398151915255565b50565b600033611876858285614134565b611881858585614194565b60019150505b9392505050565b600090815260008051602061530e833981519152602052604090206001015490565b6118c860008051602061534e83398151915233612b14565b6118e45760405162461bcd60e51b8152600401610f519061506d565b600081116119405760405162461bcd60e51b815260206004820152602360248201527f4e657720757070657220626f756e64206d757374206265206d6f72652074686160448201526206e20360ec1b6064820152608401610f51565b600e5481116119b75760405162461bcd60e51b815260206004820152603860248201527f4e657720757070657220626f756e64206d75737420626520677265617465722060448201527f7468616e2063757272656e74206c6f77657220626f756e6400000000000000006064820152608401610f51565b600f8190556040518181527f4091f60ba6c7aad614db78570cc879e0c6c771deb4738653a4e5acda9cf3b24f90602001610fec565b60008054611a0283670de0b6b3a7640000614e7b565b610d8e9190614e92565b611a367f9e3114703ec4a93cd6bc7e2610274229541e8ba5acacf7825f26bce4fae601e033612b14565b611a525760405162461bcd60e51b8152600401610f51906150b6565b60075460ff1615611a755760405162461bcd60e51b8152600401610f5190615012565b611a97826040518060600160405280602881526020016152e66028913961405f565b60008111611ae75760405162461bcd60e51b815260206004820152601d60248201527f416d6f756e74206d7573742062652067726561746572207468616e20300000006044820152606401610f51565b6040516370a0823160e01b815230600482015283906000906001600160a01b038316906370a0823190602401602060405180830381865afa158015611b30573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b5491906150ff565b905082811015611ba65760405162461bcd60e51b815260206004820152601d60248201527f4e6f7420656e6f75676820746f6b656e7320696e20636f6e74726163740000006044820152606401610f51565b6005546001600160a01b0390811690861603611be7576011548310611bcf576000601155611be7565b8260116000828254611be19190614e68565b90915550505b611bfb6001600160a01b03831685856141f3565b604080516001600160a01b038088168252861660208201529081018490527fcf343f8f9fbc18b83ca8ace5a1d7f60b823933d6fd1e58458dad0d5f210caae99060600160405180910390a15050505050565b611c55614027565b60075460ff1615611c785760405162461bcd60e51b8152600401610f5190615012565b336000908152600a60205260409020548110611cce5760405162461bcd60e51b8152602060048201526015602482015274092dcecc2d8d2c840e4cae2eacae6e840d2dcc8caf605b1b6044820152606401610f51565b336000908152600a60205260408120805483908110611cef57611cef61503e565b60009182526020918290206040805160a0810182526004939093029091018054808452600182015494840194909452600281015460ff81161515928401929092526101009091046001600160a01b031660608301526003015460808201529150611d9b5760405162461bcd60e51b815260206004820152601860248201527f4e6f20756e7374616b65207265717565737420666f756e6400000000000000006044820152606401610f51565b8060400151611dec5760405162461bcd60e51b815260206004820152601860248201527f556e7374616b65206e6f7420617070726f7665642079657400000000000000006044820152606401610f51565b602080820151336000908152600a9092526040909120805484908110611e1457611e1461503e565b600091825260208220600490910201818155600181018290556002810180546001600160a81b0319169055600301556060820151611e5c906001600160a01b031633836141f3565b6040805184815242602082015233917ff60fc3345e4a664f6362b5b4012f91076079b5510d9d05200c7bb2dfa42527a1910160405180910390a25050611865600160008051602061532e83398151915255565b611eb88261188e565b611ec181614252565b611ecb838361425c565b50505050565b6001600160a01b0381163314611efa5760405163334bd91960e11b815260040160405180910390fd5b611f048282614301565b505050565b611f216000805160206152c683398151915233612b14565b611f3d5760405162461bcd60e51b8152600401610f5190614ec7565b6001600160a01b038116611f935760405162461bcd60e51b815260206004820152601d60248201527f50726f746f636f6c207661756c742063616e6e6f74206265206e756c6c0000006044820152606401610f51565b601080546001600160a01b0319166001600160a01b0383169081179091556040519081527fc951a375519c58813e1685228d8f3e6598feb2b4b983bf8c884d75ec66df4e7690602001610fec565b611ff96000805160206152c683398151915233612b14565b6120155760405162461bcd60e51b8152600401610f5190614ec7565b601481106120795760405162461bcd60e51b815260206004820152602b60248201527f5374616b696e67206665652063616e6e6f74206265206d6f7265207468616e2060448201526a0657175616c20746f2032360ac1b6064820152608401610f51565b60028190556040518181527f14b8f3121162b96e557f0b6b5ec1ca50101edca232c06fe45c5050b18ed7f5c690602001610fec565b6120c66000805160206152c683398151915233612b14565b6120e25760405162461bcd60e51b8152600401610f5190614ec7565b600081116121465760405162461bcd60e51b815260206004820152602b60248201527f4d6178206465706f736974207065722072657175657374206d7573742062652060448201526a06d6f7265207468616e20360ac1b6064820152608401610f51565b60068190556040518181527f8ae9492f6d2f8c6b1e56cf2abf5f30b8678b0411dedc80a9a26bd32ddb9f1df990602001610fec565b6121936000805160206152c683398151915233612b14565b6121af5760405162461bcd60e51b8152600401610f5190614ec7565b6121b881614087565b60086121c48282615166565b507f02d968275bdee5bacef97681e75f14615a23ba3ded42b18c68054038d6d5ba4881604051610fec9190614af9565b6000670de0b6b3a764000060005483611a029190614e7b565b6122256000805160206152c683398151915233612b14565b6122415760405162461bcd60e51b8152600401610f5190614ec7565b612249614027565b612288816040518060400160405280601b81526020017f7754414f20616464726573732063616e6e6f74206265206e756c6c000000000081525061405f565b600580546001600160a01b038381166001600160a01b031983161790925560115491169015612387576122c16008805461115c90614e18565b601180546000918290556040516302a3830960e41b81529091906001600160a01b03841690632a383090906122fd908590600890600401614f62565b6020604051808303816000875af115801561231c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123409190614ff5565b9050806123845760405162461bcd60e51b8152602060048201526012602482015271109c9a5919d948189858dac819985a5b195960721b6044820152606401610f51565b50505b6040516001600160a01b03831681527f1cbc653ef44270e1e1b12585f3b14b78e00ca641597db4aa843efd87ce838b5c9060200160405180910390a150611865600160008051602061532e83398151915255565b6123f36000805160206152c683398151915233612b14565b61240f5760405162461bcd60e51b8152600401610f5190614ec7565b662386f26fc100008111156124775760405162461bcd60e51b815260206004820152602860248201527f53657276696365206665652063616e6e6f74206265206d6f7265207468616e206044820152670605c6062408aa8960c31b6064820152608401610f51565b600c8190556040518181527f8b38756fb556c8c4a497c16769c97c5da0bd2caafd23456b1b1c9ab4206fba5090602001610fec565b600a60205281600052604060002081815481106124c857600080fd5b60009182526020909120600490910201805460018201546002830154600390930154919450925060ff82169161010090046001600160a01b03169085565b61251e6000805160206152c683398151915233612b14565b61253a5760405162461bcd60e51b8152600401610f5190614ec7565b60035481116125a55760405162461bcd60e51b815260206004820152603160248201527f4d696e207374616b696e6720616d6f756e74206d757374206265206d6f7265206044820152707468616e206272696467696e672066656560781b6064820152608401610f51565b60048190556040518181527f61e72f410bf254d0a4e3ae5404b6179ce38ae766eff8f767dc5a122ee4a1653d90602001610fec565b6125f26000805160206152c683398151915233612b14565b61260e5760405162461bcd60e51b8152600401610f5190614ec7565b6000805160206152a68339815191525481116126925760405162461bcd60e51b815260206004820152603860248201527f4d617820737570706c79206d7573742062652067726561746572207468616e2060448201527f7468652063757272656e7420746f74616c20737570706c7900000000000000006064820152608401610f51565b600d8190556040518181527fe493ec45ddd3a76acef0c00e0a4cc1e449100df6158b37ca497ed787681cbb5b90602001610fec565b6001600160a01b03166000908152600080516020615286833981519152602052604090205490565b61130961437d565b600080546001546127089084614e68565b611a0290670de0b6b3a7640000614e7b565b3380612724613951565b6001600160a01b0316146127565760405163118cdaa760e01b81526001600160a01b0382166004820152602401610f51565b611865816143af565b6127897f9e3114703ec4a93cd6bc7e2610274229541e8ba5acacf7825f26bce4fae601e033612b14565b6127a55760405162461bcd60e51b8152600401610f51906150b6565b60075460ff16156127c85760405162461bcd60e51b8152600401610f5190615012565b6127ea826040518060600160405280602881526020016152e66028913961405f565b6000811161283a5760405162461bcd60e51b815260206004820152601d60248201527f416d6f756e74206d7573742062652067726561746572207468616e20300000006044820152606401610f51565b47818110156128975760405162461bcd60e51b8152602060048201526024808201527f4e6f7420656e6f756768206e617469766520746f6b656e7320696e20636f6e746044820152631c9858dd60e21b6064820152608401610f51565b6000836001600160a01b03168360405160006040518083038185875af1925050503d80600081146128e4576040519150601f19603f3d011682016040523d82523d6000602084013e6128e9565b606091505b505090508061293a5760405162461bcd60e51b815260206004820152601c60248201527f4e617469766520746f6b656e207472616e73666572206661696c6564000000006044820152606401610f51565b604080516001600160a01b0386168152602081018590527fbf5083663e042fcc8c207dc7c302c797ab721761e0d1ab346cf343341b67f583910160405180910390a150505050565b6008805461298f90614e18565b80601f01602080910402602001604051908101604052809291908181526020018280546129bb90614e18565b8015612a085780601f106129dd57610100808354040283529160200191612a08565b820191906000526020600020905b8154815290600101906020018083116129eb57829003601f168201915b505050505081565b612a286000805160206152c683398151915233612b14565b612a445760405162461bcd60e51b8152600401610f5190614ec7565b630bebc200811115612aaa5760405162461bcd60e51b815260206004820152602960248201527f556e7374616b696e67206665652063616e6e6f74206265206d6f7265207468616044820152686e20302e322054414f60b81b6064820152608401610f51565b60018190556040518181527f671bd930a19e6b5b8ff84de6230a7b8a922829f8b7581df2e39d50d71f92987490602001610fec565b6000807f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c1993005b546001600160a01b031692915050565b600091825260008051602061530e833981519152602090815260408084206001600160a01b0393909316845291905290205460ff1690565b7f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace04805460609160008051602061528683398151915291610dd390614e18565b612bb57f7e21c1f853a961caf8adc0c26c941d090de97558d402e0fe1d0eea44495dee7d33612b14565b612bd15760405162461bcd60e51b8152600401610f5190614f16565b612bd9614027565b60075460ff1615612bfc5760405162461bcd60e51b8152600401610f5190615012565b600081612c4b5760405162461bcd60e51b815260206004820152601760248201527f526571756573747320617272617920697320656d7074790000000000000000006044820152606401610f51565b600a600084846000818110612c6257612c6261503e565b612c789260206040909202019081019150614c1e565b6001600160a01b03166001600160a01b031681526020019081526020016000208054905083836000818110612caf57612caf61503e565b9050604002016020013510612d105760405162461bcd60e51b815260206004820152602160248201527f4669727374207265717565737420696e646578206f7574206f6620626f756e646044820152607360f81b6064820152608401610f51565b6000600a600085856000818110612d2957612d2961503e565b612d3f9260206040909202019081019150614c1e565b6001600160a01b03166001600160a01b0316815260200190815260200160002084846000818110612d7257612d7261503e565b9050604002016020013581548110612d8c57612d8c61503e565b600091825260208220600260049092020101546001600160a01b036101009091041691505b838110156130ef5736858583818110612dcc57612dcc61503e565b604002919091019150600a90506000612de86020840184614c1e565b6001600160a01b03168152602080820192909252604001600020549082013510612e4c5760405162461bcd60e51b8152602060048201526015602482015274092dcecc2d8d2c840e4cae2eacae6e840d2dcc8caf605b1b6044820152606401610f51565b6000600a81612e5e6020850185614c1e565b6001600160a01b03166001600160a01b03168152602001908152602001600020826020013581548110612e9357612e9361503e565b90600052602060002090600402016000015411612ee75760405162461bcd60e51b815260206004820152601260248201527114995c5d595cdd081a5cc81a5b9d985b1a5960721b6044820152606401610f51565b600a6000612ef86020840184614c1e565b6001600160a01b03166001600160a01b03168152602001908152602001600020816020013581548110612f2d57612f2d61503e565b600091825260209091206002600490920201015460ff1615612f915760405162461bcd60e51b815260206004820152601b60248201527f5265717565737420697320616c726561647920617070726f76656400000000006044820152606401610f51565b6001600160a01b038316600a6000612fac6020850185614c1e565b6001600160a01b03166001600160a01b03168152602001908152602001600020826020013581548110612fe157612fe161503e565b600091825260209091206004909102016002015461010090046001600160a01b0316146130765760405162461bcd60e51b815260206004820152603960248201527f5772617070656420746f6b656e206973206e6f74207468652073616d6520616360448201527f726f737320616c6c20756e7374616b65207265717565737473000000000000006064820152608401610f51565b600a60006130876020840184614c1e565b6001600160a01b03166001600160a01b031681526020019081526020016000208160200135815481106130bc576130bc61503e565b906000526020600020906004020160010154846130d99190614eb4565b93505080806130e790615054565b915050612db1565b50604051636eb1769f60e11b815233600482015230602482015282906001600160a01b0383169063dd62ed3e90604401602060405180830381865afa15801561313c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061316091906150ff565b10156131ae5760405162461bcd60e51b815260206004820152601c60248201527f496e73756666696369656e7420746f6b656e20616c6c6f77616e6365000000006044820152606401610f51565b60005b8381101561325457368585838181106131cc576131cc61503e565b60400291909101915060019050600a60006131ea6020850185614c1e565b6001600160a01b03166001600160a01b0316815260200190815260200160002082602001358154811061321f5761321f61503e565b60009182526020909120600490910201600201805460ff1916911515919091179055508061324c81615054565b9150506131b1565b5061326a6001600160a01b0382163330856143e7565b60005b8381101561330257368585838181106132885761328861503e565b6040029190910191506132a090506020820182614c1e565b6001600160a01b03167f6989ab5544b7750d8fd06869e7fc1852b2f28bf9d75e9fa272405986fd263a648260200135426040516132e7929190918252602082015260400190565b60405180910390a250806132fa81615054565b91505061326d565b50505061331c600160008051602061532e83398151915255565b5050565b600033610e65818585614194565b61334660008051602061534e83398151915233612b14565b6133625760405162461bcd60e51b8152600401610f519061506d565b600081116133b25760405162461bcd60e51b815260206004820152601c60248201527f4e65772072617465206d757374206265206d6f7265207468616e2030000000006044820152606401610f51565b600e5481101580156133c65750600f548111155b6134125760405162461bcd60e51b815260206004820152601e60248201527f4e65772072617465206d7573742062652077697468696e20626f756e647300006044820152606401610f51565b6000600e5411801561342657506000600f54115b6134725760405162461bcd60e51b815260206004820152601a60248201527f426f756e6473206d757374206265206d6f7265207468616e20300000000000006044820152606401610f51565b60008190556040518181527f4fc1b45960547ee95894b08a284c3c066cf5aca706a7420639c42c3ec2e118a490602001610fec565b6134bf6000805160206152c683398151915233612b14565b6134db5760405162461bcd60e51b8152600401610f5190614ec7565b630bebc2008111156135405760405162461bcd60e51b815260206004820152602860248201527f4272696467696e67206665652063616e6e6f74206265206d6f7265207468616e60448201526720302e322054414f60c01b6064820152608401610f51565b60038190556040518181527f04d485944ec6b81a573c140fc8ea83b6738f1bbb036d17d185027a5c4107cdf990602001610fec565b61358d60008051602061534e83398151915233612b14565b6135a95760405162461bcd60e51b8152600401610f519061506d565b600081116136055760405162461bcd60e51b815260206004820152602360248201527f4e6577206c6f77657220626f756e64206d757374206265206d6f72652074686160448201526206e20360ec1b6064820152608401610f51565b600f5481106136745760405162461bcd60e51b815260206004820152603560248201527f4e6577206c6f77657220626f756e64206d757374206265206c657373207468616044820152741b8818dd5c9c995b9d081d5c1c195c88189bdd5b99605a1b6064820152608401610f51565b600e8190556040518181527ff995fb2f30f70b5dacab19046768ab20d01b477e6a3a0075a2fb2fad3872b77690602001610fec565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff16159067ffffffffffffffff166000811580156136ef5750825b905060008267ffffffffffffffff16600114801561370c5750303b155b90508115801561371a575080155b156137385760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff19166001178555831561376257845460ff60401b1916600160401b1785555b6001600160a01b0387166137af5760405162461bcd60e51b815260206004820152601460248201527313dddb995c8818d85b9b9bdd081899481b9d5b1b60621b6044820152606401610f51565b6000861161380a5760405162461bcd60e51b815260206004820152602260248201527f496e697469616c20737570706c79206d757374206265206d6f7265207468616e604482015261020360f41b6064820152608401610f51565b61385e6040518060400160405280601581526020017454656e736f72706c6578205374616b65642054414f60581b81525060405180604001604052806005815260200164737454414f60d81b815250614420565b61386787614432565b61386f614443565b61387761444b565b61388260008061445b565b61388b876143af565b61389660008861425c565b50600d86905583156138e257845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50505050505050565b6138f48261188e565b6138fd81614252565b611ecb8383614301565b6001600160a01b0391821660009081527f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace016020908152604080832093909416825291909152205490565b6000807f237e158222e3e6968b72b9db0d8043aacf074ad9f650f0d1606b4d82ee432c00612b04565b60008060035483116139e15760405162461bcd60e51b815260206004820152602a60248201527f7754414f20616d6f756e74206d757374206265206d6f7265207468616e206272604482015269696467696e672066656560b01b6064820152608401610f51565b6000600354846139f19190614e68565b90506000806002541115613a1d576103e860025483613a109190614e7b565b613a1a9190614e92565b90505b6000613a298284614e68565b905060008111613a8d5760405162461bcd60e51b815260206004820152602960248201527f5772617020616d6f756e7420616674657220666565206d757374206265206d6f60448201526807265207468616e20360bc1b6064820152608401610f51565b9590945092505050565b613a9f614027565b60075460ff1615613ac25760405162461bcd60e51b8152600401610f5190615012565b806006541015613b145760405162461bcd60e51b815260206004820152601e60248201527f4465706f73697420616d6f756e742065786365656473206d6178696d756d00006044820152606401610f51565b600060088054613b2390614e18565b80601f0160208091040260200160405190810160405280929190818152602001828054613b4f90614e18565b8015613b9c5780601f10613b7157610100808354040283529160200191613b9c565b820191906000526020600020905b815481529060010190602001808311613b7f57829003601f168201915b5050600554939450506001600160a01b039092169150613bbd905082614087565b613bfc816040518060400160405280601f81526020017f77726170706564546f6b656e206164647265737320697320696e76616c69640081525061405f565b6040516370a0823160e01b815233600482015283906001600160a01b038316906370a0823190602401602060405180830381865afa158015613c42573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c6691906150ff565b1015613cb45760405162461bcd60e51b815260206004820152601960248201527f496e73756666696369656e74207754414f2062616c616e6365000000000000006044820152606401610f51565b60105460408051606081019091526022808252613ce3926001600160a01b03169190615243602083013961405f565b6004548311613d405760405162461bcd60e51b8152602060048201526024808201527f446f6573206e6f74206d656574206d696e696d756d207374616b696e6720616d6044820152631bdd5b9d60e21b6064820152608401610f51565b600080613d4c8561397a565b915091506000613d5b836121f4565b9050613d6733826144be565b613d7082614530565b600060035484613d809190614eb4565b9050613d8b8161454f565b8060116000828254613d9d9190614eb4565b9091555050604080514281526020810189905290810183905233907f445b6299c386d845a282565eba224a183ae1062133e1b062b35d93f855fd59bd9060600160405180910390a2505050505050611865600160008051602061532e83398151915255565b613e0a61437d565b7f237e158222e3e6968b72b9db0d8043aacf074ad9f650f0d1606b4d82ee432c0080546001600160a01b0319166001600160a01b0383169081178255613e4e612adf565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a35050565b6001600160a01b0381166000908152600a60209081526040808320805482518185028101850190935280835260609492939192909184015b82821015613f2d5760008481526020908190206040805160a081018252600486029092018054835260018082015484860152600282015460ff81161515938501939093526101009092046001600160a01b031660608401526003015460808301529083529092019101613ebf565b505050509050919050565b613f506000805160206152c683398151915233612b14565b613f6c5760405162461bcd60e51b8152600401610f5190614ec7565b6001600160a01b038116613fcc5760405162461bcd60e51b815260206004820152602160248201527f5769746864726177616c206d616e616765722063616e6e6f74206265206e756c6044820152601b60fa1b6064820152608401610f51565b600b80546001600160a01b0319166001600160a01b0383169081179091556040519081527fd85a538f003fe4c6d5aaff33960bcc7bcf9f994d5a6ddda17b8e8901b57bf7df90602001610fec565b611f048383836001614567565b60008051602061532e83398151915280546001190161405957604051633ee5aeb560e01b815260040160405180910390fd5b60029055565b806001600160a01b038316611f045760405162461bcd60e51b8152600401610f519190614af9565b80516030146118655760405162461bcd60e51b815260206004820152602960248201527f6e617469766557616c6c65745265636569766572206d757374206265206f66206044820152680d8cadccee8d04068760bb1b6064820152608401610f51565b600160008051602061532e83398151915255565b6001600160a01b03821661412857604051634b637e8f60e11b815260006004820152602401610f51565b61331c8260008361464f565b60006141408484613907565b90506000198114611ecb578181101561418557604051637dc7a0d960e11b81526001600160a01b03841660048201526024810182905260448101839052606401610f51565b611ecb84848484036000614567565b6001600160a01b0383166141be57604051634b637e8f60e11b815260006004820152602401610f51565b6001600160a01b0382166141e85760405163ec442f0560e01b815260006004820152602401610f51565b611f0483838361464f565b6040516001600160a01b03838116602483015260448201839052611f0491859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180516001600160e01b03838183161783525050505061478d565b61186581336147f0565b600060008051602061530e8339815191526142778484612b14565b6142f7576000848152602082815260408083206001600160a01b03871684529091529020805460ff191660011790556142ad3390565b6001600160a01b0316836001600160a01b0316857f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a46001915050610d8e565b6000915050610d8e565b600060008051602061530e83398151915261431c8484612b14565b156142f7576000848152602082815260408083206001600160a01b0387168085529252808320805460ff1916905551339287917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a46001915050610d8e565b33614386612adf565b6001600160a01b0316146113095760405163118cdaa760e01b8152336004820152602401610f51565b7f237e158222e3e6968b72b9db0d8043aacf074ad9f650f0d1606b4d82ee432c0080546001600160a01b031916815561331c82614829565b6040516001600160a01b038481166024830152838116604483015260648201839052611ecb9186918216906323b872dd90608401614220565b61442861489a565b61331c82826148e3565b61443a61489a565b61186581614934565b61130961489a565b61445361489a565b611309614966565b60008051602061530e83398151915260006144758461188e565b600085815260208490526040808220600101869055519192508491839187917fbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff9190a450505050565b600d54816144d86000805160206152a68339815191525490565b6144e29190614eb4565b11156145265760405162461bcd60e51b815260206004820152601360248201527213585e081cdd5c1c1b1e48195e18d959591959606a1b6044820152606401610f51565b61331c828261496e565b601054600554611865916001600160a01b0391821691339116846143e7565b600554611865906001600160a01b03163330846143e7565b6000805160206152868339815191526001600160a01b0385166145a05760405163e602df0560e01b815260006004820152602401610f51565b6001600160a01b0384166145ca57604051634a1406b160e11b815260006004820152602401610f51565b6001600160a01b0380861660009081526001830160209081526040808320938816835292905220839055811561464857836001600160a01b0316856001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258560405161463f91815260200190565b60405180910390a35b5050505050565b6000805160206152868339815191526001600160a01b03841661468b57818160020160008282546146809190614eb4565b909155506146fd9050565b6001600160a01b038416600090815260208290526040902054828110156146de5760405163391434e360e21b81526001600160a01b03861660048201526024810182905260448101849052606401610f51565b6001600160a01b03851660009081526020839052604090209083900390555b6001600160a01b03831661471b57600281018054839003905561473a565b6001600160a01b03831660009081526020829052604090208054830190555b826001600160a01b0316846001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161477f91815260200190565b60405180910390a350505050565b60006147a26001600160a01b038416836149a4565b905080516000141580156147c75750808060200190518101906147c59190614ff5565b155b15611f0457604051635274afe760e01b81526001600160a01b0384166004820152602401610f51565b6147fa8282612b14565b61331c5760405163e2517d3f60e01b81526001600160a01b038216600482015260248101839052604401610f51565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930080546001600160a01b031981166001600160a01b03848116918217845560405192169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3505050565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054600160401b900460ff1661130957604051631afcd79f60e31b815260040160405180910390fd5b6148eb61489a565b6000805160206152868339815191527f52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace036149258482615166565b5060048101611ecb8382615166565b61493c61489a565b6001600160a01b03811661275657604051631e4fbdf760e01b815260006004820152602401610f51565b6140ea61489a565b6001600160a01b0382166149985760405163ec442f0560e01b815260006004820152602401610f51565b61331c6000838361464f565b60606118878383600084600080856001600160a01b031684866040516149ca9190615226565b60006040518083038185875af1925050503d8060008114614a07576040519150601f19603f3d011682016040523d82523d6000602084013e614a0c565b606091505b5091509150614a1c868383614a26565b9695505050505050565b606082614a3b57614a3682614a82565b611887565b8151158015614a5257506001600160a01b0384163b155b15614a7b57604051639996b31560e01b81526001600160a01b0385166004820152602401610f51565b5080611887565b805115614a925780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b600060208284031215614abd57600080fd5b81356001600160e01b03198116811461188757600080fd5b60005b83811015614af0578181015183820152602001614ad8565b50506000910152565b6020815260008251806020840152614b18816040850160208701614ad5565b601f01601f19169190910160400192915050565b80356001600160a01b0381168114614b4357600080fd5b919050565b60008060408385031215614b5b57600080fd5b614b6483614b2c565b946020939093013593505050565b600060208284031215614b8457600080fd5b5035919050565b801515811461186557600080fd5b600060208284031215614bab57600080fd5b813561188781614b8b565b600080600060608486031215614bcb57600080fd5b614bd484614b2c565b9250614be260208501614b2c565b9150604084013590509250925092565b60008060408385031215614c0557600080fd5b82359150614c1560208401614b2c565b90509250929050565b600060208284031215614c3057600080fd5b61188782614b2c565b634e487b7160e01b600052604160045260246000fd5b600060208284031215614c6157600080fd5b813567ffffffffffffffff80821115614c7957600080fd5b818401915084601f830112614c8d57600080fd5b813581811115614c9f57614c9f614c39565b604051601f8201601f19908116603f01168101908382118183101715614cc757614cc7614c39565b81604052828152876020848701011115614ce057600080fd5b826020860160208301376000928101602001929092525095945050505050565b60008060208385031215614d1357600080fd5b823567ffffffffffffffff80821115614d2b57600080fd5b818501915085601f830112614d3f57600080fd5b813581811115614d4e57600080fd5b8660208260061b8501011115614d6357600080fd5b60209290920196919550909350505050565b60008060408385031215614d8857600080fd5b614d9183614b2c565b9150614c1560208401614b2c565b602080825282518282018190526000919060409081850190868401855b82811015614e0b578151805185528681015187860152858101511515868601526060808201516001600160a01b0316908601526080908101519085015260a09093019290850190600101614dbc565b5091979650505050505050565b600181811c90821680614e2c57607f821691505b602082108103614e4c57634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b81810381811115610d8e57610d8e614e52565b8082028115828204841417610d8e57610d8e614e52565b600082614eaf57634e487b7160e01b600052601260045260246000fd5b500490565b80820180821115610d8e57610d8e614e52565b6020808252602f908201527f43616c6c657220646f6573206e6f742068617665204d414e4147455f5354414b60408201526e494e475f5550444154455f524f4c4560881b606082015260800190565b6020808252602c908201527f43616c6c657220646f6573206e6f74206861766520415050524f56455f57495460408201526b4844524157414c5f524f4c4560a01b606082015260800190565b8281526000602060408184015260008454614f7c81614e18565b8060408701526060600180841660008114614f9e5760018114614fb857614fe6565b60ff1985168984015283151560051b890183019550614fe6565b896000528660002060005b85811015614fde5781548b8201860152908301908801614fc3565b8a0184019650505b50939998505050505050505050565b60006020828403121561500757600080fd5b815161188781614b8b565b60208082526012908201527110dbdb9d1c9858dd081a5cc81c185d5cd95960721b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b60006001820161506657615066614e52565b5060010190565b60208082526029908201527f43616c6c657220646f6573206e6f7420686176652045584348414e47455f5550604082015268444154455f524f4c4560b81b606082015260800190565b60208082526029908201527f43616c6c657220646f6573206e6f74206861766520544f4b454e5f534146455f60408201526850554c4c5f524f4c4560b81b606082015260800190565b60006020828403121561511157600080fd5b5051919050565b601f821115611f0457600081815260208120601f850160051c8101602086101561513f5750805b601f850160051c820191505b8181101561515e5782815560010161514b565b505050505050565b815167ffffffffffffffff81111561518057615180614c39565b6151948161518e8454614e18565b84615118565b602080601f8311600181146151c957600084156151b15750858301515b600019600386901b1c1916600185901b17855561515e565b600085815260208120601f198616915b828110156151f8578886015182559484019460019091019084016151d9565b50858210156152165787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60008251615238818460208701614ad5565b919091019291505056fe50726f746f636f6c207661756c7420616464726573732063616e6e6f7420626520307769746864726177616c20616464726573732063616e6e6f74206265206e756c6c52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace0052c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace02cdc459158320f1e5dc6a2790e6223a1fae30e193e0b9c0c623cd787aee91ddd3526563697069656e7420616464726573732063616e6e6f74206265206e756c6c206164647265737302dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b6268009b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f008265d83785d3287e7d7481132632b4a43778b737fb1aeb3bb294f9e9984de840a2646970667358221220dd41f63694bb59f6f2256623877b7e29e430813330260281949b7805d80f30eb64736f6c63430008140033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.