Overview
GLMR Balance
0 GLMR
GLMR Value
$0.00More Info
Private Name Tags
ContractCreator:
Loading...
Loading
Contract Name:
L1LiquidityPool
Compiler Version
v0.8.9+commit.e5eed63a
Optimization Enabled:
Yes with 10000 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity >0.7.5; pragma experimental ABIEncoderV2; import "./interfaces/iL2LiquidityPool.sol"; import "../libraries/CrossDomainEnabledFast.sol"; /* External Imports */ import '@openzeppelin/contracts/utils/math/SafeMath.sol'; import '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol'; import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol"; /* External Imports */ import "@eth-optimism/contracts/contracts/L1/messaging/L1StandardBridge.sol"; /** * @dev An L1 LiquidityPool implementation */ contract L1LiquidityPool is CrossDomainEnabledFast, ReentrancyGuardUpgradeable, PausableUpgradeable { using SafeMath for uint256; using SafeERC20 for IERC20; /************** * Struct * **************/ // Info of each user. struct UserInfo { uint256 amount; // How many LP tokens the user has provided. uint256 rewardDebt; // Reward debt. See explanation below. uint256 pendingReward; // Pending reward // // We do some fancy math here. Basically, any point in time, the amount of rewards // entitled to a user but is pending to be distributed is: // // Update Reward Per Share: // accUserRewardPerShare = accUserRewardPerShare + (accUserReward - lastAccUserReward) / userDepositAmount // // LP Provider: // Deposit: // Case 1 (new user): // Update Reward Per Share(); // Calculate user.rewardDebt = amount * accUserRewardPerShare; // Case 2 (user who has already deposited add more funds): // Update Reward Per Share(); // Calculate user.pendingReward = amount * accUserRewardPerShare - user.rewardDebt; // Calculate user.rewardDebt = (amount + new_amount) * accUserRewardPerShare; // // Withdraw // Update Reward Per Share(); // Calculate user.pendingReward = amount * accUserRewardPerShare - user.rewardDebt; // Calculate user.rewardDebt = (amount - withdraw_amount) * accUserRewardPerShare; } // Info of each pool. struct PoolInfo { address l1TokenAddress; // Address of token contract. address l2TokenAddress; // Address of toekn contract. // balance uint256 userDepositAmount; // user deposit amount; // user rewards uint256 lastAccUserReward; // Last accumulated user reward uint256 accUserReward; // Accumulated user reward. uint256 accUserRewardPerShare; // Accumulated user rewards per share, times 1e12. See below. // owner rewards uint256 accOwnerReward; // Accumulated owner reward. // start time -- used to calculate APR uint256 startTime; } // Token batch structure struct ClientDepositToken { address l1TokenAddress; uint256 amount; } struct ClientPayToken { address to; address l2TokenAddress; uint256 amount; } /************* * Variables * *************/ // mapping L1 and L2 token address to poolInfo mapping(address => PoolInfo) public poolInfo; // Info of each user that stakes tokens. mapping(address => mapping(address => UserInfo)) public userInfo; address public owner; address public L2LiquidityPoolAddress; uint256 public userRewardMinFeeRate; uint256 public ownerRewardFeeRate; // Default gas value which can be overridden if more complex logic runs on L2. uint32 public SETTLEMENT_L2_GAS; uint256 public SAFE_GAS_STIPEND; // cdm address address public l1CrossDomainMessenger; // L1StandardBridge address address payable public L1StandardBridgeAddress; uint256 public userRewardMaxFeeRate; bytes32 public priorDepositInfoHash; bytes32 public currentDepositInfoHash; uint256 public lastHashUpdateBlock; /******************** * Events * ********************/ event AddLiquidity( address sender, uint256 amount, address tokenAddress ); event OwnerRecoverFee( address sender, address receiver, uint256 amount, address tokenAddress ); event ClientDepositL1( address sender, uint256 receivedAmount, address tokenAddress ); event ClientDepositL1Batch( ClientPayToken[] _tokens ); event ClientPayL1( address sender, uint256 amount, uint256 userRewardFee, uint256 ownerRewardFee, uint256 totalFee, address tokenAddress ); event ClientPayL1Settlement( address sender, uint256 amount, uint256 userRewardFee, uint256 ownerRewardFee, uint256 totalFee, address tokenAddress ); event WithdrawLiquidity( address sender, address receiver, uint256 amount, address tokenAddress ); event WithdrawReward( address sender, address receiver, uint256 amount, address tokenAddress ); event RebalanceLP( uint256 amount, address tokenAddress ); event OwnershipTransferred( address newOwner ); /******************** * Constructor * ********************/ constructor() CrossDomainEnabledFast(address(0), address(0)) {} /********************** * Function Modifiers * **********************/ modifier onlyOwner() { require(msg.sender == owner || owner == address(0), 'Caller is not the owner'); _; } modifier onlyNotInitialized() { require(address(L2LiquidityPoolAddress) == address(0), "Contract has been initialized"); _; } modifier onlyInitialized() { require(address(L2LiquidityPoolAddress) != address(0), "Contract has not yet been initialized"); _; } modifier onlyL1StandardBridge() { require(address(L1StandardBridgeAddress) == msg.sender, "Can't receive ETH"); _; } /******************** * Fall back Functions * ********************/ receive() external payable onlyL1StandardBridge() {} /******************** * Public Functions * ********************/ /** * @dev transfer ownership * * @param _newOwner new owner of this contract */ function transferOwnership( address _newOwner ) public onlyOwner() { require(_newOwner != address(0), 'New owner cannot be the zero address'); owner = _newOwner; emit OwnershipTransferred(_newOwner); } /** * @dev Initialize this contract. * * @param _l1CrossDomainMessenger L1 Messenger address being used for sending the cross-chain message. * @param _l1CrossDomainMessengerFast L1 Messenger address being used for relaying cross-chain messages quickly. * @param _L2LiquidityPoolAddress Address of the corresponding L2 LP deployed to the L2 chain * @param _L1StandardBridgeAddress Address of L1 StandardBridge */ function initialize( address _l1CrossDomainMessenger, address _l1CrossDomainMessengerFast, address _L2LiquidityPoolAddress, address payable _L1StandardBridgeAddress ) public onlyOwner() onlyNotInitialized() initializer() { require(_l1CrossDomainMessenger != address(0) && _l1CrossDomainMessengerFast != address(0) && _L2LiquidityPoolAddress != address(0), "zero address not allowed"); senderMessenger = _l1CrossDomainMessenger; relayerMessenger = _l1CrossDomainMessengerFast; L2LiquidityPoolAddress = _L2LiquidityPoolAddress; L1StandardBridgeAddress = _L1StandardBridgeAddress; owner = msg.sender; // translates to fee rates 0.5%, 5% and 0% respectively _configureFee(5, 50, 0); configureGas(700000, 2300); __Context_init_unchained(); __Pausable_init_unchained(); __ReentrancyGuard_init_unchained(); } function _configureFee( uint256 _userRewardMinFeeRate, uint256 _userRewardMaxFeeRate, uint256 _ownerRewardFeeRate ) internal { userRewardMinFeeRate = _userRewardMinFeeRate; userRewardMaxFeeRate = _userRewardMaxFeeRate; ownerRewardFeeRate = _ownerRewardFeeRate; } /** * @dev Configure gas. * * @param _l2GasFee default finalized deposit L2 Gas * @param _safeGas safe gas stipened */ function configureGas( uint32 _l2GasFee, uint256 _safeGas ) public onlyOwner() onlyInitialized() { SETTLEMENT_L2_GAS = _l2GasFee; SAFE_GAS_STIPEND = _safeGas; } /** * @dev Return user reward fee rate. * * @param _l1TokenAddress L1 token address */ function getUserRewardFeeRate( address _l1TokenAddress ) public view onlyInitialized() returns (uint256 userRewardFeeRate) { PoolInfo storage pool = poolInfo[_l1TokenAddress]; uint256 poolLiquidity = pool.userDepositAmount; uint256 poolBalance; if (_l1TokenAddress == address(0)) { poolBalance = address(this).balance; } else { poolBalance = IERC20(_l1TokenAddress).balanceOf(address(this)); } if (poolBalance == 0) { return userRewardMaxFeeRate; } else { uint256 poolRewardRate = userRewardMinFeeRate * poolLiquidity / poolBalance; if (userRewardMinFeeRate > poolRewardRate) { return userRewardMinFeeRate; } else if (userRewardMaxFeeRate < poolRewardRate) { return userRewardMaxFeeRate; } return poolRewardRate; } } /*** * @dev Add the new token pair to the pool * DO NOT add the same LP token more than once. Rewards will be messed up if you do. * * @param _l1TokenAddress * @param _l2TokenAddress * */ function registerPool( address _l1TokenAddress, address _l2TokenAddress ) public onlyOwner() { require(_l1TokenAddress != _l2TokenAddress, "l1 and l2 token addresses cannot be same"); require(_l2TokenAddress != address(0), "l2 token address cannot be zero address"); // use with caution, can register only once PoolInfo storage pool = poolInfo[_l1TokenAddress]; // l2 token address equal to zero, then pair is not registered. require(pool.l2TokenAddress == address(0), "Token Address Already Registered"); poolInfo[_l1TokenAddress] = PoolInfo({ l1TokenAddress: _l1TokenAddress, l2TokenAddress: _l2TokenAddress, userDepositAmount: 0, lastAccUserReward: 0, accUserReward: 0, accUserRewardPerShare: 0, accOwnerReward: 0, startTime: block.timestamp }); } /** * Update the user reward per share * @param _tokenAddress Address of the target token. */ function updateUserRewardPerShare( address _tokenAddress ) public { PoolInfo storage pool = poolInfo[_tokenAddress]; if (pool.lastAccUserReward < pool.accUserReward) { uint256 accUserRewardDiff = (pool.accUserReward.sub(pool.lastAccUserReward)); if (pool.userDepositAmount != 0) { pool.accUserRewardPerShare = pool.accUserRewardPerShare.add( accUserRewardDiff.mul(1e12).div(pool.userDepositAmount) ); } pool.lastAccUserReward = pool.accUserReward; } } /** * Liquididity providers add liquidity * @param _amount liquidity amount that users want to deposit. * @param _tokenAddress address of the liquidity token. */ function addLiquidity( uint256 _amount, address _tokenAddress ) external payable nonReentrant whenNotPaused { require(msg.value != 0 || _tokenAddress != address(0), "Either Amount Incorrect or Token Address Incorrect"); // combine to make logical XOR to avoid user error require(!(msg.value != 0 && _tokenAddress != address(0)), "Either Amount Incorrect or Token Address Incorrect"); // check whether user sends ETH or ERC20 if (msg.value != 0) { // override the _amount and token address _amount = msg.value; _tokenAddress = address(0); } PoolInfo storage pool = poolInfo[_tokenAddress]; UserInfo storage user = userInfo[_tokenAddress][msg.sender]; require(pool.l2TokenAddress != address(0), "Token Address Not Registered"); // Update accUserRewardPerShare updateUserRewardPerShare(_tokenAddress); // if the user has already deposited token, we move the rewards to // pendingReward and update the reward debet. if (user.amount > 0) { user.pendingReward = user.pendingReward.add( user.amount.mul(pool.accUserRewardPerShare).div(1e12).sub(user.rewardDebt) ); user.rewardDebt = (user.amount.add(_amount)).mul(pool.accUserRewardPerShare).div(1e12); } else { user.rewardDebt = _amount.mul(pool.accUserRewardPerShare).div(1e12); } // update amounts user.amount = user.amount.add(_amount); pool.userDepositAmount = pool.userDepositAmount.add(_amount); emit AddLiquidity( msg.sender, _amount, _tokenAddress ); // transfer funds if users deposit ERC20 if (_tokenAddress != address(0)) { IERC20(_tokenAddress).safeTransferFrom(msg.sender, address(this), _amount); } } /** * Client deposit ERC20 from their account to this contract, which then releases funds on the L2 side * @param _amount amount that client wants to transfer. * @param _tokenAddress L2 token address */ function clientDepositL1( uint256 _amount, address _tokenAddress ) external payable whenNotPaused { require(msg.value != 0 || _tokenAddress != address(0), "Either Amount Incorrect or Token Address Incorrect"); // combine to make logical XOR to avoid user error require(!(msg.value != 0 && _tokenAddress != address(0)), "Either Amount Incorrect or Token Address Incorrect"); // check whether user sends ETH or ERC20 if (msg.value != 0) { // override the _amount and token address _amount = msg.value; _tokenAddress = address(0); } PoolInfo storage pool = poolInfo[_tokenAddress]; require(pool.l2TokenAddress != address(0), "Token Address Not Registered"); _updateDepositHash(_tokenAddress, msg.sender, _amount); emit ClientDepositL1( msg.sender, _amount, _tokenAddress ); // transfer funds if users deposit ERC20 if (_tokenAddress != address(0)) { IERC20(_tokenAddress).safeTransferFrom(msg.sender, address(this), _amount); } // Construct calldata for L1LiquidityPool.clientPayL2(_to, receivedAmount, l2TokenAddress) bytes memory data = abi.encodeWithSelector( iL2LiquidityPool.clientPayL2.selector, msg.sender, _amount, pool.l2TokenAddress ); // Send calldata into L2 sendCrossDomainMessage( address(L2LiquidityPoolAddress), // extra gas for complex l2 logic SETTLEMENT_L2_GAS, data ); } function clientDepositL1Batch( ClientDepositToken[] calldata _tokens ) external payable whenNotPaused { // The l2 gas amount is SETTLEMENT_L2_GAS * 2 // We shouldn't send too many tokens in one batch require(_tokens.length < 5, "Too Many Tokens"); // The total ETH amount in ClientDepositToken[] uint256 ETHAmount; // Create a payload that is sent to L2 ClientPayToken[] memory payload = new ClientPayToken[](_tokens.length); // Check all tokens for (uint256 i = 0; i < _tokens.length; i++) { ClientDepositToken memory token = _tokens[i]; require(token.amount != 0, "Invalid Amount"); PoolInfo storage pool = poolInfo[token.l1TokenAddress]; require(pool.l2TokenAddress != address(0), "Invaild Token"); if (token.l1TokenAddress != address(0)) { IERC20(token.l1TokenAddress).safeTransferFrom(msg.sender, address(this), token.amount); } else { ETHAmount = ETHAmount + token.amount; } payload[i] = ClientPayToken(msg.sender, pool.l2TokenAddress, token.amount); } // verify that the total ETH amount is eqaul to msg.value require(ETHAmount == msg.value, "Invalid ETH Amount"); // Construct calldata for L1LiquidityPool.clientPayL2Batch(ClientPayToken) bytes memory data = abi.encodeWithSelector( iL2LiquidityPool.clientPayL2Batch.selector, payload ); // Send calldata into L1 sendCrossDomainMessage( address(L2LiquidityPoolAddress), // extra gas for complex l2 logic SETTLEMENT_L2_GAS * 2, data ); emit ClientDepositL1Batch( payload ); } /** * Users withdraw token from LP * @param _amount amount to withdraw * @param _tokenAddress L1 token address * @param _to receiver to get the funds */ function withdrawLiquidity( uint256 _amount, address _tokenAddress, address payable _to ) external whenNotPaused { PoolInfo storage pool = poolInfo[_tokenAddress]; UserInfo storage user = userInfo[_tokenAddress][msg.sender]; require(pool.l2TokenAddress != address(0), "Token Address Not Registered"); require(user.amount >= _amount, "Withdraw Error"); // Update accUserRewardPerShare updateUserRewardPerShare(_tokenAddress); // calculate all the rewards and set it as pending rewards user.pendingReward = user.pendingReward.add( user.amount.mul(pool.accUserRewardPerShare).div(1e12).sub(user.rewardDebt) ); // Update the user data user.amount = user.amount.sub(_amount); // update reward debt user.rewardDebt = user.amount.mul(pool.accUserRewardPerShare).div(1e12); // update total user deposit amount pool.userDepositAmount = pool.userDepositAmount.sub(_amount); emit WithdrawLiquidity( msg.sender, _to, _amount, _tokenAddress ); if (_tokenAddress != address(0)) { IERC20(_tokenAddress).safeTransfer(_to, _amount); } else { (bool sent,) = _to.call{gas: SAFE_GAS_STIPEND, value: _amount}(""); require(sent, "Failed to send ETH"); } } /** * owner recovers fee from ERC20 * @param _amount amount that owner wants to recover. * @param _tokenAddress L1 token address * @param _to receiver to get the fee. */ function ownerRecoverFee( uint256 _amount, address _tokenAddress, address _to ) external onlyOwner() { PoolInfo storage pool = poolInfo[_tokenAddress]; require(pool.l2TokenAddress != address(0), "Token Address Not Registered"); require(pool.accOwnerReward >= _amount, "Owner Reward Withdraw Error"); pool.accOwnerReward = pool.accOwnerReward.sub(_amount); emit OwnerRecoverFee( msg.sender, _to, _amount, _tokenAddress ); if (_tokenAddress != address(0)) { IERC20(_tokenAddress).safeTransfer(_to, _amount); } else { (bool sent,) = _to.call{gas: SAFE_GAS_STIPEND, value: _amount}(""); require(sent, "Failed to send Ether"); } } /** * withdraw reward from ERC20 * @param _amount reward amount that liquidity providers want to withdraw * @param _tokenAddress L1 token address * @param _to receiver to get the reward */ function withdrawReward( uint256 _amount, address _tokenAddress, address _to ) external whenNotPaused { PoolInfo storage pool = poolInfo[_tokenAddress]; UserInfo storage user = userInfo[_tokenAddress][msg.sender]; require(pool.l2TokenAddress != address(0), "Token Address Not Registered"); uint256 pendingReward = user.pendingReward.add( user.amount.mul(pool.accUserRewardPerShare).div(1e12).sub(user.rewardDebt) ); require(pendingReward >= _amount, "Withdraw Reward Error"); user.pendingReward = pendingReward.sub(_amount); user.rewardDebt = user.amount.mul(pool.accUserRewardPerShare).div(1e12); emit WithdrawReward( msg.sender, _to, _amount, _tokenAddress ); if (_tokenAddress != address(0)) { IERC20(_tokenAddress).safeTransfer(_to, _amount); } else { (bool sent,) = _to.call{gas: SAFE_GAS_STIPEND, value: _amount}(""); require(sent, "Failed to send Ether"); } } /* * Rebalance LPs * @param _amount token amount that we want to move from L1 to L2 * @param _tokenAddress L1 token address */ function rebalanceLP( uint256 _amount, address _tokenAddress ) external onlyOwner() whenNotPaused() { require(_amount != 0, "Amount Incorrect"); PoolInfo storage pool = poolInfo[_tokenAddress]; require(L2LiquidityPoolAddress != address(0), "L2 Liquidity Pool Not Registered"); require(pool.l2TokenAddress != address(0), "Token Address Not Registered"); emit RebalanceLP( _amount, _tokenAddress ); if (_tokenAddress == address(0)) { require(_amount <= address(this).balance, "Failed to Rebalance LP"); L1StandardBridge(L1StandardBridgeAddress).depositNativeTokenTo{value: _amount}( L2LiquidityPoolAddress, SETTLEMENT_L2_GAS, "" ); } else { require(_amount <= IERC20(_tokenAddress).balanceOf(address(this)), "Failed to Rebalance LP"); IERC20(_tokenAddress).safeIncreaseAllowance(L1StandardBridgeAddress, _amount); L1StandardBridge(L1StandardBridgeAddress).depositERC20To( _tokenAddress, pool.l2TokenAddress, L2LiquidityPoolAddress, _amount, SETTLEMENT_L2_GAS, "" ); } } /** * Pause contract */ function pause() external onlyOwner() { _pause(); } /** * UnPause contract */ function unpause() external onlyOwner() { _unpause(); } function _updateDepositHash(address _tokenAddress, address _account, uint256 _amount) internal { // if block number is different only then update prior if (block.number > lastHashUpdateBlock) { priorDepositInfoHash = currentDepositInfoHash; } currentDepositInfoHash = keccak256(abi.encode( currentDepositInfoHash, _tokenAddress, _account, _amount )); lastHashUpdateBlock = block.number; } /************************* * Cross-chain Functions * *************************/ /** * Move funds from L2 to L1, and pay out from the right liquidity pool * part of the contract pause, if only this method needs pausing use pause on CDM_Fast * @param _to receiver to get the funds * @param _amount amount to to be transferred. * @param _tokenAddress L1 token address */ function clientPayL1( address payable _to, uint256 _amount, address _tokenAddress ) external onlyFromCrossDomainAccount(address(L2LiquidityPoolAddress)) whenNotPaused { // replyNeeded helps store the status if a message needs to be sent back to the other layer // in case there is not enough funds to give away bool replyNeeded = false; PoolInfo storage pool = poolInfo[_tokenAddress]; uint256 userRewardFeeRate = getUserRewardFeeRate(_tokenAddress); uint256 userRewardFee = (_amount.mul(userRewardFeeRate)).div(1000); uint256 ownerRewardFee = (_amount.mul(ownerRewardFeeRate)).div(1000); uint256 totalFee = userRewardFee.add(ownerRewardFee); uint256 receivedAmount = _amount.sub(totalFee); if (_tokenAddress != address(0)) { if (receivedAmount > IERC20(_tokenAddress).balanceOf(address(this))) { replyNeeded = true; } else { pool.accUserReward = pool.accUserReward.add(userRewardFee); pool.accOwnerReward = pool.accOwnerReward.add(ownerRewardFee); IERC20(_tokenAddress).safeTransfer(_to, receivedAmount); } } else { // //this is ETH if (receivedAmount > address(this).balance) { replyNeeded = true; } else { pool.accUserReward = pool.accUserReward.add(userRewardFee); pool.accOwnerReward = pool.accOwnerReward.add(ownerRewardFee); //this is ETH (bool sent,) = _to.call{gas: SAFE_GAS_STIPEND, value: receivedAmount}(""); require(sent, "Failed to send ETH"); } } if (replyNeeded) { // send cross domain message bytes memory data = abi.encodeWithSelector( iL2LiquidityPool.clientPayL2Settlement.selector, _to, _amount, pool.l2TokenAddress ); sendCrossDomainMessage( address(L2LiquidityPoolAddress), SETTLEMENT_L2_GAS, data ); } else { emit ClientPayL1( _to, receivedAmount, userRewardFee, ownerRewardFee, totalFee, _tokenAddress ); } } /** * Settlement pay when there's not enough funds on the other side * part of the contract pause, if only this method needs pausing use pause on CDM_Fast * @param _to receiver to get the funds * @param _amount amount to to be transferred. * @param _tokenAddress L1 token address */ function clientPayL1Settlement( address payable _to, uint256 _amount, address _tokenAddress ) external onlyFromCrossDomainAccount(address(L2LiquidityPoolAddress)) whenNotPaused { PoolInfo storage pool = poolInfo[_tokenAddress]; uint256 userRewardFeeRate = getUserRewardFeeRate(_tokenAddress); uint256 userRewardFee = (_amount.mul(userRewardFeeRate)).div(1000); uint256 ownerRewardFee = (_amount.mul(ownerRewardFeeRate)).div(1000); uint256 totalFee = userRewardFee.add(ownerRewardFee); uint256 receivedAmount = _amount.sub(totalFee); pool.accUserReward = pool.accUserReward.add(userRewardFee); pool.accOwnerReward = pool.accOwnerReward.add(ownerRewardFee); emit ClientPayL1Settlement( _to, receivedAmount, userRewardFee, ownerRewardFee, totalFee, _tokenAddress ); if (_tokenAddress != address(0)) { IERC20(_tokenAddress).safeTransfer(_to, receivedAmount); } else { //this is ETH (bool sent,) = _to.call{gas: SAFE_GAS_STIPEND, value: receivedAmount}(""); require(sent, "Failed to send Ether"); } } /** * @dev Configure fee of this contract. called from L2 * @dev Each fee rate is scaled by 10^3 for precision, eg- a fee rate of 50 would mean 5% * @param _userRewardMinFeeRate minimum fee rate that users get * @param _userRewardMaxFeeRate maximum fee rate that users get * @param _ownerRewardFeeRate fee rate that contract owner gets */ function configureFee( uint256 _userRewardMinFeeRate, uint256 _userRewardMaxFeeRate, uint256 _ownerRewardFeeRate ) external onlyOwner() onlyInitialized() { require(_userRewardMinFeeRate <= _userRewardMaxFeeRate, "Invalud user reward fee"); _configureFee(_userRewardMinFeeRate, _userRewardMaxFeeRate,_ownerRewardFeeRate); } }
// SPDX-License-Identifier: MIT pragma solidity >0.7.5; pragma experimental ABIEncoderV2; /** * @title iL2LiquidityPool */ interface iL2LiquidityPool { struct ClientPayToken { address payable to; address l2TokenAddress; uint256 amount; } /******************** * Events * ********************/ event AddLiquidity( address sender, uint256 amount, address tokenAddress ); event OwnerRecoverFee( address sender, address receiver, uint256 amount, address tokenAddress ); event ClientDepositL2( address sender, uint256 receivedAmount, address tokenAddress ); event ClientPayL2( address sender, uint256 amount, uint256 userRewardFee, uint256 ownerRewardFee, uint256 totalFee, address tokenAddress ); event ClientPayL2Settlement( address sender, uint256 amount, uint256 userRewardFee, uint256 ownerRewardFee, uint256 totalFee, address tokenAddress ); event WithdrawLiquidity( address sender, address receiver, uint256 amount, address tokenAddress ); event WithdrawReward( address sender, address receiver, uint256 amount, address tokenAddress ); /************************* * Cross-chain Functions * *************************/ function clientPayL2( address payable _to, uint256 _amount, address _tokenAddress ) external; function clientPayL2Batch( ClientPayToken [] calldata _tokens ) external; function clientPayL2Settlement( address payable _to, uint256 _amount, address _tokenAddress ) external; }
// SPDX-License-Identifier: MIT pragma solidity >0.7.5; /* Interface Imports */ import { ICrossDomainMessenger } from "@eth-optimism/contracts/contracts/libraries/bridge/ICrossDomainMessenger.sol"; /** * @title CrossDomainEnabledFast * @dev Helper contract for contracts performing cross-domain communications * * Compiler used: defined by inheriting contract * Runtime target: defined by inheriting contract */ contract CrossDomainEnabledFast { // Messenger contract used to send and receive messages from the other domain. address public senderMessenger; address public relayerMessenger; /*************** * Constructor * ***************/ constructor( address _senderMessenger, address _relayerMessenger ) { senderMessenger = _senderMessenger; relayerMessenger = _relayerMessenger; } /********************** * Function Modifiers * **********************/ /** * @notice Enforces that the modified function is only callable by a specific cross-domain account. * @param _sourceDomainAccount The only account on the originating domain which is authenticated to call this function. */ modifier onlyFromCrossDomainAccount( address _sourceDomainAccount ) { require( msg.sender == address(getCrossDomainRelayerMessenger()), "XCHAIN: messenger contract unauthenticated" ); require( getCrossDomainRelayerMessenger().xDomainMessageSender() == _sourceDomainAccount, "XCHAIN: wrong sender of cross-domain message" ); _; } /********************** * Internal Functions * **********************/ /** * @notice Gets the messenger, usually from storage. This function is exposed in case a child contract needs to override. * @return The address of the cross-domain messenger contract which should be used. */ function getCrossDomainSenderMessenger() internal virtual returns( ICrossDomainMessenger ) { return ICrossDomainMessenger(senderMessenger); } /** * @notice Gets the messenger, usually from storage. This function is exposed in case a child contract needs to override. * @return The address of the cross-domain messenger contract which should be used. */ function getCrossDomainRelayerMessenger() internal virtual returns( ICrossDomainMessenger ) { return ICrossDomainMessenger(relayerMessenger); } /** * @notice Sends a message to an account on another domain * @param _crossDomainTarget The intended recipient on the destination domain * @param _data The data to send to the target (usually calldata to a function with `onlyFromCrossDomainAccount()`) * @param _gasLimit The gasLimit for the receipt of the message on the target domain. */ function sendCrossDomainMessage( address _crossDomainTarget, uint32 _gasLimit, bytes memory _data ) internal { getCrossDomainSenderMessenger().sendMessage(_crossDomainTarget, _data, _gasLimit); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; // CAUTION // This version of SafeMath should only be used with Solidity 0.8 or later, // because it relies on the compiler's built in overflow checks. /** * @dev Wrappers over Solidity's arithmetic operations. * * NOTE: `SafeMath` is no longer needed starting with Solidity 0.8. The compiler * now has built in overflow checking. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } } /** * @dev Returns the substraction of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b > a) return (false, 0); return (true, a - b); } } /** * @dev Returns the multiplication of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) return (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } } /** * @dev Returns the division of two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a / b); } } /** * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a % b); } } /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { return a + b; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { return a - b; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { return a * b; } /** * @dev Returns the integer division of two unsigned integers, reverting on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { return a % b; } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {trySub}. * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub( uint256 a, uint256 b, string memory errorMessage ) internal pure returns (uint256) { unchecked { require(b <= a, errorMessage); return a - b; } } /** * @dev Returns the integer division of two unsigned integers, reverting with custom message on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div( uint256 a, uint256 b, string memory errorMessage ) internal pure returns (uint256) { unchecked { require(b > 0, errorMessage); return a / b; } } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting with custom message when dividing by zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryMod}. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod( uint256 a, uint256 b, string memory errorMessage ) internal pure returns (uint256) { unchecked { require(b > 0, errorMessage); return a % b; } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../IERC20.sol"; import "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; function safeTransfer( IERC20 token, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom( IERC20 token, address from, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove( IERC20 token, address spender, uint256 value ) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance( IERC20 token, address spender, uint256 value ) internal { uint256 newAllowance = token.allowance(address(this), spender) + value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance( IERC20 token, address spender, uint256 value ) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); uint256 newAllowance = oldAllowance - value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../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; uint256 private _status; function __ReentrancyGuard_init() internal initializer { __ReentrancyGuard_init_unchained(); } function __ReentrancyGuard_init_unchained() internal initializer { _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 make it call a * `private` function that does the actual work. */ modifier nonReentrant() { // On the first call to nonReentrant, _notEntered will be true require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; _; // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } uint256[49] private __gap; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../utils/ContextUpgradeable.sol"; import "../proxy/utils/Initializable.sol"; /** * @dev Contract module which allows children to implement an emergency stop * mechanism that can be triggered by an authorized account. * * This module is used through inheritance. It will make available the * modifiers `whenNotPaused` and `whenPaused`, which can be applied to * the functions of your contract. Note that they will not be pausable by * simply including this module, only once the modifiers are put in place. */ abstract contract PausableUpgradeable is Initializable, ContextUpgradeable { /** * @dev Emitted when the pause is triggered by `account`. */ event Paused(address account); /** * @dev Emitted when the pause is lifted by `account`. */ event Unpaused(address account); bool private _paused; /** * @dev Initializes the contract in unpaused state. */ function __Pausable_init() internal initializer { __Context_init_unchained(); __Pausable_init_unchained(); } function __Pausable_init_unchained() internal initializer { _paused = false; } /** * @dev Returns true if the contract is paused, and false otherwise. */ function paused() public view virtual returns (bool) { return _paused; } /** * @dev Modifier to make a function callable only when the contract is not paused. * * Requirements: * * - The contract must not be paused. */ modifier whenNotPaused() { require(!paused(), "Pausable: paused"); _; } /** * @dev Modifier to make a function callable only when the contract is paused. * * Requirements: * * - The contract must be paused. */ modifier whenPaused() { require(paused(), "Pausable: not paused"); _; } /** * @dev Triggers stopped state. * * Requirements: * * - The contract must not be paused. */ function _pause() internal virtual whenNotPaused { _paused = true; emit Paused(_msgSender()); } /** * @dev Returns to normal state. * * Requirements: * * - The contract must be paused. */ function _unpause() internal virtual whenPaused { _paused = false; emit Unpaused(_msgSender()); } uint256[49] private __gap; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.9; /* Interface Imports */ import { IL1StandardBridge } from "./IL1StandardBridge.sol"; import { IL1ERC20Bridge } from "./IL1ERC20Bridge.sol"; import { IL2ERC20Bridge } from "../../L2/messaging/IL2ERC20Bridge.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; /* Library Imports */ import { CrossDomainEnabled } from "../../libraries/bridge/CrossDomainEnabled.sol"; import { Lib_PredeployAddresses } from "../../libraries/constants/Lib_PredeployAddresses.sol"; import { Address } from "@openzeppelin/contracts/utils/Address.sol"; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; /** * @title L1StandardBridge * @dev The L1 native token and ERC20 Bridge is a contract which stores deposited L1 funds and standard * tokens that are in use on L2. It synchronizes a corresponding L2 Bridge, informing it of deposits * and listening to it for newly finalized withdrawals. * * Runtime target: EVM */ contract L1StandardBridge is IL1StandardBridge, CrossDomainEnabled { using SafeERC20 for IERC20; /******************************** * External Contract References * ********************************/ address public l2TokenBridge; // Maps L1 token to L2 token to balance of the L1 token deposited mapping(address => mapping(address => uint256)) public deposits; bytes32 public priorDepositInfoHash; bytes32 public currentDepositInfoHash; uint256 public lastHashUpdateBlock; /*************** * Constructor * ***************/ // This contract lives behind a proxy, so the constructor parameters will go unused. constructor() CrossDomainEnabled(address(0)) {} /****************** * Initialization * ******************/ /** * @param _l1messenger L1 Messenger address being used for cross-chain communications. * @param _l2TokenBridge L2 standard bridge address. */ function initialize(address _l1messenger, address _l2TokenBridge) public { require(messenger == address(0), "Contract has already been initialized."); messenger = _l1messenger; l2TokenBridge = _l2TokenBridge; } /************** * Depositing * **************/ /** @dev Modifier requiring sender to be EOA. This check could be bypassed by a malicious * contract via initcode, but it takes care of the user error we want to avoid. */ modifier onlyEOA() { // Used to stop deposits from contracts (avoid accidentally lost tokens) require(!Address.isContract(msg.sender), "Account not EOA"); _; } /** * @dev This function can be called with no data * to deposit an amount of native token to the caller's balance on L2. * Since the receive function doesn't take data, a conservative * default amount is forwarded to L2. */ receive() external payable onlyEOA { _initiateNativeTokenDeposit(msg.sender, msg.sender, 1_300_000, bytes("")); } /** * @inheritdoc IL1StandardBridge */ function depositNativeToken(uint32 _l2Gas, bytes calldata _data) external payable onlyEOA { _initiateNativeTokenDeposit(msg.sender, msg.sender, _l2Gas, _data); } /** * @inheritdoc IL1StandardBridge */ function depositNativeTokenTo( address _to, uint32 _l2Gas, bytes calldata _data ) external payable { _initiateNativeTokenDeposit(msg.sender, _to, _l2Gas, _data); } /** * @dev Performs the logic for deposits by storing the nativa token and informing the L2 Gateway of * the deposit. * @param _from Account to pull the deposit from on L1. * @param _to Account to give the deposit to on L2. * @param _l2Gas Gas limit required to complete the deposit on L2. * @param _data Optional data to forward to L2. This data is provided * solely as a convenience for external contracts. Aside from enforcing a maximum * length, these contracts provide no guarantees about its content. */ function _initiateNativeTokenDeposit( address _from, address _to, uint32 _l2Gas, bytes memory _data ) internal { // Construct calldata for finalizeDeposit call bytes memory message = abi.encodeWithSelector( IL2ERC20Bridge.finalizeDeposit.selector, address(0), Lib_PredeployAddresses.L1_NATIVE_TOKEN_L2_ADDRESS, _from, _to, msg.value, _data ); // Send calldata into L2 sendCrossDomainMessage(l2TokenBridge, _l2Gas, message); // compute and update deposit hash _updateDepositHash( address(0), Lib_PredeployAddresses.L1_NATIVE_TOKEN_L2_ADDRESS, _from, _to, msg.value ); emit NativeTokenDepositInitiated(_from, _to, msg.value, _data); } /** * @inheritdoc IL1ERC20Bridge */ function depositERC20( address _l1Token, address _l2Token, uint256 _amount, uint32 _l2Gas, bytes calldata _data ) external virtual onlyEOA { _initiateERC20Deposit(_l1Token, _l2Token, msg.sender, msg.sender, _amount, _l2Gas, _data); } /** * @inheritdoc IL1ERC20Bridge */ function depositERC20To( address _l1Token, address _l2Token, address _to, uint256 _amount, uint32 _l2Gas, bytes calldata _data ) external virtual { _initiateERC20Deposit(_l1Token, _l2Token, msg.sender, _to, _amount, _l2Gas, _data); } /** * @dev Performs the logic for deposits by informing the L2 Deposited Token * contract of the deposit and calling a handler to lock the L1 funds. (e.g. transferFrom) * * @param _l1Token Address of the L1 ERC20 we are depositing * @param _l2Token Address of the L1 respective L2 ERC20 * @param _from Account to pull the deposit from on L1 * @param _to Account to give the deposit to on L2 * @param _amount Amount of the ERC20 to deposit. * @param _l2Gas Gas limit required to complete the deposit on L2. * @param _data Optional data to forward to L2. This data is provided * solely as a convenience for external contracts. Aside from enforcing a maximum * length, these contracts provide no guarantees about its content. */ function _initiateERC20Deposit( address _l1Token, address _l2Token, address _from, address _to, uint256 _amount, uint32 _l2Gas, bytes calldata _data ) internal { // When a deposit is initiated on L1, the L1 Bridge transfers the funds to itself for future // withdrawals. safeTransferFrom also checks if the contract has code, so this will fail if // _from is an EOA or address(0). IERC20(_l1Token).safeTransferFrom(_from, address(this), _amount); // Construct calldata for _l2Token.finalizeDeposit(_to, _amount) bytes memory message = abi.encodeWithSelector( IL2ERC20Bridge.finalizeDeposit.selector, _l1Token, _l2Token, _from, _to, _amount, _data ); // Send calldata into L2 sendCrossDomainMessage(l2TokenBridge, _l2Gas, message); deposits[_l1Token][_l2Token] = deposits[_l1Token][_l2Token] + _amount; _updateDepositHash(_l1Token, _l2Token, _from, _to, _amount); emit ERC20DepositInitiated(_l1Token, _l2Token, _from, _to, _amount, _data); } function _updateDepositHash( address _l1Token, address _l2Token, address _from, address _to, uint256 _amount ) internal { // if block number is different only then update prior if (block.number > lastHashUpdateBlock) { priorDepositInfoHash = currentDepositInfoHash; } currentDepositInfoHash = keccak256( abi.encode(currentDepositInfoHash, _l1Token, _l2Token, _from, _to, _amount) ); lastHashUpdateBlock = block.number; } /************************* * Cross-chain Functions * *************************/ /** * @inheritdoc IL1StandardBridge */ function finalizeNativeTokenWithdrawal( address _from, address _to, uint256 _amount, bytes calldata _data ) external onlyFromCrossDomainAccount(l2TokenBridge) { (bool success, ) = _to.call{ value: _amount }(new bytes(0)); require(success, "TransferHelper::safeTransferNativeToken: NativeToken transfer failed"); emit NativeTokenWithdrawalFinalized(_from, _to, _amount, _data); } /** * @inheritdoc IL1ERC20Bridge */ function finalizeERC20Withdrawal( address _l1Token, address _l2Token, address _from, address _to, uint256 _amount, bytes calldata _data ) external onlyFromCrossDomainAccount(l2TokenBridge) { deposits[_l1Token][_l2Token] = deposits[_l1Token][_l2Token] - _amount; // When a withdrawal is finalized on L1, the L1 Bridge transfers the funds to the withdrawer IERC20(_l1Token).safeTransfer(_to, _amount); emit ERC20WithdrawalFinalized(_l1Token, _l2Token, _from, _to, _amount, _data); } /************************************** * Temporary - Migrating Native Token * **************************************/ /** * @dev Adds native token balance to the account. This is meant to allow for native token * to be migrated from an old gateway to a new gateway. * NOTE: This is left for one upgrade only so we are able to receive the migrated * native token from the old contract */ function donateNativeToken() external payable {} }
// SPDX-License-Identifier: MIT pragma solidity >0.5.0 <0.9.0; /** * @title ICrossDomainMessenger */ interface ICrossDomainMessenger { /********** * Events * **********/ event SentMessage( address indexed target, address sender, bytes message, uint256 messageNonce, uint256 gasLimit ); event RelayedMessage(bytes32 indexed msgHash); event FailedRelayedMessage(bytes32 indexed msgHash); /************* * Variables * *************/ function xDomainMessageSender() external view returns (address); /******************** * Public Functions * ********************/ /** * Sends a cross domain message to the target messenger. * @param _target Target contract address. * @param _message Message to send to the target. * @param _gasLimit Gas limit for the provided message. */ function sendMessage( address _target, bytes calldata _message, uint32 _gasLimit ) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address sender, address recipient, uint256 amount ) external returns (bool); /** * @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); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; assembly { size := extcodesize(account) } return size > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { require(isContract(target), "Address: delegate call to non-contract"); (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @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 a proxied contract can't have 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. * * 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. */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. */ bool private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Modifier to protect an initializer function from being invoked twice. */ modifier initializer() { require(_initializing || !_initialized, "Initializable: contract is already initialized"); bool isTopLevelCall = !_initializing; if (isTopLevelCall) { _initializing = true; _initialized = true; } _; if (isTopLevelCall) { _initializing = false; } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../proxy/utils/Initializable.sol"; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract ContextUpgradeable is Initializable { function __Context_init() internal initializer { __Context_init_unchained(); } function __Context_init_unchained() internal initializer { } function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } uint256[50] private __gap; }
// SPDX-License-Identifier: MIT pragma solidity >0.5.0 <0.9.0; import "./IL1ERC20Bridge.sol"; /** * @title IL1StandardBridge */ interface IL1StandardBridge is IL1ERC20Bridge { /********** * Events * **********/ event NativeTokenDepositInitiated( address indexed _from, address indexed _to, uint256 _amount, bytes _data ); event NativeTokenWithdrawalFinalized( address indexed _from, address indexed _to, uint256 _amount, bytes _data ); /******************** * Public Functions * ********************/ /** * @dev Deposit an amount of the native token to the caller's balance on L2. * @param _l2Gas Gas limit required to complete the deposit on L2. * @param _data Optional data to forward to L2. This data is provided * solely as a convenience for external contracts. Aside from enforcing a maximum * length, these contracts provide no guarantees about its content. */ function depositNativeToken(uint32 _l2Gas, bytes calldata _data) external payable; /** * @dev Deposit an amount of native token to a recipient's balance on L2. * @param _to L2 address to credit the withdrawal to. * @param _l2Gas Gas limit required to complete the deposit on L2. * @param _data Optional data to forward to L2. This data is provided * solely as a convenience for external contracts. Aside from enforcing a maximum * length, these contracts provide no guarantees about its content. */ function depositNativeTokenTo( address _to, uint32 _l2Gas, bytes calldata _data ) external payable; /************************* * Cross-chain Functions * *************************/ /** * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the * L1 ETH token. Since only the xDomainMessenger can call this function, it will never be called * before the withdrawal is finalized. * @param _from L2 address initiating the transfer. * @param _to L1 address to credit the withdrawal to. * @param _amount Amount of the ERC20 to deposit. * @param _data Optional data to forward to L2. This data is provided * solely as a convenience for external contracts. Aside from enforcing a maximum * length, these contracts provide no guarantees about its content. */ function finalizeNativeTokenWithdrawal( address _from, address _to, uint256 _amount, bytes calldata _data ) external; }
// SPDX-License-Identifier: MIT pragma solidity >0.5.0 <0.9.0; /** * @title IL1ERC20Bridge */ interface IL1ERC20Bridge { /********** * Events * **********/ event ERC20DepositInitiated( address indexed _l1Token, address indexed _l2Token, address indexed _from, address _to, uint256 _amount, bytes _data ); event ERC20WithdrawalFinalized( address indexed _l1Token, address indexed _l2Token, address indexed _from, address _to, uint256 _amount, bytes _data ); /******************** * Public Functions * ********************/ /** * @dev get the address of the corresponding L2 bridge contract. * @return Address of the corresponding L2 bridge contract. */ function l2TokenBridge() external returns (address); /** * @dev deposit an amount of the ERC20 to the caller's balance on L2. * @param _l1Token Address of the L1 ERC20 we are depositing * @param _l2Token Address of the L1 respective L2 ERC20 * @param _amount Amount of the ERC20 to deposit * @param _l2Gas Gas limit required to complete the deposit on L2. * @param _data Optional data to forward to L2. This data is provided * solely as a convenience for external contracts. Aside from enforcing a maximum * length, these contracts provide no guarantees about its content. */ function depositERC20( address _l1Token, address _l2Token, uint256 _amount, uint32 _l2Gas, bytes calldata _data ) external; /** * @dev deposit an amount of ERC20 to a recipient's balance on L2. * @param _l1Token Address of the L1 ERC20 we are depositing * @param _l2Token Address of the L1 respective L2 ERC20 * @param _to L2 address to credit the withdrawal to. * @param _amount Amount of the ERC20 to deposit. * @param _l2Gas Gas limit required to complete the deposit on L2. * @param _data Optional data to forward to L2. This data is provided * solely as a convenience for external contracts. Aside from enforcing a maximum * length, these contracts provide no guarantees about its content. */ function depositERC20To( address _l1Token, address _l2Token, address _to, uint256 _amount, uint32 _l2Gas, bytes calldata _data ) external; /************************* * Cross-chain Functions * *************************/ /** * @dev Complete a withdrawal from L2 to L1, and credit funds to the recipient's balance of the * L1 ERC20 token. * This call will fail if the initialized withdrawal from L2 has not been finalized. * * @param _l1Token Address of L1 token to finalizeWithdrawal for. * @param _l2Token Address of L2 token where withdrawal was initiated. * @param _from L2 address initiating the transfer. * @param _to L1 address to credit the withdrawal to. * @param _amount Amount of the ERC20 to deposit. * @param _data Data provided by the sender on L2. This data is provided * solely as a convenience for external contracts. Aside from enforcing a maximum * length, these contracts provide no guarantees about its content. */ function finalizeERC20Withdrawal( address _l1Token, address _l2Token, address _from, address _to, uint256 _amount, bytes calldata _data ) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.9; /** * @title IL2ERC20Bridge */ interface IL2ERC20Bridge { /********** * Events * **********/ event WithdrawalInitiated( address indexed _l1Token, address indexed _l2Token, address indexed _from, address _to, uint256 _amount, bytes _data ); event DepositFinalized( address indexed _l1Token, address indexed _l2Token, address indexed _from, address _to, uint256 _amount, bytes _data ); event DepositFailed( address indexed _l1Token, address indexed _l2Token, address indexed _from, address _to, uint256 _amount, bytes _data ); /******************** * Public Functions * ********************/ /** * @dev get the address of the corresponding L1 bridge contract. * @return Address of the corresponding L1 bridge contract. */ function l1TokenBridge() external returns (address); /** * @dev initiate a withdraw of some tokens to the caller's account on L1 * @param _l2Token Address of L2 token where withdrawal was initiated. * @param _amount Amount of the token to withdraw. * param _l1Gas Unused, but included for potential forward compatibility considerations. * @param _data Optional data to forward to L1. This data is provided * solely as a convenience for external contracts. Aside from enforcing a maximum * length, these contracts provide no guarantees about its content. */ function withdraw( address _l2Token, uint256 _amount, uint32 _l1Gas, bytes calldata _data ) external; /** * @dev initiate a withdraw of some token to a recipient's account on L1. * @param _l2Token Address of L2 token where withdrawal is initiated. * @param _to L1 adress to credit the withdrawal to. * @param _amount Amount of the token to withdraw. * param _l1Gas Unused, but included for potential forward compatibility considerations. * @param _data Optional data to forward to L1. This data is provided * solely as a convenience for external contracts. Aside from enforcing a maximum * length, these contracts provide no guarantees about its content. */ function withdrawTo( address _l2Token, address _to, uint256 _amount, uint32 _l1Gas, bytes calldata _data ) external; /************************* * Cross-chain Functions * *************************/ /** * @dev Complete a deposit from L1 to L2, and credits funds to the recipient's balance of this * L2 token. This call will fail if it did not originate from a corresponding deposit in * L1StandardTokenBridge. * @param _l1Token Address for the l1 token this is called with * @param _l2Token Address for the l2 token this is called with * @param _from Account to pull the deposit from on L2. * @param _to Address to receive the withdrawal at * @param _amount Amount of the token to withdraw * @param _data Data provider by the sender on L1. This data is provided * solely as a convenience for external contracts. Aside from enforcing a maximum * length, these contracts provide no guarantees about its content. */ function finalizeDeposit( address _l1Token, address _l2Token, address _from, address _to, uint256 _amount, bytes calldata _data ) external; }
// SPDX-License-Identifier: MIT pragma solidity >0.5.0 <0.9.0; /* Interface Imports */ import { ICrossDomainMessenger } from "./ICrossDomainMessenger.sol"; /** * @title CrossDomainEnabled * @dev Helper contract for contracts performing cross-domain communications * * Compiler used: defined by inheriting contract * Runtime target: defined by inheriting contract */ contract CrossDomainEnabled { /************* * Variables * *************/ // Messenger contract used to send and recieve messages from the other domain. address public messenger; /*************** * Constructor * ***************/ /** * @param _messenger Address of the CrossDomainMessenger on the current layer. */ constructor(address _messenger) { messenger = _messenger; } /********************** * Function Modifiers * **********************/ /** * Enforces that the modified function is only callable by a specific cross-domain account. * @param _sourceDomainAccount The only account on the originating domain which is * authenticated to call this function. */ modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) { require( msg.sender == address(getCrossDomainMessenger()), "OVM_XCHAIN: messenger contract unauthenticated" ); require( getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount, "OVM_XCHAIN: wrong sender of cross-domain message" ); _; } /********************** * Internal Functions * **********************/ /** * Gets the messenger, usually from storage. This function is exposed in case a child contract * needs to override. * @return The address of the cross-domain messenger contract which should be used. */ function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) { return ICrossDomainMessenger(messenger); } /**q * Sends a message to an account on another domain * @param _crossDomainTarget The intended recipient on the destination domain * @param _message The data to send to the target (usually calldata to a function with * `onlyFromCrossDomainAccount()`) * @param _gasLimit The gasLimit for the receipt of the message on the target domain. */ function sendCrossDomainMessage( address _crossDomainTarget, uint32 _gasLimit, bytes memory _message ) internal { getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.9; /** * @title Lib_PredeployAddresses */ library Lib_PredeployAddresses { // solhint-disable max-line-length address internal constant L2_TO_L1_MESSAGE_PASSER = 0x4200000000000000000000000000000000000000; address internal constant L1_MESSAGE_SENDER = 0x4200000000000000000000000000000000000001; address internal constant DEPLOYER_WHITELIST = 0x4200000000000000000000000000000000000002; // BOBA is the L2 native token address payable internal constant L2_BOBA = payable(0x4200000000000000000000000000000000000006); // L1 native token is a ERC20 token on L2 address internal constant L1_NATIVE_TOKEN_L2_ADDRESS = 0x4200000000000000000000000000000000000023; // solhint-disable-next-line max-line-length address internal constant L2_CROSS_DOMAIN_MESSENGER = 0x4200000000000000000000000000000000000007; address internal constant LIB_ADDRESS_MANAGER = 0x4200000000000000000000000000000000000008; address internal constant PROXY_EOA = 0x4200000000000000000000000000000000000009; address internal constant L2_STANDARD_BRIDGE = 0x4200000000000000000000000000000000000010; address internal constant SEQUENCER_FEE_WALLET = 0x4200000000000000000000000000000000000011; address internal constant L2_STANDARD_TOKEN_FACTORY = 0x4200000000000000000000000000000000000012; address internal constant L1_BLOCK_NUMBER = 0x4200000000000000000000000000000000000013; address internal constant OVM_GAS_PRICE_ORACLE = 0x420000000000000000000000000000000000000F; address internal constant PROXY__BOBA_TURING_PREPAY = 0x4200000000000000000000000000000000000020; address internal constant BOBA_TURING_PREPAY = 0x4200000000000000000000000000000000000021; address internal constant BOBA_TURING_HELPER = 0x4200000000000000000000000000000000000022; address internal constant PROXY__BOBA_GAS_PRICE_ORACLE = 0x4200000000000000000000000000000000000024; address internal constant BOBA_GAS_PRICE_ORACLE = 0x4200000000000000000000000000000000000025; }
{ "optimizer": { "enabled": true, "runs": 10000 }, "metadata": { "bytecodeHash": "none", "useLiteralContent": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"tokenAddress","type":"address"}],"name":"AddLiquidity","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"receivedAmount","type":"uint256"},{"indexed":false,"internalType":"address","name":"tokenAddress","type":"address"}],"name":"ClientDepositL1","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"l2TokenAddress","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"indexed":false,"internalType":"struct L1LiquidityPool.ClientPayToken[]","name":"_tokens","type":"tuple[]"}],"name":"ClientDepositL1Batch","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"userRewardFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"ownerRewardFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalFee","type":"uint256"},{"indexed":false,"internalType":"address","name":"tokenAddress","type":"address"}],"name":"ClientPayL1","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"userRewardFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"ownerRewardFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalFee","type":"uint256"},{"indexed":false,"internalType":"address","name":"tokenAddress","type":"address"}],"name":"ClientPayL1Settlement","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"tokenAddress","type":"address"}],"name":"OwnerRecoverFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"tokenAddress","type":"address"}],"name":"RebalanceLP","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"tokenAddress","type":"address"}],"name":"WithdrawLiquidity","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"tokenAddress","type":"address"}],"name":"WithdrawReward","type":"event"},{"inputs":[],"name":"L1StandardBridgeAddress","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"L2LiquidityPoolAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SAFE_GAS_STIPEND","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SETTLEMENT_L2_GAS","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_tokenAddress","type":"address"}],"name":"addLiquidity","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_tokenAddress","type":"address"}],"name":"clientDepositL1","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"l1TokenAddress","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct L1LiquidityPool.ClientDepositToken[]","name":"_tokens","type":"tuple[]"}],"name":"clientDepositL1Batch","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address payable","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_tokenAddress","type":"address"}],"name":"clientPayL1","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_tokenAddress","type":"address"}],"name":"clientPayL1Settlement","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_userRewardMinFeeRate","type":"uint256"},{"internalType":"uint256","name":"_userRewardMaxFeeRate","type":"uint256"},{"internalType":"uint256","name":"_ownerRewardFeeRate","type":"uint256"}],"name":"configureFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_l2GasFee","type":"uint32"},{"internalType":"uint256","name":"_safeGas","type":"uint256"}],"name":"configureGas","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"currentDepositInfoHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_l1TokenAddress","type":"address"}],"name":"getUserRewardFeeRate","outputs":[{"internalType":"uint256","name":"userRewardFeeRate","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_l1CrossDomainMessenger","type":"address"},{"internalType":"address","name":"_l1CrossDomainMessengerFast","type":"address"},{"internalType":"address","name":"_L2LiquidityPoolAddress","type":"address"},{"internalType":"address payable","name":"_L1StandardBridgeAddress","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"l1CrossDomainMessenger","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastHashUpdateBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_tokenAddress","type":"address"},{"internalType":"address","name":"_to","type":"address"}],"name":"ownerRecoverFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"ownerRewardFeeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"poolInfo","outputs":[{"internalType":"address","name":"l1TokenAddress","type":"address"},{"internalType":"address","name":"l2TokenAddress","type":"address"},{"internalType":"uint256","name":"userDepositAmount","type":"uint256"},{"internalType":"uint256","name":"lastAccUserReward","type":"uint256"},{"internalType":"uint256","name":"accUserReward","type":"uint256"},{"internalType":"uint256","name":"accUserRewardPerShare","type":"uint256"},{"internalType":"uint256","name":"accOwnerReward","type":"uint256"},{"internalType":"uint256","name":"startTime","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"priorDepositInfoHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_tokenAddress","type":"address"}],"name":"rebalanceLP","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_l1TokenAddress","type":"address"},{"internalType":"address","name":"_l2TokenAddress","type":"address"}],"name":"registerPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"relayerMessenger","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"senderMessenger","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenAddress","type":"address"}],"name":"updateUserRewardPerShare","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"userInfo","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"rewardDebt","type":"uint256"},{"internalType":"uint256","name":"pendingReward","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"userRewardMaxFeeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"userRewardMinFeeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_tokenAddress","type":"address"},{"internalType":"address payable","name":"_to","type":"address"}],"name":"withdrawLiquidity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_tokenAddress","type":"address"},{"internalType":"address","name":"_to","type":"address"}],"name":"withdrawReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
608060405234801561001057600080fd5b50600080546001600160a01b03199081169091556001805490911690556145fc8061003c6000396000f3fe6080604052600436106102385760003560e01c806381e6bdac11610138578063c95f9d0e116100b0578063f2fde38b1161007f578063f72e5aa011610064578063f72e5aa01461073d578063f8c8765e1461075d578063f8fe09a31461077d57600080fd5b8063f2fde38b1461070a578063f64b5f441461072a57600080fd5b8063c95f9d0e14610685578063cf26fb1b14610698578063d04a966a146106b8578063ecb12db0146106ea57600080fd5b80639a7b5f1111610107578063a5ab6190116100ec578063a5ab61901461062f578063a711986914610645578063c58827ea1461066557600080fd5b80639a7b5f111461056b578063a44c80e31461061c57600080fd5b806381e6bdac146104f65780638456cb59146105165780638cac78931461052b5780638da5cb5b1461054b57600080fd5b8063513f3132116101cb57806368be42ca1161019a578063744a5aa21161017f578063744a5aa2146104aa57806377b594a2146104c0578063818c021e146104d657600080fd5b806368be42ca1461046a5780637286e5e51461048a57600080fd5b8063513f3132146103fb57806353174cc11461041157806359326e6f146104315780635c975abb1461044757600080fd5b80633f4ba83a116102075780633f4ba83a1461036e5780633f89e9521461038357806349561dc4146103a3578063508e01c4146103c357600080fd5b80630f208beb146102a357806312f54c1a1461030a578063358fc07e1461032a578063369fd1021461034e57600080fd5b3661029e5760a1546001600160a01b0316331461029c5760405162461bcd60e51b815260206004820152601160248201527f43616e277420726563656976652045544800000000000000000000000000000060448201526064015b60405180910390fd5b005b600080fd5b3480156102af57600080fd5b506102ea6102be366004614017565b609960209081526000928352604080842090915290825290208054600182015460029092015490919083565b604080519384526020840192909252908201526060015b60405180910390f35b34801561031657600080fd5b5061029c610325366004614050565b610793565b34801561033657600080fd5b50610340609d5481565b604051908152602001610301565b34801561035a57600080fd5b5061029c61036936600461406d565b610829565b34801561037a57600080fd5b5061029c610950565b34801561038f57600080fd5b5061029c61039e3660046140a2565b6109c8565b3480156103af57600080fd5b5061029c6103be3660046140c7565b610e8b565b3480156103cf57600080fd5b506000546103e3906001600160a01b031681565b6040516001600160a01b039091168152602001610301565b34801561040757600080fd5b50610340609f5481565b34801561041d57600080fd5b5061029c61042c366004614109565b61114a565b34801561043d57600080fd5b5061034060a55481565b34801561045357600080fd5b5060665460ff166040519015158152602001610301565b34801561047657600080fd5b5061029c6104853660046140c7565b611521565b34801561049657600080fd5b5061029c6104a5366004614017565b6117f7565b3480156104b657600080fd5b5061034060a25481565b3480156104cc57600080fd5b50610340609c5481565b3480156104e257600080fd5b506001546103e3906001600160a01b031681565b34801561050257600080fd5b5061029c6105113660046140c7565b611aa3565b34801561052257600080fd5b5061029c611d0b565b34801561053757600080fd5b5060a1546103e3906001600160a01b031681565b34801561055757600080fd5b50609a546103e3906001600160a01b031681565b34801561057757600080fd5b506105d6610586366004614050565b609860205260009081526040902080546001820154600283015460038401546004850154600586015460068701546007909701546001600160a01b03968716979590961695939492939192909188565b604080516001600160a01b03998a168152989097166020890152958701949094526060860192909252608085015260a084015260c083015260e082015261010001610301565b61029c61062a366004614140565b611d81565b34801561063b57600080fd5b5061034060a45481565b34801561065157600080fd5b5060a0546103e3906001600160a01b031681565b34801561067157600080fd5b5061029c6106803660046141b5565b6121a6565b61029c6106933660046140a2565b6122f6565b3480156106a457600080fd5b5061029c6106b3366004614109565b612674565b3480156106c457600080fd5b50609e546106d59063ffffffff1681565b60405163ffffffff9091168152602001610301565b3480156106f657600080fd5b50610340610705366004614050565b612bcf565b34801561071657600080fd5b5061029c610725366004614050565b612d7c565b61029c6107383660046140a2565b612ed1565b34801561074957600080fd5b50609b546103e3906001600160a01b031681565b34801561076957600080fd5b5061029c6107783660046141e1565b6131c6565b34801561078957600080fd5b5061034060a35481565b6001600160a01b03811660009081526098602052604090206004810154600382015410156108255760006107d8826003015483600401546134ff90919063ffffffff16565b9050816002015460001461081957600282015461081390610808906108028464e8d4a51000613512565b9061351e565b60058401549061352a565b60058301555b50600481015460038201555b5050565b609a546001600160a01b031633148061084b5750609a546001600160a01b0316155b6108975760405162461bcd60e51b815260206004820152601760248201527f43616c6c6572206973206e6f7420746865206f776e65720000000000000000006044820152606401610293565b609b546001600160a01b03166109155760405162461bcd60e51b815260206004820152602560248201527f436f6e747261637420686173206e6f7420796574206265656e20696e6974696160448201527f6c697a65640000000000000000000000000000000000000000000000000000006064820152608401610293565b609e80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff9390931692909217909155609f55565b609a546001600160a01b03163314806109725750609a546001600160a01b0316155b6109be5760405162461bcd60e51b815260206004820152601760248201527f43616c6c6572206973206e6f7420746865206f776e65720000000000000000006044820152606401610293565b6109c6613536565b565b609a546001600160a01b03163314806109ea5750609a546001600160a01b0316155b610a365760405162461bcd60e51b815260206004820152601760248201527f43616c6c6572206973206e6f7420746865206f776e65720000000000000000006044820152606401610293565b60665460ff1615610a895760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610293565b81610ad65760405162461bcd60e51b815260206004820152601060248201527f416d6f756e7420496e636f7272656374000000000000000000000000000000006044820152606401610293565b6001600160a01b038082166000908152609860205260409020609b54909116610b415760405162461bcd60e51b815260206004820181905260248201527f4c32204c697175696469747920506f6f6c204e6f7420526567697374657265646044820152606401610293565b60018101546001600160a01b0316610b9b5760405162461bcd60e51b815260206004820152601c60248201527f546f6b656e2041646472657373204e6f742052656769737465726564000000006044820152606401610293565b604080518481526001600160a01b03841660208201527f40637a7e139eeb28b936b8decebe78604164b2ade81ce7f4c70deb132e7614c2910160405180910390a16001600160a01b038216610cd95747831115610c3a5760405162461bcd60e51b815260206004820152601660248201527f4661696c656420746f20526562616c616e6365204c50000000000000000000006044820152606401610293565b60a154609b54609e546040517f50cc72d20000000000000000000000000000000000000000000000000000000081526001600160a01b03928316600482015263ffffffff909116602482015260606044820152600060648201529116906350cc72d29085906084016000604051808303818588803b158015610cbb57600080fd5b505af1158015610ccf573d6000803e3d6000fd5b5050505050505050565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038316906370a082319060240160206040518083038186803b158015610d3157600080fd5b505afa158015610d45573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d69919061423d565b831115610db85760405162461bcd60e51b815260206004820152601660248201527f4661696c656420746f20526562616c616e6365204c50000000000000000000006044820152606401610293565b60a154610dd2906001600160a01b038481169116856135f0565b60a1546001820154609b54609e546040517f838b25200000000000000000000000000000000000000000000000000000000081526001600160a01b038781166004830152938416602482015291831660448301526064820187905263ffffffff16608482015260c060a4820152600060c482015291169063838b25209060e4015b600060405180830381600087803b158015610e6d57600080fd5b505af1158015610e81573d6000803e3d6000fd5b505050505b505050565b60665460ff1615610ede5760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610293565b6001600160a01b0380831660009081526098602090815260408083206099835281842033855290925290912060018201549192909116610f605760405162461bcd60e51b815260206004820152601c60248201527f546f6b656e2041646472657373204e6f742052656769737465726564000000006044820152606401610293565b6000610fa2610f978360010154610f9164e8d4a510006108028860050154886000015461351290919063ffffffff16565b906134ff565b60028401549061352a565b905085811015610ff45760405162461bcd60e51b815260206004820152601560248201527f576974686472617720526577617264204572726f7200000000000000000000006044820152606401610293565b610ffe81876134ff565b60028301556005830154825461101e9164e8d4a510009161080291613512565b6001830155604080513381526001600160a01b0386811660208301528183018990528716606082015290517f3cb7cb475a33eda02ee6e719b6c2fc0c899157cfc6f098daf545354dbbce41ec9181900360800190a16001600160a01b0385161561109b576110966001600160a01b0386168588613761565b611142565b6000846001600160a01b0316609f5488604051600060405180830381858888f193505050503d80600081146110ec576040519150601f19603f3d011682016040523d82523d6000602084013e6110f1565b606091505b5050905080610e815760405162461bcd60e51b815260206004820152601460248201527f4661696c656420746f2073656e642045746865720000000000000000000000006044820152606401610293565b505050505050565b609b546001600160a01b03166111686001546001600160a01b031690565b6001600160a01b0316336001600160a01b0316146111ee5760405162461bcd60e51b815260206004820152602a60248201527f58434841494e3a206d657373656e67657220636f6e747261637420756e61757460448201527f68656e74696361746564000000000000000000000000000000000000000000006064820152608401610293565b806001600160a01b031661120a6001546001600160a01b031690565b6001600160a01b0316636e296e456040518163ffffffff1660e01b815260040160206040518083038186803b15801561124257600080fd5b505afa158015611256573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061127a9190614256565b6001600160a01b0316146112f65760405162461bcd60e51b815260206004820152602c60248201527f58434841494e3a2077726f6e672073656e646572206f662063726f73732d646f60448201527f6d61696e206d65737361676500000000000000000000000000000000000000006064820152608401610293565b60665460ff16156113495760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610293565b6001600160a01b03821660009081526098602052604081209061136b84612bcf565b9050600061137f6103e86108028885613512565b9050600061139e6103e8610802609d548a61351290919063ffffffff16565b905060006113ac838361352a565b905060006113ba89836134ff565b60048701549091506113cc908561352a565b600487015560068601546113e0908461352a565b6006870155604080516001600160a01b038c811682526020820184905281830187905260608201869052608082018590528a1660a082015290517fe42a885e97ef72aed483b57141e41f9d64499b43411f58b60a0e07fcdb6e824a9181900360c00190a16001600160a01b0388161561146c576114676001600160a01b0389168b83613761565b611515565b60008a6001600160a01b0316609f5483604051600060405180830381858888f193505050503d80600081146114bd576040519150601f19603f3d011682016040523d82523d6000602084013e6114c2565b606091505b50509050806115135760405162461bcd60e51b815260206004820152601460248201527f4661696c656420746f2073656e642045746865720000000000000000000000006044820152606401610293565b505b50505050505050505050565b60665460ff16156115745760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610293565b6001600160a01b03808316600090815260986020908152604080832060998352818420338552909252909120600182015491929091166115f65760405162461bcd60e51b815260206004820152601c60248201527f546f6b656e2041646472657373204e6f742052656769737465726564000000006044820152606401610293565b80548511156116475760405162461bcd60e51b815260206004820152600e60248201527f5769746864726177204572726f720000000000000000000000000000000000006044820152606401610293565b61165084610793565b61168a61167f8260010154610f9164e8d4a510006108028760050154876000015461351290919063ffffffff16565b60028301549061352a565b6002820155805461169b90866134ff565b80825560058301546116b89164e8d4a51000916108029190613512565b600182015560028201546116cc90866134ff565b6002830155604080513381526001600160a01b0385811660208301528183018890528616606082015290517ffa2e8fcf14fd6ea11b6ebe7caf7de210198b8fe1eaf0e06d19f8d87c73860c469181900360800190a16001600160a01b03841615611749576117446001600160a01b0385168487613761565b6117f0565b6000836001600160a01b0316609f5487604051600060405180830381858888f193505050503d806000811461179a576040519150601f19603f3d011682016040523d82523d6000602084013e61179f565b606091505b50509050806111425760405162461bcd60e51b815260206004820152601260248201527f4661696c656420746f2073656e642045544800000000000000000000000000006044820152606401610293565b5050505050565b609a546001600160a01b03163314806118195750609a546001600160a01b0316155b6118655760405162461bcd60e51b815260206004820152601760248201527f43616c6c6572206973206e6f7420746865206f776e65720000000000000000006044820152606401610293565b806001600160a01b0316826001600160a01b031614156118ed5760405162461bcd60e51b815260206004820152602860248201527f6c3120616e64206c3220746f6b656e206164647265737365732063616e6e6f7460448201527f2062652073616d650000000000000000000000000000000000000000000000006064820152608401610293565b6001600160a01b0381166119695760405162461bcd60e51b815260206004820152602760248201527f6c3220746f6b656e20616464726573732063616e6e6f74206265207a65726f2060448201527f61646472657373000000000000000000000000000000000000000000000000006064820152608401610293565b6001600160a01b0380831660009081526098602052604090206001810154909116156119d75760405162461bcd60e51b815260206004820181905260248201527f546f6b656e204164647265737320416c726561647920526567697374657265646044820152606401610293565b5060408051610100810182526001600160a01b0393841680825292841660208083019182526000838501818152606085018281526080860183815260a0870184815260c088018581524260e08a019081529a865260989096529790932095518654908a167fffffffffffffffffffffffff0000000000000000000000000000000000000000918216178755945160018701805491909a16951694909417909755955160028401559051600383015593516004820155905160058201559151600683015551600790910155565b609a546001600160a01b0316331480611ac55750609a546001600160a01b0316155b611b115760405162461bcd60e51b815260206004820152601760248201527f43616c6c6572206973206e6f7420746865206f776e65720000000000000000006044820152606401610293565b6001600160a01b0380831660009081526098602052604090206001810154909116611b7e5760405162461bcd60e51b815260206004820152601c60248201527f546f6b656e2041646472657373204e6f742052656769737465726564000000006044820152606401610293565b8381600601541015611bd25760405162461bcd60e51b815260206004820152601b60248201527f4f776e657220526577617264205769746864726177204572726f7200000000006044820152606401610293565b6006810154611be190856134ff565b6006820155604080513381526001600160a01b0384811660208301528183018790528516606082015290517f3cb71b9a1fb601579f96812b9f86ab5e914fc3e54c98d5f84d95581b2b9884f39181900360800190a16001600160a01b03831615611c5e57611c596001600160a01b0384168386613761565b611d05565b6000826001600160a01b0316609f5486604051600060405180830381858888f193505050503d8060008114611caf576040519150601f19603f3d011682016040523d82523d6000602084013e611cb4565b606091505b50509050806117f05760405162461bcd60e51b815260206004820152601460248201527f4661696c656420746f2073656e642045746865720000000000000000000000006044820152606401610293565b50505050565b609a546001600160a01b0316331480611d2d5750609a546001600160a01b0316155b611d795760405162461bcd60e51b815260206004820152601760248201527f43616c6c6572206973206e6f7420746865206f776e65720000000000000000006044820152606401610293565b6109c66137aa565b60665460ff1615611dd45760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610293565b60058110611e245760405162461bcd60e51b815260206004820152600f60248201527f546f6f204d616e7920546f6b656e7300000000000000000000000000000000006044820152606401610293565b6000808267ffffffffffffffff811115611e4057611e40614273565b604051908082528060200260200182016040528015611ea957816020015b60408051606081018252600080825260208083018290529282015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff909201910181611e5e5790505b50905060005b83811015612050576000858583818110611ecb57611ecb6142a2565b905060400201803603810190611ee191906142d1565b9050806020015160001415611f385760405162461bcd60e51b815260206004820152600e60248201527f496e76616c696420416d6f756e740000000000000000000000000000000000006044820152606401610293565b80516001600160a01b0390811660009081526098602052604090206001810154909116611fa75760405162461bcd60e51b815260206004820152600d60248201527f496e7661696c6420546f6b656e000000000000000000000000000000000000006044820152606401610293565b81516001600160a01b031615611fdc5760208201518251611fd7916001600160a01b039091169033903090613850565b611fee565b6020820151611feb908661437f565b94505b6040805160608101825233815260018301546001600160a01b0316602080830191909152840151918101919091528451859085908110612030576120306142a2565b60200260200101819052505050808061204890614397565b915050611eaf565b503482146120a05760405162461bcd60e51b815260206004820152601260248201527f496e76616c69642045544820416d6f756e7400000000000000000000000000006044820152606401610293565b600063b4eeb98860e01b826040516024016120bb91906143d0565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152609b54609e54919250612168916001600160a01b03909116906121629063ffffffff166002614435565b836138a1565b7f1a79d691d0cd9e7c4f70b52af899cfc71146947ba0fa6fc236e2649c07a8e9128260405161219791906143d0565b60405180910390a15050505050565b609a546001600160a01b03163314806121c85750609a546001600160a01b0316155b6122145760405162461bcd60e51b815260206004820152601760248201527f43616c6c6572206973206e6f7420746865206f776e65720000000000000000006044820152606401610293565b609b546001600160a01b03166122925760405162461bcd60e51b815260206004820152602560248201527f436f6e747261637420686173206e6f7420796574206265656e20696e6974696160448201527f6c697a65640000000000000000000000000000000000000000000000000000006064820152608401610293565b818311156122e25760405162461bcd60e51b815260206004820152601760248201527f496e76616c7564207573657220726577617264206665650000000000000000006044820152606401610293565b610e86838383609c9290925560a255609d55565b6002805414156123485760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610293565b6002805560665460ff161561239f5760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610293565b341515806123b557506001600160a01b03811615155b6124275760405162461bcd60e51b815260206004820152603260248201527f45697468657220416d6f756e7420496e636f7272656374206f7220546f6b656e60448201527f204164647265737320496e636f727265637400000000000000000000000000006064820152608401610293565b341580159061243e57506001600160a01b03811615155b156124b15760405162461bcd60e51b815260206004820152603260248201527f45697468657220416d6f756e7420496e636f7272656374206f7220546f6b656e60448201527f204164647265737320496e636f727265637400000000000000000000000000006064820152608401610293565b34156124be575034905060005b6001600160a01b03808216600090815260986020908152604080832060998352818420338552909252909120600182015491929091166125405760405162461bcd60e51b815260206004820152601c60248201527f546f6b656e2041646472657373204e6f742052656769737465726564000000006044820152606401610293565b61254983610793565b8054156125b55761257f61167f8260010154610f9164e8d4a510006108028760050154876000015461351290919063ffffffff16565b6002820155600582015481546125ab9164e8d4a510009161080291906125a5908961352a565b90613512565b60018201556125db565b6125d564e8d4a5100061080284600501548761351290919063ffffffff16565b60018201555b80546125e7908561352a565b815560028201546125f8908561352a565b600283015560408051338152602081018690526001600160a01b0385168183015290517f5852d1d46e583f7e92c2a572221de0e681d82ef71f489847e056b9445c0147369181900360600190a16001600160a01b03831615612669576126696001600160a01b038416333087613850565b505060016002555050565b609b546001600160a01b03166126926001546001600160a01b031690565b6001600160a01b0316336001600160a01b0316146127185760405162461bcd60e51b815260206004820152602a60248201527f58434841494e3a206d657373656e67657220636f6e747261637420756e61757460448201527f68656e74696361746564000000000000000000000000000000000000000000006064820152608401610293565b806001600160a01b03166127346001546001600160a01b031690565b6001600160a01b0316636e296e456040518163ffffffff1660e01b815260040160206040518083038186803b15801561276c57600080fd5b505afa158015612780573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127a49190614256565b6001600160a01b0316146128205760405162461bcd60e51b815260206004820152602c60248201527f58434841494e3a2077726f6e672073656e646572206f662063726f73732d646f60448201527f6d61696e206d65737361676500000000000000000000000000000000000000006064820152608401610293565b60665460ff16156128735760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610293565b6001600160a01b03821660009081526098602052604081208161289585612bcf565b905060006128a96103e86108028985613512565b905060006128c86103e8610802609d548b61351290919063ffffffff16565b905060006128d6838361352a565b905060006128e48a836134ff565b90506001600160a01b038916156129d6576040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038a16906370a082319060240160206040518083038186803b15801561294d57600080fd5b505afa158015612961573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612985919061423d565b8111156129955760019650612ab6565b60048601546129a4908561352a565b600487015560068601546129b8908461352a565b60068701556129d16001600160a01b038a168c83613761565b612ab6565b478111156129e75760019650612ab6565b60048601546129f6908561352a565b60048701556006860154612a0a908461352a565b6006870155609f546040516000916001600160a01b038e1691849084818181858888f193505050503d8060008114612a5e576040519150601f19603f3d011682016040523d82523d6000602084013e612a63565b606091505b5050905080612ab45760405162461bcd60e51b815260206004820152601260248201527f4661696c656420746f2073656e642045544800000000000000000000000000006044820152606401610293565b505b8615612b63576001860154604080516001600160a01b038e81166024830152604482018e90529283166064808301919091528251808303909101815260849091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f650a767b00000000000000000000000000000000000000000000000000000000179052609b54609e549192612b5d9291169063ffffffff16836138a1565b50611513565b604080516001600160a01b038d811682526020820184905281830187905260608201869052608082018590528b1660a082015290517ffe1f8646fcb202e48551fbfd19085116c64b291c60cede7dce3665a57c05e3819181900360c00190a15050505050505050505050565b609b546000906001600160a01b0316612c505760405162461bcd60e51b815260206004820152602560248201527f436f6e747261637420686173206e6f7420796574206265656e20696e6974696160448201527f6c697a65640000000000000000000000000000000000000000000000000000006064820152608401610293565b6001600160a01b038216600081815260986020526040812060028101549092909190612c7d575047612d10565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038616906370a082319060240160206040518083038186803b158015612cd557600080fd5b505afa158015612ce9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d0d919061423d565b90505b80612d2157505060a2549392505050565b60008183609c54612d329190614461565b612d3c919061449e565b905080609c541115612d55575050609c54949350505050565b8060a2541015612d6c57505060a254949350505050565b9350612d7792505050565b919050565b609a546001600160a01b0316331480612d9e5750609a546001600160a01b0316155b612dea5760405162461bcd60e51b815260206004820152601760248201527f43616c6c6572206973206e6f7420746865206f776e65720000000000000000006044820152606401610293565b6001600160a01b038116612e655760405162461bcd60e51b8152602060048201526024808201527f4e6577206f776e65722063616e6e6f7420626520746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152608401610293565b609a80547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040519081527f04dba622d284ed0014ee4b9a6a68386be1a4c08a4913ae272de89199cc6861639060200160405180910390a150565b60665460ff1615612f245760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610293565b34151580612f3a57506001600160a01b03811615155b612fac5760405162461bcd60e51b815260206004820152603260248201527f45697468657220416d6f756e7420496e636f7272656374206f7220546f6b656e60448201527f204164647265737320496e636f727265637400000000000000000000000000006064820152608401610293565b3415801590612fc357506001600160a01b03811615155b156130365760405162461bcd60e51b815260206004820152603260248201527f45697468657220416d6f756e7420496e636f7272656374206f7220546f6b656e60448201527f204164647265737320496e636f727265637400000000000000000000000000006064820152608401610293565b3415613043575034905060005b6001600160a01b03808216600090815260986020526040902060018101549091166130b05760405162461bcd60e51b815260206004820152601c60248201527f546f6b656e2041646472657373204e6f742052656769737465726564000000006044820152606401610293565b6130bb8233856138ee565b60408051338152602081018590526001600160a01b0384168183015290517f860e25c3d48fb81f0b272550dd125a5a6ab20ee7511dd3e250d04964bd37a7a99181900360600190a16001600160a01b03821615613127576131276001600160a01b038316333086613850565b600181015460408051336024820152604481018690526001600160a01b039283166064808301919091528251808303909101815260849091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fbd2d1cab00000000000000000000000000000000000000000000000000000000179052609b54609e549192611d059291169063ffffffff16836138a1565b609a546001600160a01b03163314806131e85750609a546001600160a01b0316155b6132345760405162461bcd60e51b815260206004820152601760248201527f43616c6c6572206973206e6f7420746865206f776e65720000000000000000006044820152606401610293565b609b546001600160a01b03161561328d5760405162461bcd60e51b815260206004820152601d60248201527f436f6e747261637420686173206265656e20696e697469616c697a65640000006044820152606401610293565b6001547501000000000000000000000000000000000000000000900460ff16806132d2575060015474010000000000000000000000000000000000000000900460ff16155b6133445760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610293565b6001547501000000000000000000000000000000000000000000900460ff161580156133ab57600180547fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff1675010100000000000000000000000000000000000000001790555b6001600160a01b038516158015906133cb57506001600160a01b03841615155b80156133df57506001600160a01b03831615155b61342b5760405162461bcd60e51b815260206004820152601860248201527f7a65726f2061646472657373206e6f7420616c6c6f77656400000000000000006044820152606401610293565b600080546001600160a01b038781167fffffffffffffffffffffffff000000000000000000000000000000000000000092831617835560018054888316908416179055609b805487831690841617905560a18054918616918316919091179055609a8054909116331790556005609c55603260a255609d556134b2620aae606108fc610829565b6134ba613973565b6134c2613ac3565b6134ca613c3a565b80156117f057600180547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff1690555050505050565b600061350b82846144d9565b9392505050565b600061350b8284614461565b600061350b828461449e565b600061350b828461437f565b60665460ff166135885760405162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401610293565b606680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6040517fdd62ed3e0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038381166024830152600091839186169063dd62ed3e9060440160206040518083038186803b15801561365557600080fd5b505afa158015613669573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061368d919061423d565b613697919061437f565b6040516001600160a01b038516602482015260448101829052909150611d059085907f095ea7b300000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152613d8e565b6040516001600160a01b038316602482015260448101829052610e869084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064016136df565b60665460ff16156137fd5760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610293565b606680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586135d33390565b6040516001600160a01b0380851660248301528316604482015260648101829052611d059085907f23b872dd00000000000000000000000000000000000000000000000000000000906084016136df565b6000546040517f3dbb202b0000000000000000000000000000000000000000000000000000000081526001600160a01b0390911690633dbb202b90610e5390869085908790600401614566565b60a5544311156138ff5760a45460a3555b60a4546040805160208101929092526001600160a01b0380861691830191909152831660608201526080810182905260a001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052805160209091012060a45550504360a55550565b6001547501000000000000000000000000000000000000000000900460ff16806139b8575060015474010000000000000000000000000000000000000000900460ff16155b613a2a5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610293565b6001547501000000000000000000000000000000000000000000900460ff16158015613a9157600180547fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff1675010100000000000000000000000000000000000000001790555b8015613ac057600180547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff1690555b50565b6001547501000000000000000000000000000000000000000000900460ff1680613b08575060015474010000000000000000000000000000000000000000900460ff16155b613b7a5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610293565b6001547501000000000000000000000000000000000000000000900460ff16158015613be157600180547fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff1675010100000000000000000000000000000000000000001790555b606680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690558015613ac057600180547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff16905550565b6001547501000000000000000000000000000000000000000000900460ff1680613c7f575060015474010000000000000000000000000000000000000000900460ff16155b613cf15760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610293565b6001547501000000000000000000000000000000000000000000900460ff16158015613d5857600180547fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff1675010100000000000000000000000000000000000000001790555b60016002558015613ac057600180547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff16905550565b6000613de3826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316613e739092919063ffffffff16565b805190915015610e865780806020019051810190613e01919061459e565b610e865760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610293565b6060613e828484600085613e8a565b949350505050565b606082471015613f025760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610293565b843b613f505760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610293565b600080866001600160a01b03168587604051613f6c91906145c0565b60006040518083038185875af1925050503d8060008114613fa9576040519150601f19603f3d011682016040523d82523d6000602084013e613fae565b606091505b5091509150613fbe828286613fc9565b979650505050505050565b60608315613fd857508161350b565b825115613fe85782518084602001fd5b8160405162461bcd60e51b815260040161029391906145dc565b6001600160a01b0381168114613ac057600080fd5b6000806040838503121561402a57600080fd5b823561403581614002565b9150602083013561404581614002565b809150509250929050565b60006020828403121561406257600080fd5b813561350b81614002565b6000806040838503121561408057600080fd5b823563ffffffff8116811461409457600080fd5b946020939093013593505050565b600080604083850312156140b557600080fd5b82359150602083013561404581614002565b6000806000606084860312156140dc57600080fd5b8335925060208401356140ee81614002565b915060408401356140fe81614002565b809150509250925092565b60008060006060848603121561411e57600080fd5b833561412981614002565b92506020840135915060408401356140fe81614002565b6000806020838503121561415357600080fd5b823567ffffffffffffffff8082111561416b57600080fd5b818501915085601f83011261417f57600080fd5b81358181111561418e57600080fd5b8660208260061b85010111156141a357600080fd5b60209290920196919550909350505050565b6000806000606084860312156141ca57600080fd5b505081359360208301359350604090920135919050565b600080600080608085870312156141f757600080fd5b843561420281614002565b9350602085013561421281614002565b9250604085013561422281614002565b9150606085013561423281614002565b939692955090935050565b60006020828403121561424f57600080fd5b5051919050565b60006020828403121561426857600080fd5b815161350b81614002565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6000604082840312156142e357600080fd5b6040516040810181811067ffffffffffffffff8211171561432d577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604052823561433b81614002565b81526020928301359281019290925250919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000821982111561439257614392614350565b500190565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8214156143c9576143c9614350565b5060010190565b602080825282518282018190526000919060409081850190868401855b8281101561442857815180516001600160a01b03908116865287820151168786015285015185850152606090930192908501906001016143ed565b5091979650505050505050565b600063ffffffff8083168185168183048111821515161561445857614458614350565b02949350505050565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561449957614499614350565b500290565b6000826144d4577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b6000828210156144eb576144eb614350565b500390565b60005b8381101561450b5781810151838201526020016144f3565b83811115611d055750506000910152565b600081518084526145348160208601602086016144f0565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6001600160a01b0384168152606060208201526000614588606083018561451c565b905063ffffffff83166040830152949350505050565b6000602082840312156145b057600080fd5b8151801515811461350b57600080fd5b600082516145d28184602087016144f0565b9190910192915050565b60208152600061350b602083018461451c56fea164736f6c6343000809000a
Deployed Bytecode
0x6080604052600436106102385760003560e01c806381e6bdac11610138578063c95f9d0e116100b0578063f2fde38b1161007f578063f72e5aa011610064578063f72e5aa01461073d578063f8c8765e1461075d578063f8fe09a31461077d57600080fd5b8063f2fde38b1461070a578063f64b5f441461072a57600080fd5b8063c95f9d0e14610685578063cf26fb1b14610698578063d04a966a146106b8578063ecb12db0146106ea57600080fd5b80639a7b5f1111610107578063a5ab6190116100ec578063a5ab61901461062f578063a711986914610645578063c58827ea1461066557600080fd5b80639a7b5f111461056b578063a44c80e31461061c57600080fd5b806381e6bdac146104f65780638456cb59146105165780638cac78931461052b5780638da5cb5b1461054b57600080fd5b8063513f3132116101cb57806368be42ca1161019a578063744a5aa21161017f578063744a5aa2146104aa57806377b594a2146104c0578063818c021e146104d657600080fd5b806368be42ca1461046a5780637286e5e51461048a57600080fd5b8063513f3132146103fb57806353174cc11461041157806359326e6f146104315780635c975abb1461044757600080fd5b80633f4ba83a116102075780633f4ba83a1461036e5780633f89e9521461038357806349561dc4146103a3578063508e01c4146103c357600080fd5b80630f208beb146102a357806312f54c1a1461030a578063358fc07e1461032a578063369fd1021461034e57600080fd5b3661029e5760a1546001600160a01b0316331461029c5760405162461bcd60e51b815260206004820152601160248201527f43616e277420726563656976652045544800000000000000000000000000000060448201526064015b60405180910390fd5b005b600080fd5b3480156102af57600080fd5b506102ea6102be366004614017565b609960209081526000928352604080842090915290825290208054600182015460029092015490919083565b604080519384526020840192909252908201526060015b60405180910390f35b34801561031657600080fd5b5061029c610325366004614050565b610793565b34801561033657600080fd5b50610340609d5481565b604051908152602001610301565b34801561035a57600080fd5b5061029c61036936600461406d565b610829565b34801561037a57600080fd5b5061029c610950565b34801561038f57600080fd5b5061029c61039e3660046140a2565b6109c8565b3480156103af57600080fd5b5061029c6103be3660046140c7565b610e8b565b3480156103cf57600080fd5b506000546103e3906001600160a01b031681565b6040516001600160a01b039091168152602001610301565b34801561040757600080fd5b50610340609f5481565b34801561041d57600080fd5b5061029c61042c366004614109565b61114a565b34801561043d57600080fd5b5061034060a55481565b34801561045357600080fd5b5060665460ff166040519015158152602001610301565b34801561047657600080fd5b5061029c6104853660046140c7565b611521565b34801561049657600080fd5b5061029c6104a5366004614017565b6117f7565b3480156104b657600080fd5b5061034060a25481565b3480156104cc57600080fd5b50610340609c5481565b3480156104e257600080fd5b506001546103e3906001600160a01b031681565b34801561050257600080fd5b5061029c6105113660046140c7565b611aa3565b34801561052257600080fd5b5061029c611d0b565b34801561053757600080fd5b5060a1546103e3906001600160a01b031681565b34801561055757600080fd5b50609a546103e3906001600160a01b031681565b34801561057757600080fd5b506105d6610586366004614050565b609860205260009081526040902080546001820154600283015460038401546004850154600586015460068701546007909701546001600160a01b03968716979590961695939492939192909188565b604080516001600160a01b03998a168152989097166020890152958701949094526060860192909252608085015260a084015260c083015260e082015261010001610301565b61029c61062a366004614140565b611d81565b34801561063b57600080fd5b5061034060a45481565b34801561065157600080fd5b5060a0546103e3906001600160a01b031681565b34801561067157600080fd5b5061029c6106803660046141b5565b6121a6565b61029c6106933660046140a2565b6122f6565b3480156106a457600080fd5b5061029c6106b3366004614109565b612674565b3480156106c457600080fd5b50609e546106d59063ffffffff1681565b60405163ffffffff9091168152602001610301565b3480156106f657600080fd5b50610340610705366004614050565b612bcf565b34801561071657600080fd5b5061029c610725366004614050565b612d7c565b61029c6107383660046140a2565b612ed1565b34801561074957600080fd5b50609b546103e3906001600160a01b031681565b34801561076957600080fd5b5061029c6107783660046141e1565b6131c6565b34801561078957600080fd5b5061034060a35481565b6001600160a01b03811660009081526098602052604090206004810154600382015410156108255760006107d8826003015483600401546134ff90919063ffffffff16565b9050816002015460001461081957600282015461081390610808906108028464e8d4a51000613512565b9061351e565b60058401549061352a565b60058301555b50600481015460038201555b5050565b609a546001600160a01b031633148061084b5750609a546001600160a01b0316155b6108975760405162461bcd60e51b815260206004820152601760248201527f43616c6c6572206973206e6f7420746865206f776e65720000000000000000006044820152606401610293565b609b546001600160a01b03166109155760405162461bcd60e51b815260206004820152602560248201527f436f6e747261637420686173206e6f7420796574206265656e20696e6974696160448201527f6c697a65640000000000000000000000000000000000000000000000000000006064820152608401610293565b609e80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000001663ffffffff9390931692909217909155609f55565b609a546001600160a01b03163314806109725750609a546001600160a01b0316155b6109be5760405162461bcd60e51b815260206004820152601760248201527f43616c6c6572206973206e6f7420746865206f776e65720000000000000000006044820152606401610293565b6109c6613536565b565b609a546001600160a01b03163314806109ea5750609a546001600160a01b0316155b610a365760405162461bcd60e51b815260206004820152601760248201527f43616c6c6572206973206e6f7420746865206f776e65720000000000000000006044820152606401610293565b60665460ff1615610a895760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610293565b81610ad65760405162461bcd60e51b815260206004820152601060248201527f416d6f756e7420496e636f7272656374000000000000000000000000000000006044820152606401610293565b6001600160a01b038082166000908152609860205260409020609b54909116610b415760405162461bcd60e51b815260206004820181905260248201527f4c32204c697175696469747920506f6f6c204e6f7420526567697374657265646044820152606401610293565b60018101546001600160a01b0316610b9b5760405162461bcd60e51b815260206004820152601c60248201527f546f6b656e2041646472657373204e6f742052656769737465726564000000006044820152606401610293565b604080518481526001600160a01b03841660208201527f40637a7e139eeb28b936b8decebe78604164b2ade81ce7f4c70deb132e7614c2910160405180910390a16001600160a01b038216610cd95747831115610c3a5760405162461bcd60e51b815260206004820152601660248201527f4661696c656420746f20526562616c616e6365204c50000000000000000000006044820152606401610293565b60a154609b54609e546040517f50cc72d20000000000000000000000000000000000000000000000000000000081526001600160a01b03928316600482015263ffffffff909116602482015260606044820152600060648201529116906350cc72d29085906084016000604051808303818588803b158015610cbb57600080fd5b505af1158015610ccf573d6000803e3d6000fd5b5050505050505050565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038316906370a082319060240160206040518083038186803b158015610d3157600080fd5b505afa158015610d45573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d69919061423d565b831115610db85760405162461bcd60e51b815260206004820152601660248201527f4661696c656420746f20526562616c616e6365204c50000000000000000000006044820152606401610293565b60a154610dd2906001600160a01b038481169116856135f0565b60a1546001820154609b54609e546040517f838b25200000000000000000000000000000000000000000000000000000000081526001600160a01b038781166004830152938416602482015291831660448301526064820187905263ffffffff16608482015260c060a4820152600060c482015291169063838b25209060e4015b600060405180830381600087803b158015610e6d57600080fd5b505af1158015610e81573d6000803e3d6000fd5b505050505b505050565b60665460ff1615610ede5760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610293565b6001600160a01b0380831660009081526098602090815260408083206099835281842033855290925290912060018201549192909116610f605760405162461bcd60e51b815260206004820152601c60248201527f546f6b656e2041646472657373204e6f742052656769737465726564000000006044820152606401610293565b6000610fa2610f978360010154610f9164e8d4a510006108028860050154886000015461351290919063ffffffff16565b906134ff565b60028401549061352a565b905085811015610ff45760405162461bcd60e51b815260206004820152601560248201527f576974686472617720526577617264204572726f7200000000000000000000006044820152606401610293565b610ffe81876134ff565b60028301556005830154825461101e9164e8d4a510009161080291613512565b6001830155604080513381526001600160a01b0386811660208301528183018990528716606082015290517f3cb7cb475a33eda02ee6e719b6c2fc0c899157cfc6f098daf545354dbbce41ec9181900360800190a16001600160a01b0385161561109b576110966001600160a01b0386168588613761565b611142565b6000846001600160a01b0316609f5488604051600060405180830381858888f193505050503d80600081146110ec576040519150601f19603f3d011682016040523d82523d6000602084013e6110f1565b606091505b5050905080610e815760405162461bcd60e51b815260206004820152601460248201527f4661696c656420746f2073656e642045746865720000000000000000000000006044820152606401610293565b505050505050565b609b546001600160a01b03166111686001546001600160a01b031690565b6001600160a01b0316336001600160a01b0316146111ee5760405162461bcd60e51b815260206004820152602a60248201527f58434841494e3a206d657373656e67657220636f6e747261637420756e61757460448201527f68656e74696361746564000000000000000000000000000000000000000000006064820152608401610293565b806001600160a01b031661120a6001546001600160a01b031690565b6001600160a01b0316636e296e456040518163ffffffff1660e01b815260040160206040518083038186803b15801561124257600080fd5b505afa158015611256573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061127a9190614256565b6001600160a01b0316146112f65760405162461bcd60e51b815260206004820152602c60248201527f58434841494e3a2077726f6e672073656e646572206f662063726f73732d646f60448201527f6d61696e206d65737361676500000000000000000000000000000000000000006064820152608401610293565b60665460ff16156113495760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610293565b6001600160a01b03821660009081526098602052604081209061136b84612bcf565b9050600061137f6103e86108028885613512565b9050600061139e6103e8610802609d548a61351290919063ffffffff16565b905060006113ac838361352a565b905060006113ba89836134ff565b60048701549091506113cc908561352a565b600487015560068601546113e0908461352a565b6006870155604080516001600160a01b038c811682526020820184905281830187905260608201869052608082018590528a1660a082015290517fe42a885e97ef72aed483b57141e41f9d64499b43411f58b60a0e07fcdb6e824a9181900360c00190a16001600160a01b0388161561146c576114676001600160a01b0389168b83613761565b611515565b60008a6001600160a01b0316609f5483604051600060405180830381858888f193505050503d80600081146114bd576040519150601f19603f3d011682016040523d82523d6000602084013e6114c2565b606091505b50509050806115135760405162461bcd60e51b815260206004820152601460248201527f4661696c656420746f2073656e642045746865720000000000000000000000006044820152606401610293565b505b50505050505050505050565b60665460ff16156115745760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610293565b6001600160a01b03808316600090815260986020908152604080832060998352818420338552909252909120600182015491929091166115f65760405162461bcd60e51b815260206004820152601c60248201527f546f6b656e2041646472657373204e6f742052656769737465726564000000006044820152606401610293565b80548511156116475760405162461bcd60e51b815260206004820152600e60248201527f5769746864726177204572726f720000000000000000000000000000000000006044820152606401610293565b61165084610793565b61168a61167f8260010154610f9164e8d4a510006108028760050154876000015461351290919063ffffffff16565b60028301549061352a565b6002820155805461169b90866134ff565b80825560058301546116b89164e8d4a51000916108029190613512565b600182015560028201546116cc90866134ff565b6002830155604080513381526001600160a01b0385811660208301528183018890528616606082015290517ffa2e8fcf14fd6ea11b6ebe7caf7de210198b8fe1eaf0e06d19f8d87c73860c469181900360800190a16001600160a01b03841615611749576117446001600160a01b0385168487613761565b6117f0565b6000836001600160a01b0316609f5487604051600060405180830381858888f193505050503d806000811461179a576040519150601f19603f3d011682016040523d82523d6000602084013e61179f565b606091505b50509050806111425760405162461bcd60e51b815260206004820152601260248201527f4661696c656420746f2073656e642045544800000000000000000000000000006044820152606401610293565b5050505050565b609a546001600160a01b03163314806118195750609a546001600160a01b0316155b6118655760405162461bcd60e51b815260206004820152601760248201527f43616c6c6572206973206e6f7420746865206f776e65720000000000000000006044820152606401610293565b806001600160a01b0316826001600160a01b031614156118ed5760405162461bcd60e51b815260206004820152602860248201527f6c3120616e64206c3220746f6b656e206164647265737365732063616e6e6f7460448201527f2062652073616d650000000000000000000000000000000000000000000000006064820152608401610293565b6001600160a01b0381166119695760405162461bcd60e51b815260206004820152602760248201527f6c3220746f6b656e20616464726573732063616e6e6f74206265207a65726f2060448201527f61646472657373000000000000000000000000000000000000000000000000006064820152608401610293565b6001600160a01b0380831660009081526098602052604090206001810154909116156119d75760405162461bcd60e51b815260206004820181905260248201527f546f6b656e204164647265737320416c726561647920526567697374657265646044820152606401610293565b5060408051610100810182526001600160a01b0393841680825292841660208083019182526000838501818152606085018281526080860183815260a0870184815260c088018581524260e08a019081529a865260989096529790932095518654908a167fffffffffffffffffffffffff0000000000000000000000000000000000000000918216178755945160018701805491909a16951694909417909755955160028401559051600383015593516004820155905160058201559151600683015551600790910155565b609a546001600160a01b0316331480611ac55750609a546001600160a01b0316155b611b115760405162461bcd60e51b815260206004820152601760248201527f43616c6c6572206973206e6f7420746865206f776e65720000000000000000006044820152606401610293565b6001600160a01b0380831660009081526098602052604090206001810154909116611b7e5760405162461bcd60e51b815260206004820152601c60248201527f546f6b656e2041646472657373204e6f742052656769737465726564000000006044820152606401610293565b8381600601541015611bd25760405162461bcd60e51b815260206004820152601b60248201527f4f776e657220526577617264205769746864726177204572726f7200000000006044820152606401610293565b6006810154611be190856134ff565b6006820155604080513381526001600160a01b0384811660208301528183018790528516606082015290517f3cb71b9a1fb601579f96812b9f86ab5e914fc3e54c98d5f84d95581b2b9884f39181900360800190a16001600160a01b03831615611c5e57611c596001600160a01b0384168386613761565b611d05565b6000826001600160a01b0316609f5486604051600060405180830381858888f193505050503d8060008114611caf576040519150601f19603f3d011682016040523d82523d6000602084013e611cb4565b606091505b50509050806117f05760405162461bcd60e51b815260206004820152601460248201527f4661696c656420746f2073656e642045746865720000000000000000000000006044820152606401610293565b50505050565b609a546001600160a01b0316331480611d2d5750609a546001600160a01b0316155b611d795760405162461bcd60e51b815260206004820152601760248201527f43616c6c6572206973206e6f7420746865206f776e65720000000000000000006044820152606401610293565b6109c66137aa565b60665460ff1615611dd45760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610293565b60058110611e245760405162461bcd60e51b815260206004820152600f60248201527f546f6f204d616e7920546f6b656e7300000000000000000000000000000000006044820152606401610293565b6000808267ffffffffffffffff811115611e4057611e40614273565b604051908082528060200260200182016040528015611ea957816020015b60408051606081018252600080825260208083018290529282015282527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff909201910181611e5e5790505b50905060005b83811015612050576000858583818110611ecb57611ecb6142a2565b905060400201803603810190611ee191906142d1565b9050806020015160001415611f385760405162461bcd60e51b815260206004820152600e60248201527f496e76616c696420416d6f756e740000000000000000000000000000000000006044820152606401610293565b80516001600160a01b0390811660009081526098602052604090206001810154909116611fa75760405162461bcd60e51b815260206004820152600d60248201527f496e7661696c6420546f6b656e000000000000000000000000000000000000006044820152606401610293565b81516001600160a01b031615611fdc5760208201518251611fd7916001600160a01b039091169033903090613850565b611fee565b6020820151611feb908661437f565b94505b6040805160608101825233815260018301546001600160a01b0316602080830191909152840151918101919091528451859085908110612030576120306142a2565b60200260200101819052505050808061204890614397565b915050611eaf565b503482146120a05760405162461bcd60e51b815260206004820152601260248201527f496e76616c69642045544820416d6f756e7400000000000000000000000000006044820152606401610293565b600063b4eeb98860e01b826040516024016120bb91906143d0565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152609b54609e54919250612168916001600160a01b03909116906121629063ffffffff166002614435565b836138a1565b7f1a79d691d0cd9e7c4f70b52af899cfc71146947ba0fa6fc236e2649c07a8e9128260405161219791906143d0565b60405180910390a15050505050565b609a546001600160a01b03163314806121c85750609a546001600160a01b0316155b6122145760405162461bcd60e51b815260206004820152601760248201527f43616c6c6572206973206e6f7420746865206f776e65720000000000000000006044820152606401610293565b609b546001600160a01b03166122925760405162461bcd60e51b815260206004820152602560248201527f436f6e747261637420686173206e6f7420796574206265656e20696e6974696160448201527f6c697a65640000000000000000000000000000000000000000000000000000006064820152608401610293565b818311156122e25760405162461bcd60e51b815260206004820152601760248201527f496e76616c7564207573657220726577617264206665650000000000000000006044820152606401610293565b610e86838383609c9290925560a255609d55565b6002805414156123485760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610293565b6002805560665460ff161561239f5760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610293565b341515806123b557506001600160a01b03811615155b6124275760405162461bcd60e51b815260206004820152603260248201527f45697468657220416d6f756e7420496e636f7272656374206f7220546f6b656e60448201527f204164647265737320496e636f727265637400000000000000000000000000006064820152608401610293565b341580159061243e57506001600160a01b03811615155b156124b15760405162461bcd60e51b815260206004820152603260248201527f45697468657220416d6f756e7420496e636f7272656374206f7220546f6b656e60448201527f204164647265737320496e636f727265637400000000000000000000000000006064820152608401610293565b34156124be575034905060005b6001600160a01b03808216600090815260986020908152604080832060998352818420338552909252909120600182015491929091166125405760405162461bcd60e51b815260206004820152601c60248201527f546f6b656e2041646472657373204e6f742052656769737465726564000000006044820152606401610293565b61254983610793565b8054156125b55761257f61167f8260010154610f9164e8d4a510006108028760050154876000015461351290919063ffffffff16565b6002820155600582015481546125ab9164e8d4a510009161080291906125a5908961352a565b90613512565b60018201556125db565b6125d564e8d4a5100061080284600501548761351290919063ffffffff16565b60018201555b80546125e7908561352a565b815560028201546125f8908561352a565b600283015560408051338152602081018690526001600160a01b0385168183015290517f5852d1d46e583f7e92c2a572221de0e681d82ef71f489847e056b9445c0147369181900360600190a16001600160a01b03831615612669576126696001600160a01b038416333087613850565b505060016002555050565b609b546001600160a01b03166126926001546001600160a01b031690565b6001600160a01b0316336001600160a01b0316146127185760405162461bcd60e51b815260206004820152602a60248201527f58434841494e3a206d657373656e67657220636f6e747261637420756e61757460448201527f68656e74696361746564000000000000000000000000000000000000000000006064820152608401610293565b806001600160a01b03166127346001546001600160a01b031690565b6001600160a01b0316636e296e456040518163ffffffff1660e01b815260040160206040518083038186803b15801561276c57600080fd5b505afa158015612780573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127a49190614256565b6001600160a01b0316146128205760405162461bcd60e51b815260206004820152602c60248201527f58434841494e3a2077726f6e672073656e646572206f662063726f73732d646f60448201527f6d61696e206d65737361676500000000000000000000000000000000000000006064820152608401610293565b60665460ff16156128735760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610293565b6001600160a01b03821660009081526098602052604081208161289585612bcf565b905060006128a96103e86108028985613512565b905060006128c86103e8610802609d548b61351290919063ffffffff16565b905060006128d6838361352a565b905060006128e48a836134ff565b90506001600160a01b038916156129d6576040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038a16906370a082319060240160206040518083038186803b15801561294d57600080fd5b505afa158015612961573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612985919061423d565b8111156129955760019650612ab6565b60048601546129a4908561352a565b600487015560068601546129b8908461352a565b60068701556129d16001600160a01b038a168c83613761565b612ab6565b478111156129e75760019650612ab6565b60048601546129f6908561352a565b60048701556006860154612a0a908461352a565b6006870155609f546040516000916001600160a01b038e1691849084818181858888f193505050503d8060008114612a5e576040519150601f19603f3d011682016040523d82523d6000602084013e612a63565b606091505b5050905080612ab45760405162461bcd60e51b815260206004820152601260248201527f4661696c656420746f2073656e642045544800000000000000000000000000006044820152606401610293565b505b8615612b63576001860154604080516001600160a01b038e81166024830152604482018e90529283166064808301919091528251808303909101815260849091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f650a767b00000000000000000000000000000000000000000000000000000000179052609b54609e549192612b5d9291169063ffffffff16836138a1565b50611513565b604080516001600160a01b038d811682526020820184905281830187905260608201869052608082018590528b1660a082015290517ffe1f8646fcb202e48551fbfd19085116c64b291c60cede7dce3665a57c05e3819181900360c00190a15050505050505050505050565b609b546000906001600160a01b0316612c505760405162461bcd60e51b815260206004820152602560248201527f436f6e747261637420686173206e6f7420796574206265656e20696e6974696160448201527f6c697a65640000000000000000000000000000000000000000000000000000006064820152608401610293565b6001600160a01b038216600081815260986020526040812060028101549092909190612c7d575047612d10565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038616906370a082319060240160206040518083038186803b158015612cd557600080fd5b505afa158015612ce9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d0d919061423d565b90505b80612d2157505060a2549392505050565b60008183609c54612d329190614461565b612d3c919061449e565b905080609c541115612d55575050609c54949350505050565b8060a2541015612d6c57505060a254949350505050565b9350612d7792505050565b919050565b609a546001600160a01b0316331480612d9e5750609a546001600160a01b0316155b612dea5760405162461bcd60e51b815260206004820152601760248201527f43616c6c6572206973206e6f7420746865206f776e65720000000000000000006044820152606401610293565b6001600160a01b038116612e655760405162461bcd60e51b8152602060048201526024808201527f4e6577206f776e65722063616e6e6f7420626520746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152608401610293565b609a80547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040519081527f04dba622d284ed0014ee4b9a6a68386be1a4c08a4913ae272de89199cc6861639060200160405180910390a150565b60665460ff1615612f245760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610293565b34151580612f3a57506001600160a01b03811615155b612fac5760405162461bcd60e51b815260206004820152603260248201527f45697468657220416d6f756e7420496e636f7272656374206f7220546f6b656e60448201527f204164647265737320496e636f727265637400000000000000000000000000006064820152608401610293565b3415801590612fc357506001600160a01b03811615155b156130365760405162461bcd60e51b815260206004820152603260248201527f45697468657220416d6f756e7420496e636f7272656374206f7220546f6b656e60448201527f204164647265737320496e636f727265637400000000000000000000000000006064820152608401610293565b3415613043575034905060005b6001600160a01b03808216600090815260986020526040902060018101549091166130b05760405162461bcd60e51b815260206004820152601c60248201527f546f6b656e2041646472657373204e6f742052656769737465726564000000006044820152606401610293565b6130bb8233856138ee565b60408051338152602081018590526001600160a01b0384168183015290517f860e25c3d48fb81f0b272550dd125a5a6ab20ee7511dd3e250d04964bd37a7a99181900360600190a16001600160a01b03821615613127576131276001600160a01b038316333086613850565b600181015460408051336024820152604481018690526001600160a01b039283166064808301919091528251808303909101815260849091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fbd2d1cab00000000000000000000000000000000000000000000000000000000179052609b54609e549192611d059291169063ffffffff16836138a1565b609a546001600160a01b03163314806131e85750609a546001600160a01b0316155b6132345760405162461bcd60e51b815260206004820152601760248201527f43616c6c6572206973206e6f7420746865206f776e65720000000000000000006044820152606401610293565b609b546001600160a01b03161561328d5760405162461bcd60e51b815260206004820152601d60248201527f436f6e747261637420686173206265656e20696e697469616c697a65640000006044820152606401610293565b6001547501000000000000000000000000000000000000000000900460ff16806132d2575060015474010000000000000000000000000000000000000000900460ff16155b6133445760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610293565b6001547501000000000000000000000000000000000000000000900460ff161580156133ab57600180547fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff1675010100000000000000000000000000000000000000001790555b6001600160a01b038516158015906133cb57506001600160a01b03841615155b80156133df57506001600160a01b03831615155b61342b5760405162461bcd60e51b815260206004820152601860248201527f7a65726f2061646472657373206e6f7420616c6c6f77656400000000000000006044820152606401610293565b600080546001600160a01b038781167fffffffffffffffffffffffff000000000000000000000000000000000000000092831617835560018054888316908416179055609b805487831690841617905560a18054918616918316919091179055609a8054909116331790556005609c55603260a255609d556134b2620aae606108fc610829565b6134ba613973565b6134c2613ac3565b6134ca613c3a565b80156117f057600180547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff1690555050505050565b600061350b82846144d9565b9392505050565b600061350b8284614461565b600061350b828461449e565b600061350b828461437f565b60665460ff166135885760405162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401610293565b606680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6040517fdd62ed3e0000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038381166024830152600091839186169063dd62ed3e9060440160206040518083038186803b15801561365557600080fd5b505afa158015613669573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061368d919061423d565b613697919061437f565b6040516001600160a01b038516602482015260448101829052909150611d059085907f095ea7b300000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152613d8e565b6040516001600160a01b038316602482015260448101829052610e869084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064016136df565b60665460ff16156137fd5760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610293565b606680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586135d33390565b6040516001600160a01b0380851660248301528316604482015260648101829052611d059085907f23b872dd00000000000000000000000000000000000000000000000000000000906084016136df565b6000546040517f3dbb202b0000000000000000000000000000000000000000000000000000000081526001600160a01b0390911690633dbb202b90610e5390869085908790600401614566565b60a5544311156138ff5760a45460a3555b60a4546040805160208101929092526001600160a01b0380861691830191909152831660608201526080810182905260a001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052805160209091012060a45550504360a55550565b6001547501000000000000000000000000000000000000000000900460ff16806139b8575060015474010000000000000000000000000000000000000000900460ff16155b613a2a5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610293565b6001547501000000000000000000000000000000000000000000900460ff16158015613a9157600180547fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff1675010100000000000000000000000000000000000000001790555b8015613ac057600180547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff1690555b50565b6001547501000000000000000000000000000000000000000000900460ff1680613b08575060015474010000000000000000000000000000000000000000900460ff16155b613b7a5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610293565b6001547501000000000000000000000000000000000000000000900460ff16158015613be157600180547fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff1675010100000000000000000000000000000000000000001790555b606680547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690558015613ac057600180547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff16905550565b6001547501000000000000000000000000000000000000000000900460ff1680613c7f575060015474010000000000000000000000000000000000000000900460ff16155b613cf15760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610293565b6001547501000000000000000000000000000000000000000000900460ff16158015613d5857600180547fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff1675010100000000000000000000000000000000000000001790555b60016002558015613ac057600180547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff16905550565b6000613de3826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316613e739092919063ffffffff16565b805190915015610e865780806020019051810190613e01919061459e565b610e865760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610293565b6060613e828484600085613e8a565b949350505050565b606082471015613f025760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610293565b843b613f505760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610293565b600080866001600160a01b03168587604051613f6c91906145c0565b60006040518083038185875af1925050503d8060008114613fa9576040519150601f19603f3d011682016040523d82523d6000602084013e613fae565b606091505b5091509150613fbe828286613fc9565b979650505050505050565b60608315613fd857508161350b565b825115613fe85782518084602001fd5b8160405162461bcd60e51b815260040161029391906145dc565b6001600160a01b0381168114613ac057600080fd5b6000806040838503121561402a57600080fd5b823561403581614002565b9150602083013561404581614002565b809150509250929050565b60006020828403121561406257600080fd5b813561350b81614002565b6000806040838503121561408057600080fd5b823563ffffffff8116811461409457600080fd5b946020939093013593505050565b600080604083850312156140b557600080fd5b82359150602083013561404581614002565b6000806000606084860312156140dc57600080fd5b8335925060208401356140ee81614002565b915060408401356140fe81614002565b809150509250925092565b60008060006060848603121561411e57600080fd5b833561412981614002565b92506020840135915060408401356140fe81614002565b6000806020838503121561415357600080fd5b823567ffffffffffffffff8082111561416b57600080fd5b818501915085601f83011261417f57600080fd5b81358181111561418e57600080fd5b8660208260061b85010111156141a357600080fd5b60209290920196919550909350505050565b6000806000606084860312156141ca57600080fd5b505081359360208301359350604090920135919050565b600080600080608085870312156141f757600080fd5b843561420281614002565b9350602085013561421281614002565b9250604085013561422281614002565b9150606085013561423281614002565b939692955090935050565b60006020828403121561424f57600080fd5b5051919050565b60006020828403121561426857600080fd5b815161350b81614002565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6000604082840312156142e357600080fd5b6040516040810181811067ffffffffffffffff8211171561432d577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604052823561433b81614002565b81526020928301359281019290925250919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000821982111561439257614392614350565b500190565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8214156143c9576143c9614350565b5060010190565b602080825282518282018190526000919060409081850190868401855b8281101561442857815180516001600160a01b03908116865287820151168786015285015185850152606090930192908501906001016143ed565b5091979650505050505050565b600063ffffffff8083168185168183048111821515161561445857614458614350565b02949350505050565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561449957614499614350565b500290565b6000826144d4577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b6000828210156144eb576144eb614350565b500390565b60005b8381101561450b5781810151838201526020016144f3565b83811115611d055750506000910152565b600081518084526145348160208601602086016144f0565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6001600160a01b0384168152606060208201526000614588606083018561451c565b905063ffffffff83166040830152949350505050565b6000602082840312156145b057600080fd5b8151801515811461350b57600080fd5b600082516145d28184602087016144f0565b9190910192915050565b60208152600061350b602083018461451c56fea164736f6c6343000809000a
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 24 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
[ Download: CSV Export ]
[ 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.