Overview
ETH Balance
0.020772242049217261 ETH
Eth Value
$70.90 (@ $3,413.43/ETH)Token Holdings
More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 761 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Send | 21246769 | 16 hrs ago | IN | 0.00007357 ETH | 0.00149168 | ||||
Send | 21241594 | 33 hrs ago | IN | 0.00003007 ETH | 0.00308704 | ||||
Send | 21239943 | 39 hrs ago | IN | 0.00003007 ETH | 0.00357956 | ||||
Send | 21235801 | 2 days ago | IN | 0.00003211 ETH | 0.00390742 | ||||
Send | 21234865 | 2 days ago | IN | 0.00001124 ETH | 0.00098065 | ||||
Send | 21234715 | 2 days ago | IN | 0.00001124 ETH | 0.00105458 | ||||
Send | 21227991 | 3 days ago | IN | 0.00001124 ETH | 0.00128013 | ||||
Send | 21225970 | 3 days ago | IN | 0.00003211 ETH | 0.00374577 | ||||
Send | 21206313 | 6 days ago | IN | 0.00003211 ETH | 0.00326615 | ||||
Send | 21202822 | 6 days ago | IN | 0.00006751 ETH | 0.00128584 | ||||
Send | 21199609 | 7 days ago | IN | 0.00001124 ETH | 0.00108129 | ||||
Send | 21198607 | 7 days ago | IN | 0.00001124 ETH | 0.00152605 | ||||
Redeem Send | 21188348 | 8 days ago | IN | 0.00003211 ETH | 0.00856787 | ||||
Deposit | 21169641 | 11 days ago | IN | 0 ETH | 0.00214764 | ||||
Redeem | 21169634 | 11 days ago | IN | 0 ETH | 0.00155503 | ||||
Deposit | 21169547 | 11 days ago | IN | 0 ETH | 0.00267251 | ||||
Send | 21159678 | 12 days ago | IN | 0.00003189 ETH | 0.00832819 | ||||
Send | 21151100 | 14 days ago | IN | 0.00001189 ETH | 0.00117795 | ||||
Send | 21148674 | 14 days ago | IN | 0.00003398 ETH | 0.00375513 | ||||
Send | 21147971 | 14 days ago | IN | 0.00007038 ETH | 0.00070465 | ||||
Send | 21140405 | 15 days ago | IN | 0.00003398 ETH | 0.00313773 | ||||
Send | 21140318 | 15 days ago | IN | 0.00003398 ETH | 0.00314631 | ||||
Send | 21140201 | 15 days ago | IN | 0.00003398 ETH | 0.00347766 | ||||
Send | 21133640 | 16 days ago | IN | 0.00007114 ETH | 0.00114682 | ||||
Send | 21123994 | 17 days ago | IN | 0.00001437 ETH | 0.00083642 |
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
21241594 | 33 hrs ago | 0.00003007 ETH | ||||
21239943 | 39 hrs ago | 0.00003007 ETH | ||||
21235801 | 2 days ago | 0.00003211 ETH | ||||
21225970 | 3 days ago | 0.00003211 ETH | ||||
21220946 | 4 days ago | 0.00001124 ETH | ||||
21206313 | 6 days ago | 0.00003211 ETH | ||||
21205327 | 6 days ago | 0.00001124 ETH | ||||
21204409 | 6 days ago | 0.00001124 ETH | ||||
21202190 | 6 days ago | 0.00001124 ETH | ||||
21188348 | 8 days ago | 0.00003211 ETH | ||||
21159678 | 12 days ago | 0.00003189 ETH | ||||
21148674 | 14 days ago | 0.00003398 ETH | ||||
21140405 | 15 days ago | 0.00003398 ETH | ||||
21140318 | 15 days ago | 0.00003398 ETH | ||||
21140201 | 15 days ago | 0.00003398 ETH | ||||
21119099 | 18 days ago | 0.00004105 ETH | ||||
21119099 | 18 days ago | 0.00004105 ETH | ||||
21111956 | 19 days ago | 0.00004105 ETH | ||||
21106181 | 20 days ago | 0.00001437 ETH | ||||
21098418 | 21 days ago | 0.00003833 ETH | ||||
21098418 | 21 days ago | 0.00003833 ETH | ||||
21090802 | 22 days ago | 0.00001341 ETH | ||||
21084438 | 23 days ago | 0.00001341 ETH | ||||
21082549 | 23 days ago | 0.00001341 ETH | ||||
21070494 | 25 days ago | 0.00003833 ETH |
Loading...
Loading
Contract Name:
StargatePool
Compiler Version
v0.8.22+commit.4fc1097e
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.22; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { StargateType, MessagingReceipt, MessagingFee, SendParam, OFTReceipt } from "./interfaces/IStargate.sol"; import { IStargatePool } from "./interfaces/IStargatePool.sol"; import { ITokenMessaging, TaxiParams } from "./interfaces/ITokenMessaging.sol"; import { Transfer } from "./libs/Transfer.sol"; import { StargateBase, FeeParams } from "./StargateBase.sol"; import { LPToken } from "./utils/LPToken.sol"; /// @title A Stargate contract representing a liquidity pool. Users can deposit tokens into the pool and receive /// @title LP tokens in exchange, which can be later be redeemed to recover their deposit and a reward which is /// @title a fraction of the fee accrued by the liquidity pool during the staking time. contract StargatePool is StargateBase, IStargatePool { LPToken internal immutable lp; uint64 internal tvlSD; uint64 internal poolBalanceSD; uint64 internal deficitOffsetSD; event Deposited(address indexed payer, address indexed receiver, uint256 amountLD); event Redeemed(address indexed payer, address indexed receiver, uint256 amountLD); error Stargate_OnlyTaxi(); /// @notice Create a Stargate pool to provide liquidity. This also creates the LP token contract. /// @param _lpTokenName The name for the LP token /// @param _lpTokenSymbol The symbol for the LP token /// @param _token The token for the pool or oft. If the token is address(0), it is the native coin /// @param _tokenDecimals The number of decimals for this tokens implementation on this chain /// @param _sharedDecimals The number of decimals shared between all implementations of the OFT /// @param _endpoint The LZ endpoint contract /// @param _owner The owner of this contract constructor( string memory _lpTokenName, string memory _lpTokenSymbol, address _token, uint8 _tokenDecimals, uint8 _sharedDecimals, address _endpoint, address _owner ) StargateBase(_token, _tokenDecimals, _sharedDecimals, _endpoint, _owner) { lp = new LPToken(_lpTokenName, _lpTokenSymbol, _tokenDecimals); } // -------- LP operations -------- /// @notice Deposit token into the pool /// @dev Emits Deposited when the token is deposited /// @param _receiver The account to mint the LP tokens to /// @param _amountLD The amount of tokens to deposit in LD /// @return amountLD The actual amount of tokens deposited in LD function deposit( address _receiver, uint256 _amountLD ) external payable nonReentrantAndNotPaused returns (uint256 amountLD) { // charge the sender _assertMsgValue(_amountLD); uint64 amountSD = _inflow(msg.sender, _amountLD); _postInflow(amountSD); // increase the local credit and pool balance // mint LP token to the receiver amountLD = _sd2ld(amountSD); lp.mint(_receiver, amountLD); tvlSD += amountSD; emit Deposited(msg.sender, _receiver, amountLD); } /// @notice Redeem the LP token of the sender and return the underlying token to receiver /// @dev Emits Redeemed when the LP tokens are redeemed successfully. /// @dev Reverts if the sender does not hold enough LP tokens or if the pool does not have enough credit. /// @param _amountLD The amount of LP token to redeem in LD /// @param _receiver The account to which to return the underlying tokens /// @return amountLD The amount of LP token burned and the amount of underlying token sent to the receiver function redeem(uint256 _amountLD, address _receiver) external nonReentrantAndNotPaused returns (uint256 amountLD) { uint64 amountSD = _ld2sd(_amountLD); paths[localEid].decreaseCredit(amountSD); // de-dust LP token amountLD = _sd2ld(amountSD); // burn LP token. Will revert if the sender doesn't have enough LP token lp.burnFrom(msg.sender, amountLD); tvlSD -= amountSD; // send the underlying token from the pool to the receiver _safeOutflow(_receiver, amountLD); _postOutflow(amountSD); // decrease the pool balance emit Redeemed(msg.sender, _receiver, amountLD); } /// @notice Redeem LP tokens and use the withdrawn tokens to execute a send /// @dev Emits Redeemed when the LP tokens are redeemed successfully. /// @dev Emits OFTSent when the LP tokens are redeemed successfully. /// @param _sendParam The RedeemSendParam object describing the redeem and send /// @param _fee The MessagingFee describing the fee to pay for the send /// @param _refundAddress The address to refund any LZ fees paid in excess /// @return msgReceipt The messaging receipt proving the send /// @return oftReceipt The OFT receipt proving the send function redeemSend( SendParam calldata _sendParam, MessagingFee calldata _fee, address _refundAddress ) external payable nonReentrantAndNotPaused returns (MessagingReceipt memory msgReceipt, OFTReceipt memory oftReceipt) { if (!_isTaxiMode(_sendParam.oftCmd)) revert Stargate_OnlyTaxi(); // remove the dust uint64 amountInSD = _ld2sd(_sendParam.amountLD); uint256 amountInLD = _sd2ld(amountInSD); // burn LP token of 'msg.sender'. it will revert if the sender doesn't have enough LP token lp.burnFrom(msg.sender, amountInLD); emit Redeemed(msg.sender, address(0), amountInLD); // charge fees and handle credit FeeParams memory feeParams = _buildFeeParams(_sendParam.dstEid, amountInSD, true); uint64 amountOutSD = _chargeFee(feeParams, _ld2sd(_sendParam.minAmountLD)); // need to update the TVL after charging the fee, otherwise the deficit will be wrong tvlSD -= amountInSD; // handle credit and pool balance // due to the both of them are already increased when deposit, so if // 1) the amountOutSD is less than amountInSD, the fee should be removed from both of them // 2) the amountOutSD is more than amountInSD, the reward should be added to both of them paths[_sendParam.dstEid].decreaseCredit(amountOutSD); if (amountInSD > amountOutSD) { // fee uint64 fee = amountInSD - amountOutSD; paths[localEid].decreaseCredit(fee); poolBalanceSD -= fee; } else if (amountInSD < amountOutSD) { // reward uint64 reward = amountOutSD - amountInSD; paths[localEid].increaseCredit(reward); poolBalanceSD += reward; } // send the token to the receiver MessagingFee memory messagingFee = _assertMessagingFee(_fee, 0); msgReceipt = _taxi(_sendParam, messagingFee, amountOutSD, _refundAddress); oftReceipt = OFTReceipt(amountInLD, _sd2ld(amountOutSD)); emit OFTSent(msgReceipt.guid, _sendParam.dstEid, msg.sender, amountInLD, oftReceipt.amountReceivedLD); } /// @notice Get how many LP tokens can be redeemed by a given account. /// @dev Use 0x0 to get the total maximum redeemable (since its capped to the local credit) /// @param _owner The account to check for /// @return amountLD The max amount of LP tokens redeemable by the account function redeemable(address _owner) external view returns (uint256 amountLD) { uint256 cap = _sd2ld(paths[localEid].credit); if (_owner == address(0)) { amountLD = cap; } else { uint256 userLp = lp.balanceOf(_owner); amountLD = cap > userLp ? userLp : cap; } } /// @notice Get a quote on the fee associated with a RedeemSend operation /// @param _sendParam The RedeemSendParam object describing the RedeemSend /// @param _payInLzToken Whether to pay the LZ fee in LZ token /// @return fee The MessagingFee object that describes the Fee that would be associated with this RedeemSend function quoteRedeemSend( SendParam calldata _sendParam, bool _payInLzToken ) external view returns (MessagingFee memory fee) { if (!_isTaxiMode(_sendParam.oftCmd)) revert Stargate_OnlyTaxi(); uint64 amountInSD = _ld2sd(_sendParam.amountLD); fee = ITokenMessaging(tokenMessaging).quoteTaxi( TaxiParams({ sender: msg.sender, dstEid: _sendParam.dstEid, receiver: _sendParam.to, amountSD: amountInSD, composeMsg: _sendParam.composeMsg, extraOptions: _sendParam.extraOptions }), _payInLzToken ); } /// @notice Get the total value locked in this pool /// @dev The TVL of the pool is the total supply of the LP token since they are minted 1:1. /// @return The total value locked in LD function tvl() external view override returns (uint256) { return _sd2ld(tvlSD); } /// @notice Get the current pool balance /// @dev The pool balance is the total amount of tokens in the pool, it reflects liquidity. /// @return The pool balance in LD function poolBalance() external view override returns (uint256) { return _sd2ld(poolBalanceSD); } /// @notice Get the current deficit offset /// @dev The deficit offset allows manipulation of the ideal pool liquidity beyond surplus 0. /// @return The deficit offset in LD function deficitOffset() external view returns (uint256) { return _sd2ld(deficitOffsetSD); } /// @notice Returns the type of Stargate contract. /// @dev Fulfills the IStargate interface. /// @return The type of Stargate contract function stargateType() external pure override returns (StargateType) { return StargateType.Pool; } /// @notice Returns the LP token contract used to represent pool ownership. /// @return The address of the LP token contract. function lpToken() external view override returns (address) { return address(lp); } /// @notice Limits the reward awarded when withdrawing value. /// @dev Concretes the StargateBase contract. /// @dev Liquidity pools cap the reward to the total fees accrued in the treasury. /// @param _amountOutSD The amount of tokens expected on the destination chain in SD /// @param _reward The initial calculated reward by FeeLib /// @return newAmountOutSD The actual amount to be received on the destination chain /// @return newReward The actual reward after applying any caps function _capReward(uint64 _amountOutSD, uint64 _reward) internal view override returns (uint64, uint64) { uint64 rewardCap = treasuryFee; if (_reward > rewardCap) { // exceeds cap, recalculate with new reward unchecked { return (_amountOutSD - _reward + rewardCap, rewardCap); } } else { // lower than cap, return the original values return (_amountOutSD, _reward); } } /// @notice Increase the local credit and pool balance function _postInflow(uint64 _amountSD) internal override { paths[localEid].increaseCredit(_amountSD); poolBalanceSD += _amountSD; } /// @notice Decrease the pool balance function _postOutflow(uint64 _amountSD) internal override { poolBalanceSD -= _amountSD; } /// @notice Charge an account an amount of pooled tokens. /// @dev Reverts if the charge can not be completed. /// @param _from The account to charge /// @param _amountLD How many tokens to charge in LD /// @return amountSD The amount of tokens charged in SD function _inflow(address _from, uint256 _amountLD) internal virtual override returns (uint64 amountSD) { amountSD = _ld2sd(_amountLD); Transfer.safeTransferTokenFrom(token, _from, address(this), _sd2ld(amountSD)); // remove the dust and transfer } /// @notice Transfer a token from the pool to an account. /// @param _to The destination account /// @param _amountLD How many tokens to transfer in LD /// @return success Whether the transfer succeeded or not function _outflow(address _to, uint256 _amountLD) internal virtual override returns (bool success) { success = Transfer.transferToken(token, _to, _amountLD); } function _buildFeeParams( uint32 _dstEid, uint64 _amountInSD, bool _isTaxi ) internal view override returns (FeeParams memory) { uint64 t = tvlSD + deficitOffsetSD; uint64 deficitSD = t > poolBalanceSD ? t - poolBalanceSD : 0; return FeeParams(msg.sender, _dstEid, _amountInSD, deficitSD, paths[_dstEid].isOFTPath(), _isTaxi); } // ---------------------------------- Only Treasurer ------------------------------------------ function recoverToken( address _token, address _to, uint256 _amount ) public virtual override onlyCaller(treasurer) returns (uint256) { // only allow to recover the excess of poolBalanceSD + treasuryFee if the token is the pool token if (_token == token) { uint256 cap = _thisBalance() - _sd2ld(poolBalanceSD + treasuryFee); _amount = _amount > cap ? cap : _amount; } return super.recoverToken(_token, _to, _amount); } function _thisBalance() internal view virtual returns (uint256) { return IERC20(token).balanceOf(address(this)); } // ---------------------------------- Only Planner ------------------------------------------ function setDeficitOffset(uint256 _deficitOffsetLD) external onlyCaller(planner) { deficitOffsetSD = _ld2sd(_deficitOffsetLD); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; // @dev Import the 'MessagingFee' and 'MessagingReceipt' so it's exposed to OApp implementers // solhint-disable-next-line no-unused-import import { OAppSender, MessagingFee, MessagingReceipt } from "./OAppSender.sol"; // @dev Import the 'Origin' so it's exposed to OApp implementers // solhint-disable-next-line no-unused-import import { OAppReceiver, Origin } from "./OAppReceiver.sol"; import { OAppCore } from "./OAppCore.sol"; /** * @title OApp * @dev Abstract contract serving as the base for OApp implementation, combining OAppSender and OAppReceiver functionality. */ abstract contract OApp is OAppSender, OAppReceiver { /** * @dev Constructor to initialize the OApp with the provided endpoint and owner. * @param _endpoint The address of the LOCAL LayerZero endpoint. * @param _delegate The delegate capable of making OApp configurations inside of the endpoint. */ constructor(address _endpoint, address _delegate) OAppCore(_endpoint, _delegate) {} /** * @notice Retrieves the OApp version information. * @return senderVersion The version of the OAppSender.sol implementation. * @return receiverVersion The version of the OAppReceiver.sol implementation. */ function oAppVersion() public pure virtual override(OAppSender, OAppReceiver) returns (uint64 senderVersion, uint64 receiverVersion) { return (SENDER_VERSION, RECEIVER_VERSION); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; import { IOAppCore, ILayerZeroEndpointV2 } from "./interfaces/IOAppCore.sol"; /** * @title OAppCore * @dev Abstract contract implementing the IOAppCore interface with basic OApp configurations. */ abstract contract OAppCore is IOAppCore, Ownable { // The LayerZero endpoint associated with the given OApp ILayerZeroEndpointV2 public immutable endpoint; // Mapping to store peers associated with corresponding endpoints mapping(uint32 eid => bytes32 peer) public peers; /** * @dev Constructor to initialize the OAppCore with the provided endpoint and delegate. * @param _endpoint The address of the LOCAL Layer Zero endpoint. * @param _delegate The delegate capable of making OApp configurations inside of the endpoint. * * @dev The delegate typically should be set as the owner of the contract. */ constructor(address _endpoint, address _delegate) { endpoint = ILayerZeroEndpointV2(_endpoint); if (_delegate == address(0)) revert InvalidDelegate(); endpoint.setDelegate(_delegate); } /** * @notice Sets the peer address (OApp instance) for a corresponding endpoint. * @param _eid The endpoint ID. * @param _peer The address of the peer to be associated with the corresponding endpoint. * * @dev Only the owner/admin of the OApp can call this function. * @dev Indicates that the peer is trusted to send LayerZero messages to this OApp. * @dev Set this to bytes32(0) to remove the peer address. * @dev Peer is a bytes32 to accommodate non-evm chains. */ function setPeer(uint32 _eid, bytes32 _peer) public virtual onlyOwner { _setPeer(_eid, _peer); } /** * @notice Sets the peer address (OApp instance) for a corresponding endpoint. * @param _eid The endpoint ID. * @param _peer The address of the peer to be associated with the corresponding endpoint. * * @dev Indicates that the peer is trusted to send LayerZero messages to this OApp. * @dev Set this to bytes32(0) to remove the peer address. * @dev Peer is a bytes32 to accommodate non-evm chains. */ function _setPeer(uint32 _eid, bytes32 _peer) internal virtual { peers[_eid] = _peer; emit PeerSet(_eid, _peer); } /** * @notice Internal function to get the peer address associated with a specific endpoint; reverts if NOT set. * ie. the peer is set to bytes32(0). * @param _eid The endpoint ID. * @return peer The address of the peer associated with the specified endpoint. */ function _getPeerOrRevert(uint32 _eid) internal view virtual returns (bytes32) { bytes32 peer = peers[_eid]; if (peer == bytes32(0)) revert NoPeer(_eid); return peer; } /** * @notice Sets the delegate address for the OApp. * @param _delegate The address of the delegate to be set. * * @dev Only the owner/admin of the OApp can call this function. * @dev Provides the ability for a delegate to set configs, on behalf of the OApp, directly on the Endpoint contract. */ function setDelegate(address _delegate) public onlyOwner { endpoint.setDelegate(_delegate); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import { IOAppReceiver, Origin } from "./interfaces/IOAppReceiver.sol"; import { OAppCore } from "./OAppCore.sol"; /** * @title OAppReceiver * @dev Abstract contract implementing the ILayerZeroReceiver interface and extending OAppCore for OApp receivers. */ abstract contract OAppReceiver is IOAppReceiver, OAppCore { // Custom error message for when the caller is not the registered endpoint/ error OnlyEndpoint(address addr); // @dev The version of the OAppReceiver implementation. // @dev Version is bumped when changes are made to this contract. uint64 internal constant RECEIVER_VERSION = 2; /** * @notice Retrieves the OApp version information. * @return senderVersion The version of the OAppSender.sol contract. * @return receiverVersion The version of the OAppReceiver.sol contract. * * @dev Providing 0 as the default for OAppSender version. Indicates that the OAppSender is not implemented. * ie. this is a RECEIVE only OApp. * @dev If the OApp uses both OAppSender and OAppReceiver, then this needs to be override returning the correct versions. */ function oAppVersion() public view virtual returns (uint64 senderVersion, uint64 receiverVersion) { return (0, RECEIVER_VERSION); } /** * @notice Indicates whether an address is an approved composeMsg sender to the Endpoint. * @dev _origin The origin information containing the source endpoint and sender address. * - srcEid: The source chain endpoint ID. * - sender: The sender address on the src chain. * - nonce: The nonce of the message. * @dev _message The lzReceive payload. * @param _sender The sender address. * @return isSender Is a valid sender. * * @dev Applications can optionally choose to implement separate composeMsg senders that are NOT the bridging layer. * @dev The default sender IS the OAppReceiver implementer. */ function isComposeMsgSender( Origin calldata /*_origin*/, bytes calldata /*_message*/, address _sender ) public view virtual returns (bool) { return _sender == address(this); } /** * @notice Checks if the path initialization is allowed based on the provided origin. * @param origin The origin information containing the source endpoint and sender address. * @return Whether the path has been initialized. * * @dev This indicates to the endpoint that the OApp has enabled msgs for this particular path to be received. * @dev This defaults to assuming if a peer has been set, its initialized. * Can be overridden by the OApp if there is other logic to determine this. */ function allowInitializePath(Origin calldata origin) public view virtual returns (bool) { return peers[origin.srcEid] == origin.sender; } /** * @notice Retrieves the next nonce for a given source endpoint and sender address. * @dev _srcEid The source endpoint ID. * @dev _sender The sender address. * @return nonce The next nonce. * * @dev The path nonce starts from 1. If 0 is returned it means that there is NO nonce ordered enforcement. * @dev Is required by the off-chain executor to determine the OApp expects msg execution is ordered. * @dev This is also enforced by the OApp. * @dev By default this is NOT enabled. ie. nextNonce is hardcoded to return 0. */ function nextNonce(uint32 /*_srcEid*/, bytes32 /*_sender*/) public view virtual returns (uint64 nonce) { return 0; } /** * @dev Entry point for receiving messages or packets from the endpoint. * @param _origin The origin information containing the source endpoint and sender address. * - srcEid: The source chain endpoint ID. * - sender: The sender address on the src chain. * - nonce: The nonce of the message. * @param _guid The unique identifier for the received LayerZero message. * @param _message The payload of the received message. * @param _executor The address of the executor for the received message. * @param _extraData Additional arbitrary data provided by the corresponding executor. * * @dev Entry point for receiving msg/packet from the LayerZero endpoint. */ function lzReceive( Origin calldata _origin, bytes32 _guid, bytes calldata _message, address _executor, bytes calldata _extraData ) public payable virtual { // Ensures that only the endpoint can attempt to lzReceive() messages to this OApp. if (address(endpoint) != msg.sender) revert OnlyEndpoint(msg.sender); // Ensure that the sender matches the expected peer for the source endpoint. if (_getPeerOrRevert(_origin.srcEid) != _origin.sender) revert OnlyPeer(_origin.srcEid, _origin.sender); // Call the internal OApp implementation of lzReceive. _lzReceive(_origin, _guid, _message, _executor, _extraData); } /** * @dev Internal function to implement lzReceive logic without needing to copy the basic parameter validation. */ function _lzReceive( Origin calldata _origin, bytes32 _guid, bytes calldata _message, address _executor, bytes calldata _extraData ) internal virtual; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import { SafeERC20, IERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { MessagingParams, MessagingFee, MessagingReceipt } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroEndpointV2.sol"; import { OAppCore } from "./OAppCore.sol"; /** * @title OAppSender * @dev Abstract contract implementing the OAppSender functionality for sending messages to a LayerZero endpoint. */ abstract contract OAppSender is OAppCore { using SafeERC20 for IERC20; // Custom error messages error NotEnoughNative(uint256 msgValue); error LzTokenUnavailable(); // @dev The version of the OAppSender implementation. // @dev Version is bumped when changes are made to this contract. uint64 internal constant SENDER_VERSION = 1; /** * @notice Retrieves the OApp version information. * @return senderVersion The version of the OAppSender.sol contract. * @return receiverVersion The version of the OAppReceiver.sol contract. * * @dev Providing 0 as the default for OAppReceiver version. Indicates that the OAppReceiver is not implemented. * ie. this is a SEND only OApp. * @dev If the OApp uses both OAppSender and OAppReceiver, then this needs to be override returning the correct versions */ function oAppVersion() public view virtual returns (uint64 senderVersion, uint64 receiverVersion) { return (SENDER_VERSION, 0); } /** * @dev Internal function to interact with the LayerZero EndpointV2.quote() for fee calculation. * @param _dstEid The destination endpoint ID. * @param _message The message payload. * @param _options Additional options for the message. * @param _payInLzToken Flag indicating whether to pay the fee in LZ tokens. * @return fee The calculated MessagingFee for the message. * - nativeFee: The native fee for the message. * - lzTokenFee: The LZ token fee for the message. */ function _quote( uint32 _dstEid, bytes memory _message, bytes memory _options, bool _payInLzToken ) internal view virtual returns (MessagingFee memory fee) { return endpoint.quote( MessagingParams(_dstEid, _getPeerOrRevert(_dstEid), _message, _options, _payInLzToken), address(this) ); } /** * @dev Internal function to interact with the LayerZero EndpointV2.send() for sending a message. * @param _dstEid The destination endpoint ID. * @param _message The message payload. * @param _options Additional options for the message. * @param _fee The calculated LayerZero fee for the message. * - nativeFee: The native fee. * - lzTokenFee: The lzToken fee. * @param _refundAddress The address to receive any excess fee values sent to the endpoint. * @return receipt The receipt for the sent message. * - guid: The unique identifier for the sent message. * - nonce: The nonce of the sent message. * - fee: The LayerZero fee incurred for the message. */ function _lzSend( uint32 _dstEid, bytes memory _message, bytes memory _options, MessagingFee memory _fee, address _refundAddress ) internal virtual returns (MessagingReceipt memory receipt) { // @dev Push corresponding fees to the endpoint, any excess is sent back to the _refundAddress from the endpoint. uint256 messageValue = _payNative(_fee.nativeFee); if (_fee.lzTokenFee > 0) _payLzToken(_fee.lzTokenFee); return // solhint-disable-next-line check-send-result endpoint.send{ value: messageValue }( MessagingParams(_dstEid, _getPeerOrRevert(_dstEid), _message, _options, _fee.lzTokenFee > 0), _refundAddress ); } /** * @dev Internal function to pay the native fee associated with the message. * @param _nativeFee The native fee to be paid. * @return nativeFee The amount of native currency paid. * * @dev If the OApp needs to initiate MULTIPLE LayerZero messages in a single transaction, * this will need to be overridden because msg.value would contain multiple lzFees. * @dev Should be overridden in the event the LayerZero endpoint requires a different native currency. * @dev Some EVMs use an ERC20 as a method for paying transactions/gasFees. * @dev The endpoint is EITHER/OR, ie. it will NOT support both types of native payment at a time. */ function _payNative(uint256 _nativeFee) internal virtual returns (uint256 nativeFee) { if (msg.value != _nativeFee) revert NotEnoughNative(msg.value); return _nativeFee; } /** * @dev Internal function to pay the LZ token fee associated with the message. * @param _lzTokenFee The LZ token fee to be paid. * * @dev If the caller is trying to pay in the specified lzToken, then the lzTokenFee is passed to the endpoint. * @dev Any excess sent, is passed back to the specified _refundAddress in the _lzSend(). */ function _payLzToken(uint256 _lzTokenFee) internal virtual { // @dev Cannot cache the token because it is not immutable in the endpoint. address lzToken = endpoint.lzToken(); if (lzToken == address(0)) revert LzTokenUnavailable(); // Pay LZ token fee by sending tokens to the endpoint. IERC20(lzToken).safeTransferFrom(msg.sender, address(endpoint), _lzTokenFee); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import { ILayerZeroEndpointV2 } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroEndpointV2.sol"; /** * @title IOAppCore */ interface IOAppCore { // Custom error messages error OnlyPeer(uint32 eid, bytes32 sender); error NoPeer(uint32 eid); error InvalidEndpointCall(); error InvalidDelegate(); // Event emitted when a peer (OApp) is set for a corresponding endpoint event PeerSet(uint32 eid, bytes32 peer); /** * @notice Retrieves the OApp version information. * @return senderVersion The version of the OAppSender.sol contract. * @return receiverVersion The version of the OAppReceiver.sol contract. */ function oAppVersion() external view returns (uint64 senderVersion, uint64 receiverVersion); /** * @notice Retrieves the LayerZero endpoint associated with the OApp. * @return iEndpoint The LayerZero endpoint as an interface. */ function endpoint() external view returns (ILayerZeroEndpointV2 iEndpoint); /** * @notice Retrieves the peer (OApp) associated with a corresponding endpoint. * @param _eid The endpoint ID. * @return peer The peer address (OApp instance) associated with the corresponding endpoint. */ function peers(uint32 _eid) external view returns (bytes32 peer); /** * @notice Sets the peer address (OApp instance) for a corresponding endpoint. * @param _eid The endpoint ID. * @param _peer The address of the peer to be associated with the corresponding endpoint. */ function setPeer(uint32 _eid, bytes32 _peer) external; /** * @notice Sets the delegate address for the OApp Core. * @param _delegate The address of the delegate to be set. */ function setDelegate(address _delegate) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import { ILayerZeroReceiver, Origin } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroReceiver.sol"; interface IOAppReceiver is ILayerZeroReceiver { /** * @notice Indicates whether an address is an approved composeMsg sender to the Endpoint. * @param _origin The origin information containing the source endpoint and sender address. * - srcEid: The source chain endpoint ID. * - sender: The sender address on the src chain. * - nonce: The nonce of the message. * @param _message The lzReceive payload. * @param _sender The sender address. * @return isSender Is a valid sender. * * @dev Applications can optionally choose to implement a separate composeMsg sender that is NOT the bridging layer. * @dev The default sender IS the OAppReceiver implementer. */ function isComposeMsgSender( Origin calldata _origin, bytes calldata _message, address _sender ) external view returns (bool isSender); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import { MessagingReceipt, MessagingFee } from "../../oapp/OAppSender.sol"; /** * @dev Struct representing token parameters for the OFT send() operation. */ struct SendParam { uint32 dstEid; // Destination endpoint ID. bytes32 to; // Recipient address. uint256 amountLD; // Amount to send in local decimals. uint256 minAmountLD; // Minimum amount to send in local decimals. bytes extraOptions; // Additional options supplied by the caller to be used in the LayerZero message. bytes composeMsg; // The composed message for the send() operation. bytes oftCmd; // The OFT command to be executed, unused in default OFT implementations. } /** * @dev Struct representing OFT limit information. * @dev These amounts can change dynamically and are up the the specific oft implementation. */ struct OFTLimit { uint256 minAmountLD; // Minimum amount in local decimals that can be sent to the recipient. uint256 maxAmountLD; // Maximum amount in local decimals that can be sent to the recipient. } /** * @dev Struct representing OFT receipt information. */ struct OFTReceipt { uint256 amountSentLD; // Amount of tokens ACTUALLY debited from the sender in local decimals. // @dev In non-default implementations, the amountReceivedLD COULD differ from this value. uint256 amountReceivedLD; // Amount of tokens to be received on the remote side. } /** * @dev Struct representing OFT fee details. * @dev Future proof mechanism to provide a standardized way to communicate fees to things like a UI. */ struct OFTFeeDetail { int256 feeAmountLD; // Amount of the fee in local decimals. string description; // Description of the fee. } /** * @title IOFT * @dev Interface for the OftChain (OFT) token. * @dev Does not inherit ERC20 to accommodate usage by OFTAdapter as well. * @dev This specific interface ID is '0x02e49c2c'. */ interface IOFT { // Custom error messages error InvalidLocalDecimals(); error SlippageExceeded(uint256 amountLD, uint256 minAmountLD); // Events event OFTSent( bytes32 indexed guid, // GUID of the OFT message. uint32 dstEid, // Destination Endpoint ID. address indexed fromAddress, // Address of the sender on the src chain. uint256 amountSentLD, // Amount of tokens sent in local decimals. uint256 amountReceivedLD // Amount of tokens received in local decimals. ); event OFTReceived( bytes32 indexed guid, // GUID of the OFT message. uint32 srcEid, // Source Endpoint ID. address indexed toAddress, // Address of the recipient on the dst chain. uint256 amountReceivedLD // Amount of tokens received in local decimals. ); /** * @notice Retrieves interfaceID and the version of the OFT. * @return interfaceId The interface ID. * @return version The version. * * @dev interfaceId: This specific interface ID is '0x02e49c2c'. * @dev version: Indicates a cross-chain compatible msg encoding with other OFTs. * @dev If a new feature is added to the OFT cross-chain msg encoding, the version will be incremented. * ie. localOFT version(x,1) CAN send messages to remoteOFT version(x,1) */ function oftVersion() external view returns (bytes4 interfaceId, uint64 version); /** * @notice Retrieves the address of the token associated with the OFT. * @return token The address of the ERC20 token implementation. */ function token() external view returns (address); /** * @notice Indicates whether the OFT contract requires approval of the 'token()' to send. * @return requiresApproval Needs approval of the underlying token implementation. * * @dev Allows things like wallet implementers to determine integration requirements, * without understanding the underlying token implementation. */ function approvalRequired() external view returns (bool); /** * @notice Retrieves the shared decimals of the OFT. * @return sharedDecimals The shared decimals of the OFT. */ function sharedDecimals() external view returns (uint8); /** * @notice Provides a quote for OFT-related operations. * @param _sendParam The parameters for the send operation. * @return limit The OFT limit information. * @return oftFeeDetails The details of OFT fees. * @return receipt The OFT receipt information. */ function quoteOFT( SendParam calldata _sendParam ) external view returns (OFTLimit memory, OFTFeeDetail[] memory oftFeeDetails, OFTReceipt memory); /** * @notice Provides a quote for the send() operation. * @param _sendParam The parameters for the send() operation. * @param _payInLzToken Flag indicating whether the caller is paying in the LZ token. * @return fee The calculated LayerZero messaging fee from the send() operation. * * @dev MessagingFee: LayerZero msg fee * - nativeFee: The native fee. * - lzTokenFee: The lzToken fee. */ function quoteSend(SendParam calldata _sendParam, bool _payInLzToken) external view returns (MessagingFee memory); /** * @notice Executes the send() operation. * @param _sendParam The parameters for the send operation. * @param _fee The fee information supplied by the caller. * - nativeFee: The native fee. * - lzTokenFee: The lzToken fee. * @param _refundAddress The address to receive any excess funds from fees etc. on the src. * @return receipt The LayerZero messaging receipt from the send() operation. * @return oftReceipt The OFT receipt information. * * @dev MessagingReceipt: LayerZero msg receipt * - guid: The unique identifier for the sent message. * - nonce: The nonce of the sent message. * - fee: The LayerZero fee incurred for the message. */ function send( SendParam calldata _sendParam, MessagingFee calldata _fee, address _refundAddress ) external payable returns (MessagingReceipt memory, OFTReceipt memory); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; library OFTComposeMsgCodec { // Offset constants for decoding composed messages uint8 private constant NONCE_OFFSET = 8; uint8 private constant SRC_EID_OFFSET = 12; uint8 private constant AMOUNT_LD_OFFSET = 44; uint8 private constant COMPOSE_FROM_OFFSET = 76; /** * @dev Encodes a OFT composed message. * @param _nonce The nonce value. * @param _srcEid The source endpoint ID. * @param _amountLD The amount in local decimals. * @param _composeMsg The composed message. * @return _msg The encoded Composed message. */ function encode( uint64 _nonce, uint32 _srcEid, uint256 _amountLD, bytes memory _composeMsg // 0x[composeFrom][composeMsg] ) internal pure returns (bytes memory _msg) { _msg = abi.encodePacked(_nonce, _srcEid, _amountLD, _composeMsg); } /** * @dev Retrieves the nonce from the composed message. * @param _msg The message. * @return The nonce value. */ function nonce(bytes calldata _msg) internal pure returns (uint64) { return uint64(bytes8(_msg[:NONCE_OFFSET])); } /** * @dev Retrieves the source endpoint ID from the composed message. * @param _msg The message. * @return The source endpoint ID. */ function srcEid(bytes calldata _msg) internal pure returns (uint32) { return uint32(bytes4(_msg[NONCE_OFFSET:SRC_EID_OFFSET])); } /** * @dev Retrieves the amount in local decimals from the composed message. * @param _msg The message. * @return The amount in local decimals. */ function amountLD(bytes calldata _msg) internal pure returns (uint256) { return uint256(bytes32(_msg[SRC_EID_OFFSET:AMOUNT_LD_OFFSET])); } /** * @dev Retrieves the composeFrom value from the composed message. * @param _msg The message. * @return The composeFrom value. */ function composeFrom(bytes calldata _msg) internal pure returns (bytes32) { return bytes32(_msg[AMOUNT_LD_OFFSET:COMPOSE_FROM_OFFSET]); } /** * @dev Retrieves the composed message. * @param _msg The message. * @return The composed message. */ function composeMsg(bytes calldata _msg) internal pure returns (bytes memory) { return _msg[COMPOSE_FROM_OFFSET:]; } /** * @dev Converts an address to bytes32. * @param _addr The address to convert. * @return The bytes32 representation of the address. */ function addressToBytes32(address _addr) internal pure returns (bytes32) { return bytes32(uint256(uint160(_addr))); } /** * @dev Converts bytes32 to an address. * @param _b The bytes32 value to convert. * @return The address representation of bytes32. */ function bytes32ToAddress(bytes32 _b) internal pure returns (address) { return address(uint160(uint256(_b))); } }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; import { IMessageLibManager } from "./IMessageLibManager.sol"; import { IMessagingComposer } from "./IMessagingComposer.sol"; import { IMessagingChannel } from "./IMessagingChannel.sol"; import { IMessagingContext } from "./IMessagingContext.sol"; struct MessagingParams { uint32 dstEid; bytes32 receiver; bytes message; bytes options; bool payInLzToken; } struct MessagingReceipt { bytes32 guid; uint64 nonce; MessagingFee fee; } struct MessagingFee { uint256 nativeFee; uint256 lzTokenFee; } struct Origin { uint32 srcEid; bytes32 sender; uint64 nonce; } enum ExecutionState { NotExecutable, Executable, Executed } interface ILayerZeroEndpointV2 is IMessageLibManager, IMessagingComposer, IMessagingChannel, IMessagingContext { event PacketSent(bytes encodedPayload, bytes options, address sendLibrary); event PacketVerified(Origin origin, address receiver, bytes32 payloadHash); event PacketDelivered(Origin origin, address receiver); event LzReceiveAlert( address indexed receiver, address indexed executor, Origin origin, bytes32 guid, uint256 gas, uint256 value, bytes message, bytes extraData, bytes reason ); event LzTokenSet(address token); function quote(MessagingParams calldata _params, address _sender) external view returns (MessagingFee memory); function send( MessagingParams calldata _params, address _refundAddress ) external payable returns (MessagingReceipt memory); function verify(Origin calldata _origin, address _receiver, bytes32 _payloadHash) external; function verifiable( Origin calldata _origin, address _receiver, address _receiveLib, bytes32 _payloadHash ) external view returns (bool); function executable(Origin calldata _origin, address _receiver) external view returns (ExecutionState); function lzReceive( Origin calldata _origin, address _receiver, bytes32 _guid, bytes calldata _message, bytes calldata _extraData ) external payable; // oapp can burn messages partially by calling this function with its own business logic if messages are verified in order function clear(address _oapp, Origin calldata _origin, bytes32 _guid, bytes calldata _message) external; function setLzToken(address _lzToken) external; function lzToken() external view returns (address); function nativeToken() external view returns (address); function setDelegate(address _delegate) external; }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; import { Origin } from "./ILayerZeroEndpointV2.sol"; interface ILayerZeroReceiver { function allowInitializePath(Origin calldata _origin) external view returns (bool); // todo: move to OAppReceiver? it is just convention for executor. we may can change it in a new Receiver version function nextNonce(uint32 _eid, bytes32 _sender) external view returns (uint64); function lzReceive( Origin calldata _origin, bytes32 _guid, bytes calldata _message, address _executor, bytes calldata _extraData ) external payable; }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; struct SetConfigParam { uint32 eid; uint32 configType; bytes config; } interface IMessageLibManager { struct Timeout { address lib; uint256 expiry; } event LibraryRegistered(address newLib); event DefaultSendLibrarySet(uint32 eid, address newLib); event DefaultReceiveLibrarySet(uint32 eid, address oldLib, address newLib); event DefaultReceiveLibraryTimeoutSet(uint32 eid, address oldLib, uint256 expiry); event SendLibrarySet(address sender, uint32 eid, address newLib); event ReceiveLibrarySet(address receiver, uint32 eid, address oldLib, address newLib); event ReceiveLibraryTimeoutSet(address receiver, uint32 eid, address oldLib, uint256 timeout); function registerLibrary(address _lib) external; function isRegisteredLibrary(address _lib) external view returns (bool); function getRegisteredLibraries() external view returns (address[] memory); function setDefaultSendLibrary(uint32 _eid, address _newLib) external; function defaultSendLibrary(uint32 _eid) external view returns (address); function setDefaultReceiveLibrary(uint32 _eid, address _newLib, uint256 _timeout) external; function defaultReceiveLibrary(uint32 _eid) external view returns (address); function setDefaultReceiveLibraryTimeout(uint32 _eid, address _lib, uint256 _expiry) external; function defaultReceiveLibraryTimeout(uint32 _eid) external view returns (address lib, uint256 expiry); function isSupportedEid(uint32 _eid) external view returns (bool); /// ------------------- OApp interfaces ------------------- function setSendLibrary(address _oapp, uint32 _eid, address _newLib) external; function getSendLibrary(address _sender, uint32 _eid) external view returns (address lib); function isDefaultSendLibrary(address _sender, uint32 _eid) external view returns (bool); function setReceiveLibrary(address _oapp, uint32 _eid, address _newLib, uint256 _gracePeriod) external; function getReceiveLibrary(address _receiver, uint32 _eid) external view returns (address lib, bool isDefault); function setReceiveLibraryTimeout(address _oapp, uint32 _eid, address _lib, uint256 _gracePeriod) external; function receiveLibraryTimeout(address _receiver, uint32 _eid) external view returns (address lib, uint256 expiry); function setConfig(address _oapp, address _lib, SetConfigParam[] calldata _params) external; function getConfig( address _oapp, address _lib, uint32 _eid, uint32 _configType ) external view returns (bytes memory config); }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; interface IMessagingChannel { event InboundNonceSkipped(uint32 srcEid, bytes32 sender, address receiver, uint64 nonce); event PacketNilified(uint32 srcEid, bytes32 sender, address receiver, uint64 nonce, bytes32 payloadHash); event PacketBurnt(uint32 srcEid, bytes32 sender, address receiver, uint64 nonce, bytes32 payloadHash); function eid() external view returns (uint32); // this is an emergency function if a message cannot be verified for some reasons // required to provide _nextNonce to avoid race condition function skip(address _oapp, uint32 _srcEid, bytes32 _sender, uint64 _nonce) external; function nilify(address _oapp, uint32 _srcEid, bytes32 _sender, uint64 _nonce, bytes32 _payloadHash) external; function burn(address _oapp, uint32 _srcEid, bytes32 _sender, uint64 _nonce, bytes32 _payloadHash) external; function nextGuid(address _sender, uint32 _dstEid, bytes32 _receiver) external view returns (bytes32); function inboundNonce(address _receiver, uint32 _srcEid, bytes32 _sender) external view returns (uint64); function outboundNonce(address _sender, uint32 _dstEid, bytes32 _receiver) external view returns (uint64); function inboundPayloadHash( address _receiver, uint32 _srcEid, bytes32 _sender, uint64 _nonce ) external view returns (bytes32); }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; interface IMessagingComposer { event ComposeSent(address from, address to, bytes32 guid, uint16 index, bytes message); event ComposeDelivered(address from, address to, bytes32 guid, uint16 index); event LzComposeAlert( address indexed from, address indexed to, address indexed executor, bytes32 guid, uint16 index, uint256 gas, uint256 value, bytes message, bytes extraData, bytes reason ); function composeQueue( address _from, address _to, bytes32 _guid, uint16 _index ) external view returns (bytes32 messageHash); function sendCompose(address _to, bytes32 _guid, uint16 _index, bytes calldata _message) external; function lzCompose( address _from, address _to, bytes32 _guid, uint16 _index, bytes calldata _message, bytes calldata _extraData ) external payable; }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; interface IMessagingContext { function isSendingMessage() external view returns (bool); function getSendContext() external view returns (uint32 dstEid, address sender); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor() { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC5267.sol) pragma solidity ^0.8.0; interface IERC5267 { /** * @dev MAY be emitted to signal that the domain could have changed. */ event EIP712DomainChanged(); /** * @dev returns the fields and values that describe the domain separator used by this contract for EIP-712 * signature. */ function eip712Domain() external view returns ( bytes1 fields, string memory name, string memory version, uint256 chainId, address verifyingContract, bytes32 salt, uint256[] memory extensions ); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/ERC20.sol) pragma solidity ^0.8.0; import "./IERC20.sol"; import "./extensions/IERC20Metadata.sol"; import "../../utils/Context.sol"; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20PresetMinterPauser}. * * TIP: For a detailed writeup see our guide * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * The default value of {decimals} is 18. To change this, you should override * this function so it returns a different value. * * We have followed general OpenZeppelin Contracts guidelines: functions revert * instead returning `false` on failure. This behavior is nonetheless * conventional and does not conflict with the expectations of ERC20 * applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20 is Context, IERC20, IERC20Metadata { mapping(address => uint256) private _balances; mapping(address => mapping(address => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; /** * @dev Sets the values for {name} and {symbol}. * * All two of these values are immutable: they can only be set once during * construction. */ constructor(string memory name_, string memory symbol_) { _name = name_; _symbol = symbol_; } /** * @dev Returns the name of the token. */ function name() public view virtual override returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual override returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5.05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the default value returned by this function, unless * it's overridden. * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view virtual override returns (uint8) { return 18; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view virtual override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view virtual override returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `to` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address to, uint256 amount) public virtual override returns (bool) { address owner = _msgSender(); _transfer(owner, to, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on * `transferFrom`. This is semantically equivalent to an infinite approval. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public virtual override returns (bool) { address owner = _msgSender(); _approve(owner, spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}. * * NOTE: Does not update the allowance if the current allowance * is the maximum `uint256`. * * Requirements: * * - `from` and `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. * - the caller must have allowance for ``from``'s tokens of at least * `amount`. */ function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) { address spender = _msgSender(); _spendAllowance(from, spender, amount); _transfer(from, to, amount); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { address owner = _msgSender(); _approve(owner, spender, allowance(owner, spender) + addedValue); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { address owner = _msgSender(); uint256 currentAllowance = allowance(owner, spender); require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero"); unchecked { _approve(owner, spender, currentAllowance - subtractedValue); } return true; } /** * @dev Moves `amount` of tokens from `from` to `to`. * * This internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. */ function _transfer(address from, address to, uint256 amount) internal virtual { require(from != address(0), "ERC20: transfer from the zero address"); require(to != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(from, to, amount); uint256 fromBalance = _balances[from]; require(fromBalance >= amount, "ERC20: transfer amount exceeds balance"); unchecked { _balances[from] = fromBalance - amount; // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by // decrementing then incrementing. _balances[to] += amount; } emit Transfer(from, to, amount); _afterTokenTransfer(from, to, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply += amount; unchecked { // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above. _balances[account] += amount; } emit Transfer(address(0), account, amount); _afterTokenTransfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); uint256 accountBalance = _balances[account]; require(accountBalance >= amount, "ERC20: burn amount exceeds balance"); unchecked { _balances[account] = accountBalance - amount; // Overflow not possible: amount <= accountBalance <= totalSupply. _totalSupply -= amount; } emit Transfer(account, address(0), amount); _afterTokenTransfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. * * This internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve(address owner, address spender, uint256 amount) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @dev Updates `owner` s allowance for `spender` based on spent `amount`. * * Does not update the allowance amount in case of infinite allowance. * Revert if not enough allowance is available. * * Might emit an {Approval} event. */ function _spendAllowance(address owner, address spender, uint256 amount) internal virtual { uint256 currentAllowance = allowance(owner, spender); if (currentAllowance != type(uint256).max) { require(currentAllowance >= amount, "ERC20: insufficient allowance"); unchecked { _approve(owner, spender, currentAllowance - amount); } } } /** * @dev Hook that is called before any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * will be transferred to `to`. * - when `from` is zero, `amount` tokens will be minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {} /** * @dev Hook that is called after any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * has been transferred to `to`. * - when `from` is zero, `amount` tokens have been minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens have been burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {} }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 amount) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.4) (token/ERC20/extensions/ERC20Permit.sol) pragma solidity ^0.8.0; import "./IERC20Permit.sol"; import "../ERC20.sol"; import "../../../utils/cryptography/ECDSA.sol"; import "../../../utils/cryptography/EIP712.sol"; import "../../../utils/Counters.sol"; /** * @dev Implementation of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. * * _Available since v3.4._ */ abstract contract ERC20Permit is ERC20, IERC20Permit, EIP712 { using Counters for Counters.Counter; mapping(address => Counters.Counter) private _nonces; // solhint-disable-next-line var-name-mixedcase bytes32 private constant _PERMIT_TYPEHASH = keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); /** * @dev In previous versions `_PERMIT_TYPEHASH` was declared as `immutable`. * However, to ensure consistency with the upgradeable transpiler, we will continue * to reserve a slot. * @custom:oz-renamed-from _PERMIT_TYPEHASH */ // solhint-disable-next-line var-name-mixedcase bytes32 private _PERMIT_TYPEHASH_DEPRECATED_SLOT; /** * @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `"1"`. * * It's a good idea to use the same `name` that is defined as the ERC20 token name. */ constructor(string memory name) EIP712(name, "1") {} /** * @inheritdoc IERC20Permit */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) public virtual override { require(block.timestamp <= deadline, "ERC20Permit: expired deadline"); bytes32 structHash = keccak256(abi.encode(_PERMIT_TYPEHASH, owner, spender, value, _useNonce(owner), deadline)); bytes32 hash = _hashTypedDataV4(structHash); address signer = ECDSA.recover(hash, v, r, s); require(signer == owner, "ERC20Permit: invalid signature"); _approve(owner, spender, value); } /** * @inheritdoc IERC20Permit */ function nonces(address owner) public view virtual override returns (uint256) { return _nonces[owner].current(); } /** * @inheritdoc IERC20Permit */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view override returns (bytes32) { return _domainSeparatorV4(); } /** * @dev "Consume a nonce": return the current value and increment. * * _Available since v4.1._ */ function _useNonce(address owner) internal virtual returns (uint256 current) { Counters.Counter storage nonce = _nonces[owner]; current = nonce.current(); nonce.increment(); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. * * _Available since v4.1._ */ interface IERC20Metadata is IERC20 { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.4) (token/ERC20/extensions/IERC20Permit.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. * * ==== Security Considerations * * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be * considered as an intention to spend the allowance in any specific way. The second is that because permits have * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be * generally recommended is: * * ```solidity * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public { * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {} * doThing(..., value); * } * * function doThing(..., uint256 value) public { * token.safeTransferFrom(msg.sender, address(this), value); * ... * } * ``` * * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also * {SafeERC20-safeTransferFrom}). * * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so * contracts should have entry points that don't rely on permit. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. * * CAUTION: See Security Considerations above. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; import "../extensions/IERC20Permit.sol"; import "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; /** * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } /** * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful. */ function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove(IERC20 token, address spender, uint256 value) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } /** * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 oldAllowance = token.allowance(address(this), spender); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value)); } /** * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value)); } } /** * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval * to be set to zero before setting it to a non-zero value, such as USDT. */ function forceApprove(IERC20 token, address spender, uint256 value) internal { bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value); if (!_callOptionalReturnBool(token, approvalCall)) { _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0)); _callOptionalReturn(token, approvalCall); } } /** * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`. * Revert on invalid signature. */ function safePermit( IERC20Permit token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit(owner, spender, value, deadline, v, r, s); uint256 nonceAfter = token.nonces(owner); require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). * * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead. */ function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false // and not revert is the subcall reverts. (bool success, bytes memory returndata) = address(token).call(data); return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * * Furthermore, `isContract` will also return true if the target contract within * the same transaction is already scheduled for destruction by `SELFDESTRUCT`, * which only has an effect at the end of a transaction. * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } function _contextSuffixLength() internal view virtual returns (uint256) { return 0; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Counters.sol) pragma solidity ^0.8.0; /** * @title Counters * @author Matt Condon (@shrugs) * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number * of elements in a mapping, issuing ERC721 ids, or counting request ids. * * Include with `using Counters for Counters.Counter;` */ library Counters { struct Counter { // This variable should never be directly accessed by users of the library: interactions must be restricted to // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add // this feature: see https://github.com/ethereum/solidity/issues/4637 uint256 _value; // default: 0 } function current(Counter storage counter) internal view returns (uint256) { return counter._value; } function increment(Counter storage counter) internal { unchecked { counter._value += 1; } } function decrement(Counter storage counter) internal { uint256 value = counter._value; require(value > 0, "Counter: decrement overflow"); unchecked { counter._value = value - 1; } } function reset(Counter storage counter) internal { counter._value = 0; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/ShortStrings.sol) pragma solidity ^0.8.8; import "./StorageSlot.sol"; // | string | 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | // | length | 0x BB | type ShortString is bytes32; /** * @dev This library provides functions to convert short memory strings * into a `ShortString` type that can be used as an immutable variable. * * Strings of arbitrary length can be optimized using this library if * they are short enough (up to 31 bytes) by packing them with their * length (1 byte) in a single EVM word (32 bytes). Additionally, a * fallback mechanism can be used for every other case. * * Usage example: * * ```solidity * contract Named { * using ShortStrings for *; * * ShortString private immutable _name; * string private _nameFallback; * * constructor(string memory contractName) { * _name = contractName.toShortStringWithFallback(_nameFallback); * } * * function name() external view returns (string memory) { * return _name.toStringWithFallback(_nameFallback); * } * } * ``` */ library ShortStrings { // Used as an identifier for strings longer than 31 bytes. bytes32 private constant _FALLBACK_SENTINEL = 0x00000000000000000000000000000000000000000000000000000000000000FF; error StringTooLong(string str); error InvalidShortString(); /** * @dev Encode a string of at most 31 chars into a `ShortString`. * * This will trigger a `StringTooLong` error is the input string is too long. */ function toShortString(string memory str) internal pure returns (ShortString) { bytes memory bstr = bytes(str); if (bstr.length > 31) { revert StringTooLong(str); } return ShortString.wrap(bytes32(uint256(bytes32(bstr)) | bstr.length)); } /** * @dev Decode a `ShortString` back to a "normal" string. */ function toString(ShortString sstr) internal pure returns (string memory) { uint256 len = byteLength(sstr); // using `new string(len)` would work locally but is not memory safe. string memory str = new string(32); /// @solidity memory-safe-assembly assembly { mstore(str, len) mstore(add(str, 0x20), sstr) } return str; } /** * @dev Return the length of a `ShortString`. */ function byteLength(ShortString sstr) internal pure returns (uint256) { uint256 result = uint256(ShortString.unwrap(sstr)) & 0xFF; if (result > 31) { revert InvalidShortString(); } return result; } /** * @dev Encode a string into a `ShortString`, or write it to storage if it is too long. */ function toShortStringWithFallback(string memory value, string storage store) internal returns (ShortString) { if (bytes(value).length < 32) { return toShortString(value); } else { StorageSlot.getStringSlot(store).value = value; return ShortString.wrap(_FALLBACK_SENTINEL); } } /** * @dev Decode a string that was encoded to `ShortString` or written to storage using {setWithFallback}. */ function toStringWithFallback(ShortString value, string storage store) internal pure returns (string memory) { if (ShortString.unwrap(value) != _FALLBACK_SENTINEL) { return toString(value); } else { return store; } } /** * @dev Return the length of a string that was encoded to `ShortString` or written to storage using {setWithFallback}. * * WARNING: This will return the "byte length" of the string. This may not reflect the actual length in terms of * actual characters as the UTF-8 encoding of a single character can span over multiple bytes. */ function byteLengthWithFallback(ShortString value, string storage store) internal view returns (uint256) { if (ShortString.unwrap(value) != _FALLBACK_SENTINEL) { return byteLength(value); } else { return bytes(store).length; } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/StorageSlot.sol) // This file was procedurally generated from scripts/generate/templates/StorageSlot.js. pragma solidity ^0.8.0; /** * @dev Library for reading and writing primitive types to specific storage slots. * * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts. * This library helps with reading and writing to such slots without the need for inline assembly. * * The functions in this library return Slot structs that contain a `value` member that can be used to read or write. * * Example usage to set ERC1967 implementation slot: * ```solidity * contract ERC1967 { * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; * * function _getImplementation() internal view returns (address) { * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; * } * * function _setImplementation(address newImplementation) internal { * require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract"); * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; * } * } * ``` * * _Available since v4.1 for `address`, `bool`, `bytes32`, `uint256`._ * _Available since v4.9 for `string`, `bytes`._ */ library StorageSlot { struct AddressSlot { address value; } struct BooleanSlot { bool value; } struct Bytes32Slot { bytes32 value; } struct Uint256Slot { uint256 value; } struct StringSlot { string value; } struct BytesSlot { bytes value; } /** * @dev Returns an `AddressSlot` with member `value` located at `slot`. */ function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `BooleanSlot` with member `value` located at `slot`. */ function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `Bytes32Slot` with member `value` located at `slot`. */ function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `Uint256Slot` with member `value` located at `slot`. */ function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `StringSlot` with member `value` located at `slot`. */ function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `StringSlot` representation of the string storage pointer `store`. */ function getStringSlot(string storage store) internal pure returns (StringSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := store.slot } } /** * @dev Returns an `BytesSlot` with member `value` located at `slot`. */ function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`. */ function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := store.slot } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol) pragma solidity ^0.8.0; import "./math/Math.sol"; import "./math/SignedMath.sol"; /** * @dev String operations. */ library Strings { bytes16 private constant _SYMBOLS = "0123456789abcdef"; uint8 private constant _ADDRESS_LENGTH = 20; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { unchecked { uint256 length = Math.log10(value) + 1; string memory buffer = new string(length); uint256 ptr; /// @solidity memory-safe-assembly assembly { ptr := add(buffer, add(32, length)) } while (true) { ptr--; /// @solidity memory-safe-assembly assembly { mstore8(ptr, byte(mod(value, 10), _SYMBOLS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `int256` to its ASCII `string` decimal representation. */ function toString(int256 value) internal pure returns (string memory) { return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value)))); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { unchecked { return toHexString(value, Math.log256(value) + 1); } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = _SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); } /** * @dev Returns true if the two strings are equal. */ function equal(string memory a, string memory b) internal pure returns (bool) { return keccak256(bytes(a)) == keccak256(bytes(b)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/ECDSA.sol) pragma solidity ^0.8.0; import "../Strings.sol"; /** * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. * * These functions can be used to verify that a message was signed by the holder * of the private keys of a given address. */ library ECDSA { enum RecoverError { NoError, InvalidSignature, InvalidSignatureLength, InvalidSignatureS, InvalidSignatureV // Deprecated in v4.8 } function _throwError(RecoverError error) private pure { if (error == RecoverError.NoError) { return; // no error: do nothing } else if (error == RecoverError.InvalidSignature) { revert("ECDSA: invalid signature"); } else if (error == RecoverError.InvalidSignatureLength) { revert("ECDSA: invalid signature length"); } else if (error == RecoverError.InvalidSignatureS) { revert("ECDSA: invalid signature 's' value"); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature` or error string. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. * * Documentation for signature generation: * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js] * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers] * * _Available since v4.3._ */ function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) { if (signature.length == 65) { bytes32 r; bytes32 s; uint8 v; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. /// @solidity memory-safe-assembly assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } return tryRecover(hash, v, r, s); } else { return (address(0), RecoverError.InvalidSignatureLength); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature`. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, signature); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately. * * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures] * * _Available since v4.3._ */ function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError) { bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff); uint8 v = uint8((uint256(vs) >> 255) + 27); return tryRecover(hash, v, r, s); } /** * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately. * * _Available since v4.2._ */ function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, r, vs); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `v`, * `r` and `s` signature fields separately. * * _Available since v4.3._ */ function tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address, RecoverError) { // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { return (address(0), RecoverError.InvalidSignatureS); } // If the signature is valid (and not malleable), return the signer address address signer = ecrecover(hash, v, r, s); if (signer == address(0)) { return (address(0), RecoverError.InvalidSignature); } return (signer, RecoverError.NoError); } /** * @dev Overload of {ECDSA-recover} that receives the `v`, * `r` and `s` signature fields separately. */ function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, v, r, s); _throwError(error); return recovered; } /** * @dev Returns an Ethereum Signed Message, created from a `hash`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 message) { // 32 is the length in bytes of hash, // enforced by the type signature above /// @solidity memory-safe-assembly assembly { mstore(0x00, "\x19Ethereum Signed Message:\n32") mstore(0x1c, hash) message := keccak256(0x00, 0x3c) } } /** * @dev Returns an Ethereum Signed Message, created from `s`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s)); } /** * @dev Returns an Ethereum Signed Typed Data, created from a * `domainSeparator` and a `structHash`. This produces hash corresponding * to the one signed with the * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] * JSON-RPC method as part of EIP-712. * * See {recover}. */ function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 data) { /// @solidity memory-safe-assembly assembly { let ptr := mload(0x40) mstore(ptr, "\x19\x01") mstore(add(ptr, 0x02), domainSeparator) mstore(add(ptr, 0x22), structHash) data := keccak256(ptr, 0x42) } } /** * @dev Returns an Ethereum Signed Data with intended validator, created from a * `validator` and `data` according to the version 0 of EIP-191. * * See {recover}. */ function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19\x00", validator, data)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/EIP712.sol) pragma solidity ^0.8.8; import "./ECDSA.sol"; import "../ShortStrings.sol"; import "../../interfaces/IERC5267.sol"; /** * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data. * * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible, * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding * they need in their contracts using a combination of `abi.encode` and `keccak256`. * * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA * ({_hashTypedDataV4}). * * The implementation of the domain separator was designed to be as efficient as possible while still properly updating * the chain id to protect against replay attacks on an eventual fork of the chain. * * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask]. * * NOTE: In the upgradeable version of this contract, the cached values will correspond to the address, and the domain * separator of the implementation contract. This will cause the `_domainSeparatorV4` function to always rebuild the * separator from the immutable values, which is cheaper than accessing a cached version in cold storage. * * _Available since v3.4._ * * @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment */ abstract contract EIP712 is IERC5267 { using ShortStrings for *; bytes32 private constant _TYPE_HASH = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"); // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to // invalidate the cached domain separator if the chain id changes. bytes32 private immutable _cachedDomainSeparator; uint256 private immutable _cachedChainId; address private immutable _cachedThis; bytes32 private immutable _hashedName; bytes32 private immutable _hashedVersion; ShortString private immutable _name; ShortString private immutable _version; string private _nameFallback; string private _versionFallback; /** * @dev Initializes the domain separator and parameter caches. * * The meaning of `name` and `version` is specified in * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]: * * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol. * - `version`: the current major version of the signing domain. * * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart * contract upgrade]. */ constructor(string memory name, string memory version) { _name = name.toShortStringWithFallback(_nameFallback); _version = version.toShortStringWithFallback(_versionFallback); _hashedName = keccak256(bytes(name)); _hashedVersion = keccak256(bytes(version)); _cachedChainId = block.chainid; _cachedDomainSeparator = _buildDomainSeparator(); _cachedThis = address(this); } /** * @dev Returns the domain separator for the current chain. */ function _domainSeparatorV4() internal view returns (bytes32) { if (address(this) == _cachedThis && block.chainid == _cachedChainId) { return _cachedDomainSeparator; } else { return _buildDomainSeparator(); } } function _buildDomainSeparator() private view returns (bytes32) { return keccak256(abi.encode(_TYPE_HASH, _hashedName, _hashedVersion, block.chainid, address(this))); } /** * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this * function returns the hash of the fully encoded EIP712 message for this domain. * * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example: * * ```solidity * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode( * keccak256("Mail(address to,string contents)"), * mailTo, * keccak256(bytes(mailContents)) * ))); * address signer = ECDSA.recover(digest, signature); * ``` */ function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) { return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash); } /** * @dev See {EIP-5267}. * * _Available since v4.9._ */ function eip712Domain() public view virtual override returns ( bytes1 fields, string memory name, string memory version, uint256 chainId, address verifyingContract, bytes32 salt, uint256[] memory extensions ) { return ( hex"0f", // 01111 _name.toStringWithFallback(_nameFallback), _version.toStringWithFallback(_versionFallback), block.chainid, address(this), bytes32(0), new uint256[](0) ); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { // Solidity will revert if denominator == 0, unlike the div opcode on its own. // The surrounding unchecked block does not change this fact. // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1, "Math: mulDiv overflow"); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2, rounded down, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10, rounded down, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10 ** 64) { value /= 10 ** 64; result += 64; } if (value >= 10 ** 32) { value /= 10 ** 32; result += 32; } if (value >= 10 ** 16) { value /= 10 ** 16; result += 16; } if (value >= 10 ** 8) { value /= 10 ** 8; result += 8; } if (value >= 10 ** 4) { value /= 10 ** 4; result += 4; } if (value >= 10 ** 2) { value /= 10 ** 2; result += 2; } if (value >= 10 ** 1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0); } } /** * @dev Return the log in base 256, rounded down, of a positive value. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 256, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SafeCast.sol) // This file was procedurally generated from scripts/generate/templates/SafeCast.js. pragma solidity ^0.8.0; /** * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow * checks. * * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can * easily result in undesired exploitation or bugs, since developers usually * assume that overflows raise errors. `SafeCast` restores this intuition by * reverting the transaction when such an operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. * * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing * all math on `uint256` and `int256` and then downcasting. */ library SafeCast { /** * @dev Returns the downcasted uint248 from uint256, reverting on * overflow (when the input is greater than largest uint248). * * Counterpart to Solidity's `uint248` operator. * * Requirements: * * - input must fit into 248 bits * * _Available since v4.7._ */ function toUint248(uint256 value) internal pure returns (uint248) { require(value <= type(uint248).max, "SafeCast: value doesn't fit in 248 bits"); return uint248(value); } /** * @dev Returns the downcasted uint240 from uint256, reverting on * overflow (when the input is greater than largest uint240). * * Counterpart to Solidity's `uint240` operator. * * Requirements: * * - input must fit into 240 bits * * _Available since v4.7._ */ function toUint240(uint256 value) internal pure returns (uint240) { require(value <= type(uint240).max, "SafeCast: value doesn't fit in 240 bits"); return uint240(value); } /** * @dev Returns the downcasted uint232 from uint256, reverting on * overflow (when the input is greater than largest uint232). * * Counterpart to Solidity's `uint232` operator. * * Requirements: * * - input must fit into 232 bits * * _Available since v4.7._ */ function toUint232(uint256 value) internal pure returns (uint232) { require(value <= type(uint232).max, "SafeCast: value doesn't fit in 232 bits"); return uint232(value); } /** * @dev Returns the downcasted uint224 from uint256, reverting on * overflow (when the input is greater than largest uint224). * * Counterpart to Solidity's `uint224` operator. * * Requirements: * * - input must fit into 224 bits * * _Available since v4.2._ */ function toUint224(uint256 value) internal pure returns (uint224) { require(value <= type(uint224).max, "SafeCast: value doesn't fit in 224 bits"); return uint224(value); } /** * @dev Returns the downcasted uint216 from uint256, reverting on * overflow (when the input is greater than largest uint216). * * Counterpart to Solidity's `uint216` operator. * * Requirements: * * - input must fit into 216 bits * * _Available since v4.7._ */ function toUint216(uint256 value) internal pure returns (uint216) { require(value <= type(uint216).max, "SafeCast: value doesn't fit in 216 bits"); return uint216(value); } /** * @dev Returns the downcasted uint208 from uint256, reverting on * overflow (when the input is greater than largest uint208). * * Counterpart to Solidity's `uint208` operator. * * Requirements: * * - input must fit into 208 bits * * _Available since v4.7._ */ function toUint208(uint256 value) internal pure returns (uint208) { require(value <= type(uint208).max, "SafeCast: value doesn't fit in 208 bits"); return uint208(value); } /** * @dev Returns the downcasted uint200 from uint256, reverting on * overflow (when the input is greater than largest uint200). * * Counterpart to Solidity's `uint200` operator. * * Requirements: * * - input must fit into 200 bits * * _Available since v4.7._ */ function toUint200(uint256 value) internal pure returns (uint200) { require(value <= type(uint200).max, "SafeCast: value doesn't fit in 200 bits"); return uint200(value); } /** * @dev Returns the downcasted uint192 from uint256, reverting on * overflow (when the input is greater than largest uint192). * * Counterpart to Solidity's `uint192` operator. * * Requirements: * * - input must fit into 192 bits * * _Available since v4.7._ */ function toUint192(uint256 value) internal pure returns (uint192) { require(value <= type(uint192).max, "SafeCast: value doesn't fit in 192 bits"); return uint192(value); } /** * @dev Returns the downcasted uint184 from uint256, reverting on * overflow (when the input is greater than largest uint184). * * Counterpart to Solidity's `uint184` operator. * * Requirements: * * - input must fit into 184 bits * * _Available since v4.7._ */ function toUint184(uint256 value) internal pure returns (uint184) { require(value <= type(uint184).max, "SafeCast: value doesn't fit in 184 bits"); return uint184(value); } /** * @dev Returns the downcasted uint176 from uint256, reverting on * overflow (when the input is greater than largest uint176). * * Counterpart to Solidity's `uint176` operator. * * Requirements: * * - input must fit into 176 bits * * _Available since v4.7._ */ function toUint176(uint256 value) internal pure returns (uint176) { require(value <= type(uint176).max, "SafeCast: value doesn't fit in 176 bits"); return uint176(value); } /** * @dev Returns the downcasted uint168 from uint256, reverting on * overflow (when the input is greater than largest uint168). * * Counterpart to Solidity's `uint168` operator. * * Requirements: * * - input must fit into 168 bits * * _Available since v4.7._ */ function toUint168(uint256 value) internal pure returns (uint168) { require(value <= type(uint168).max, "SafeCast: value doesn't fit in 168 bits"); return uint168(value); } /** * @dev Returns the downcasted uint160 from uint256, reverting on * overflow (when the input is greater than largest uint160). * * Counterpart to Solidity's `uint160` operator. * * Requirements: * * - input must fit into 160 bits * * _Available since v4.7._ */ function toUint160(uint256 value) internal pure returns (uint160) { require(value <= type(uint160).max, "SafeCast: value doesn't fit in 160 bits"); return uint160(value); } /** * @dev Returns the downcasted uint152 from uint256, reverting on * overflow (when the input is greater than largest uint152). * * Counterpart to Solidity's `uint152` operator. * * Requirements: * * - input must fit into 152 bits * * _Available since v4.7._ */ function toUint152(uint256 value) internal pure returns (uint152) { require(value <= type(uint152).max, "SafeCast: value doesn't fit in 152 bits"); return uint152(value); } /** * @dev Returns the downcasted uint144 from uint256, reverting on * overflow (when the input is greater than largest uint144). * * Counterpart to Solidity's `uint144` operator. * * Requirements: * * - input must fit into 144 bits * * _Available since v4.7._ */ function toUint144(uint256 value) internal pure returns (uint144) { require(value <= type(uint144).max, "SafeCast: value doesn't fit in 144 bits"); return uint144(value); } /** * @dev Returns the downcasted uint136 from uint256, reverting on * overflow (when the input is greater than largest uint136). * * Counterpart to Solidity's `uint136` operator. * * Requirements: * * - input must fit into 136 bits * * _Available since v4.7._ */ function toUint136(uint256 value) internal pure returns (uint136) { require(value <= type(uint136).max, "SafeCast: value doesn't fit in 136 bits"); return uint136(value); } /** * @dev Returns the downcasted uint128 from uint256, reverting on * overflow (when the input is greater than largest uint128). * * Counterpart to Solidity's `uint128` operator. * * Requirements: * * - input must fit into 128 bits * * _Available since v2.5._ */ function toUint128(uint256 value) internal pure returns (uint128) { require(value <= type(uint128).max, "SafeCast: value doesn't fit in 128 bits"); return uint128(value); } /** * @dev Returns the downcasted uint120 from uint256, reverting on * overflow (when the input is greater than largest uint120). * * Counterpart to Solidity's `uint120` operator. * * Requirements: * * - input must fit into 120 bits * * _Available since v4.7._ */ function toUint120(uint256 value) internal pure returns (uint120) { require(value <= type(uint120).max, "SafeCast: value doesn't fit in 120 bits"); return uint120(value); } /** * @dev Returns the downcasted uint112 from uint256, reverting on * overflow (when the input is greater than largest uint112). * * Counterpart to Solidity's `uint112` operator. * * Requirements: * * - input must fit into 112 bits * * _Available since v4.7._ */ function toUint112(uint256 value) internal pure returns (uint112) { require(value <= type(uint112).max, "SafeCast: value doesn't fit in 112 bits"); return uint112(value); } /** * @dev Returns the downcasted uint104 from uint256, reverting on * overflow (when the input is greater than largest uint104). * * Counterpart to Solidity's `uint104` operator. * * Requirements: * * - input must fit into 104 bits * * _Available since v4.7._ */ function toUint104(uint256 value) internal pure returns (uint104) { require(value <= type(uint104).max, "SafeCast: value doesn't fit in 104 bits"); return uint104(value); } /** * @dev Returns the downcasted uint96 from uint256, reverting on * overflow (when the input is greater than largest uint96). * * Counterpart to Solidity's `uint96` operator. * * Requirements: * * - input must fit into 96 bits * * _Available since v4.2._ */ function toUint96(uint256 value) internal pure returns (uint96) { require(value <= type(uint96).max, "SafeCast: value doesn't fit in 96 bits"); return uint96(value); } /** * @dev Returns the downcasted uint88 from uint256, reverting on * overflow (when the input is greater than largest uint88). * * Counterpart to Solidity's `uint88` operator. * * Requirements: * * - input must fit into 88 bits * * _Available since v4.7._ */ function toUint88(uint256 value) internal pure returns (uint88) { require(value <= type(uint88).max, "SafeCast: value doesn't fit in 88 bits"); return uint88(value); } /** * @dev Returns the downcasted uint80 from uint256, reverting on * overflow (when the input is greater than largest uint80). * * Counterpart to Solidity's `uint80` operator. * * Requirements: * * - input must fit into 80 bits * * _Available since v4.7._ */ function toUint80(uint256 value) internal pure returns (uint80) { require(value <= type(uint80).max, "SafeCast: value doesn't fit in 80 bits"); return uint80(value); } /** * @dev Returns the downcasted uint72 from uint256, reverting on * overflow (when the input is greater than largest uint72). * * Counterpart to Solidity's `uint72` operator. * * Requirements: * * - input must fit into 72 bits * * _Available since v4.7._ */ function toUint72(uint256 value) internal pure returns (uint72) { require(value <= type(uint72).max, "SafeCast: value doesn't fit in 72 bits"); return uint72(value); } /** * @dev Returns the downcasted uint64 from uint256, reverting on * overflow (when the input is greater than largest uint64). * * Counterpart to Solidity's `uint64` operator. * * Requirements: * * - input must fit into 64 bits * * _Available since v2.5._ */ function toUint64(uint256 value) internal pure returns (uint64) { require(value <= type(uint64).max, "SafeCast: value doesn't fit in 64 bits"); return uint64(value); } /** * @dev Returns the downcasted uint56 from uint256, reverting on * overflow (when the input is greater than largest uint56). * * Counterpart to Solidity's `uint56` operator. * * Requirements: * * - input must fit into 56 bits * * _Available since v4.7._ */ function toUint56(uint256 value) internal pure returns (uint56) { require(value <= type(uint56).max, "SafeCast: value doesn't fit in 56 bits"); return uint56(value); } /** * @dev Returns the downcasted uint48 from uint256, reverting on * overflow (when the input is greater than largest uint48). * * Counterpart to Solidity's `uint48` operator. * * Requirements: * * - input must fit into 48 bits * * _Available since v4.7._ */ function toUint48(uint256 value) internal pure returns (uint48) { require(value <= type(uint48).max, "SafeCast: value doesn't fit in 48 bits"); return uint48(value); } /** * @dev Returns the downcasted uint40 from uint256, reverting on * overflow (when the input is greater than largest uint40). * * Counterpart to Solidity's `uint40` operator. * * Requirements: * * - input must fit into 40 bits * * _Available since v4.7._ */ function toUint40(uint256 value) internal pure returns (uint40) { require(value <= type(uint40).max, "SafeCast: value doesn't fit in 40 bits"); return uint40(value); } /** * @dev Returns the downcasted uint32 from uint256, reverting on * overflow (when the input is greater than largest uint32). * * Counterpart to Solidity's `uint32` operator. * * Requirements: * * - input must fit into 32 bits * * _Available since v2.5._ */ function toUint32(uint256 value) internal pure returns (uint32) { require(value <= type(uint32).max, "SafeCast: value doesn't fit in 32 bits"); return uint32(value); } /** * @dev Returns the downcasted uint24 from uint256, reverting on * overflow (when the input is greater than largest uint24). * * Counterpart to Solidity's `uint24` operator. * * Requirements: * * - input must fit into 24 bits * * _Available since v4.7._ */ function toUint24(uint256 value) internal pure returns (uint24) { require(value <= type(uint24).max, "SafeCast: value doesn't fit in 24 bits"); return uint24(value); } /** * @dev Returns the downcasted uint16 from uint256, reverting on * overflow (when the input is greater than largest uint16). * * Counterpart to Solidity's `uint16` operator. * * Requirements: * * - input must fit into 16 bits * * _Available since v2.5._ */ function toUint16(uint256 value) internal pure returns (uint16) { require(value <= type(uint16).max, "SafeCast: value doesn't fit in 16 bits"); return uint16(value); } /** * @dev Returns the downcasted uint8 from uint256, reverting on * overflow (when the input is greater than largest uint8). * * Counterpart to Solidity's `uint8` operator. * * Requirements: * * - input must fit into 8 bits * * _Available since v2.5._ */ function toUint8(uint256 value) internal pure returns (uint8) { require(value <= type(uint8).max, "SafeCast: value doesn't fit in 8 bits"); return uint8(value); } /** * @dev Converts a signed int256 into an unsigned uint256. * * Requirements: * * - input must be greater than or equal to 0. * * _Available since v3.0._ */ function toUint256(int256 value) internal pure returns (uint256) { require(value >= 0, "SafeCast: value must be positive"); return uint256(value); } /** * @dev Returns the downcasted int248 from int256, reverting on * overflow (when the input is less than smallest int248 or * greater than largest int248). * * Counterpart to Solidity's `int248` operator. * * Requirements: * * - input must fit into 248 bits * * _Available since v4.7._ */ function toInt248(int256 value) internal pure returns (int248 downcasted) { downcasted = int248(value); require(downcasted == value, "SafeCast: value doesn't fit in 248 bits"); } /** * @dev Returns the downcasted int240 from int256, reverting on * overflow (when the input is less than smallest int240 or * greater than largest int240). * * Counterpart to Solidity's `int240` operator. * * Requirements: * * - input must fit into 240 bits * * _Available since v4.7._ */ function toInt240(int256 value) internal pure returns (int240 downcasted) { downcasted = int240(value); require(downcasted == value, "SafeCast: value doesn't fit in 240 bits"); } /** * @dev Returns the downcasted int232 from int256, reverting on * overflow (when the input is less than smallest int232 or * greater than largest int232). * * Counterpart to Solidity's `int232` operator. * * Requirements: * * - input must fit into 232 bits * * _Available since v4.7._ */ function toInt232(int256 value) internal pure returns (int232 downcasted) { downcasted = int232(value); require(downcasted == value, "SafeCast: value doesn't fit in 232 bits"); } /** * @dev Returns the downcasted int224 from int256, reverting on * overflow (when the input is less than smallest int224 or * greater than largest int224). * * Counterpart to Solidity's `int224` operator. * * Requirements: * * - input must fit into 224 bits * * _Available since v4.7._ */ function toInt224(int256 value) internal pure returns (int224 downcasted) { downcasted = int224(value); require(downcasted == value, "SafeCast: value doesn't fit in 224 bits"); } /** * @dev Returns the downcasted int216 from int256, reverting on * overflow (when the input is less than smallest int216 or * greater than largest int216). * * Counterpart to Solidity's `int216` operator. * * Requirements: * * - input must fit into 216 bits * * _Available since v4.7._ */ function toInt216(int256 value) internal pure returns (int216 downcasted) { downcasted = int216(value); require(downcasted == value, "SafeCast: value doesn't fit in 216 bits"); } /** * @dev Returns the downcasted int208 from int256, reverting on * overflow (when the input is less than smallest int208 or * greater than largest int208). * * Counterpart to Solidity's `int208` operator. * * Requirements: * * - input must fit into 208 bits * * _Available since v4.7._ */ function toInt208(int256 value) internal pure returns (int208 downcasted) { downcasted = int208(value); require(downcasted == value, "SafeCast: value doesn't fit in 208 bits"); } /** * @dev Returns the downcasted int200 from int256, reverting on * overflow (when the input is less than smallest int200 or * greater than largest int200). * * Counterpart to Solidity's `int200` operator. * * Requirements: * * - input must fit into 200 bits * * _Available since v4.7._ */ function toInt200(int256 value) internal pure returns (int200 downcasted) { downcasted = int200(value); require(downcasted == value, "SafeCast: value doesn't fit in 200 bits"); } /** * @dev Returns the downcasted int192 from int256, reverting on * overflow (when the input is less than smallest int192 or * greater than largest int192). * * Counterpart to Solidity's `int192` operator. * * Requirements: * * - input must fit into 192 bits * * _Available since v4.7._ */ function toInt192(int256 value) internal pure returns (int192 downcasted) { downcasted = int192(value); require(downcasted == value, "SafeCast: value doesn't fit in 192 bits"); } /** * @dev Returns the downcasted int184 from int256, reverting on * overflow (when the input is less than smallest int184 or * greater than largest int184). * * Counterpart to Solidity's `int184` operator. * * Requirements: * * - input must fit into 184 bits * * _Available since v4.7._ */ function toInt184(int256 value) internal pure returns (int184 downcasted) { downcasted = int184(value); require(downcasted == value, "SafeCast: value doesn't fit in 184 bits"); } /** * @dev Returns the downcasted int176 from int256, reverting on * overflow (when the input is less than smallest int176 or * greater than largest int176). * * Counterpart to Solidity's `int176` operator. * * Requirements: * * - input must fit into 176 bits * * _Available since v4.7._ */ function toInt176(int256 value) internal pure returns (int176 downcasted) { downcasted = int176(value); require(downcasted == value, "SafeCast: value doesn't fit in 176 bits"); } /** * @dev Returns the downcasted int168 from int256, reverting on * overflow (when the input is less than smallest int168 or * greater than largest int168). * * Counterpart to Solidity's `int168` operator. * * Requirements: * * - input must fit into 168 bits * * _Available since v4.7._ */ function toInt168(int256 value) internal pure returns (int168 downcasted) { downcasted = int168(value); require(downcasted == value, "SafeCast: value doesn't fit in 168 bits"); } /** * @dev Returns the downcasted int160 from int256, reverting on * overflow (when the input is less than smallest int160 or * greater than largest int160). * * Counterpart to Solidity's `int160` operator. * * Requirements: * * - input must fit into 160 bits * * _Available since v4.7._ */ function toInt160(int256 value) internal pure returns (int160 downcasted) { downcasted = int160(value); require(downcasted == value, "SafeCast: value doesn't fit in 160 bits"); } /** * @dev Returns the downcasted int152 from int256, reverting on * overflow (when the input is less than smallest int152 or * greater than largest int152). * * Counterpart to Solidity's `int152` operator. * * Requirements: * * - input must fit into 152 bits * * _Available since v4.7._ */ function toInt152(int256 value) internal pure returns (int152 downcasted) { downcasted = int152(value); require(downcasted == value, "SafeCast: value doesn't fit in 152 bits"); } /** * @dev Returns the downcasted int144 from int256, reverting on * overflow (when the input is less than smallest int144 or * greater than largest int144). * * Counterpart to Solidity's `int144` operator. * * Requirements: * * - input must fit into 144 bits * * _Available since v4.7._ */ function toInt144(int256 value) internal pure returns (int144 downcasted) { downcasted = int144(value); require(downcasted == value, "SafeCast: value doesn't fit in 144 bits"); } /** * @dev Returns the downcasted int136 from int256, reverting on * overflow (when the input is less than smallest int136 or * greater than largest int136). * * Counterpart to Solidity's `int136` operator. * * Requirements: * * - input must fit into 136 bits * * _Available since v4.7._ */ function toInt136(int256 value) internal pure returns (int136 downcasted) { downcasted = int136(value); require(downcasted == value, "SafeCast: value doesn't fit in 136 bits"); } /** * @dev Returns the downcasted int128 from int256, reverting on * overflow (when the input is less than smallest int128 or * greater than largest int128). * * Counterpart to Solidity's `int128` operator. * * Requirements: * * - input must fit into 128 bits * * _Available since v3.1._ */ function toInt128(int256 value) internal pure returns (int128 downcasted) { downcasted = int128(value); require(downcasted == value, "SafeCast: value doesn't fit in 128 bits"); } /** * @dev Returns the downcasted int120 from int256, reverting on * overflow (when the input is less than smallest int120 or * greater than largest int120). * * Counterpart to Solidity's `int120` operator. * * Requirements: * * - input must fit into 120 bits * * _Available since v4.7._ */ function toInt120(int256 value) internal pure returns (int120 downcasted) { downcasted = int120(value); require(downcasted == value, "SafeCast: value doesn't fit in 120 bits"); } /** * @dev Returns the downcasted int112 from int256, reverting on * overflow (when the input is less than smallest int112 or * greater than largest int112). * * Counterpart to Solidity's `int112` operator. * * Requirements: * * - input must fit into 112 bits * * _Available since v4.7._ */ function toInt112(int256 value) internal pure returns (int112 downcasted) { downcasted = int112(value); require(downcasted == value, "SafeCast: value doesn't fit in 112 bits"); } /** * @dev Returns the downcasted int104 from int256, reverting on * overflow (when the input is less than smallest int104 or * greater than largest int104). * * Counterpart to Solidity's `int104` operator. * * Requirements: * * - input must fit into 104 bits * * _Available since v4.7._ */ function toInt104(int256 value) internal pure returns (int104 downcasted) { downcasted = int104(value); require(downcasted == value, "SafeCast: value doesn't fit in 104 bits"); } /** * @dev Returns the downcasted int96 from int256, reverting on * overflow (when the input is less than smallest int96 or * greater than largest int96). * * Counterpart to Solidity's `int96` operator. * * Requirements: * * - input must fit into 96 bits * * _Available since v4.7._ */ function toInt96(int256 value) internal pure returns (int96 downcasted) { downcasted = int96(value); require(downcasted == value, "SafeCast: value doesn't fit in 96 bits"); } /** * @dev Returns the downcasted int88 from int256, reverting on * overflow (when the input is less than smallest int88 or * greater than largest int88). * * Counterpart to Solidity's `int88` operator. * * Requirements: * * - input must fit into 88 bits * * _Available since v4.7._ */ function toInt88(int256 value) internal pure returns (int88 downcasted) { downcasted = int88(value); require(downcasted == value, "SafeCast: value doesn't fit in 88 bits"); } /** * @dev Returns the downcasted int80 from int256, reverting on * overflow (when the input is less than smallest int80 or * greater than largest int80). * * Counterpart to Solidity's `int80` operator. * * Requirements: * * - input must fit into 80 bits * * _Available since v4.7._ */ function toInt80(int256 value) internal pure returns (int80 downcasted) { downcasted = int80(value); require(downcasted == value, "SafeCast: value doesn't fit in 80 bits"); } /** * @dev Returns the downcasted int72 from int256, reverting on * overflow (when the input is less than smallest int72 or * greater than largest int72). * * Counterpart to Solidity's `int72` operator. * * Requirements: * * - input must fit into 72 bits * * _Available since v4.7._ */ function toInt72(int256 value) internal pure returns (int72 downcasted) { downcasted = int72(value); require(downcasted == value, "SafeCast: value doesn't fit in 72 bits"); } /** * @dev Returns the downcasted int64 from int256, reverting on * overflow (when the input is less than smallest int64 or * greater than largest int64). * * Counterpart to Solidity's `int64` operator. * * Requirements: * * - input must fit into 64 bits * * _Available since v3.1._ */ function toInt64(int256 value) internal pure returns (int64 downcasted) { downcasted = int64(value); require(downcasted == value, "SafeCast: value doesn't fit in 64 bits"); } /** * @dev Returns the downcasted int56 from int256, reverting on * overflow (when the input is less than smallest int56 or * greater than largest int56). * * Counterpart to Solidity's `int56` operator. * * Requirements: * * - input must fit into 56 bits * * _Available since v4.7._ */ function toInt56(int256 value) internal pure returns (int56 downcasted) { downcasted = int56(value); require(downcasted == value, "SafeCast: value doesn't fit in 56 bits"); } /** * @dev Returns the downcasted int48 from int256, reverting on * overflow (when the input is less than smallest int48 or * greater than largest int48). * * Counterpart to Solidity's `int48` operator. * * Requirements: * * - input must fit into 48 bits * * _Available since v4.7._ */ function toInt48(int256 value) internal pure returns (int48 downcasted) { downcasted = int48(value); require(downcasted == value, "SafeCast: value doesn't fit in 48 bits"); } /** * @dev Returns the downcasted int40 from int256, reverting on * overflow (when the input is less than smallest int40 or * greater than largest int40). * * Counterpart to Solidity's `int40` operator. * * Requirements: * * - input must fit into 40 bits * * _Available since v4.7._ */ function toInt40(int256 value) internal pure returns (int40 downcasted) { downcasted = int40(value); require(downcasted == value, "SafeCast: value doesn't fit in 40 bits"); } /** * @dev Returns the downcasted int32 from int256, reverting on * overflow (when the input is less than smallest int32 or * greater than largest int32). * * Counterpart to Solidity's `int32` operator. * * Requirements: * * - input must fit into 32 bits * * _Available since v3.1._ */ function toInt32(int256 value) internal pure returns (int32 downcasted) { downcasted = int32(value); require(downcasted == value, "SafeCast: value doesn't fit in 32 bits"); } /** * @dev Returns the downcasted int24 from int256, reverting on * overflow (when the input is less than smallest int24 or * greater than largest int24). * * Counterpart to Solidity's `int24` operator. * * Requirements: * * - input must fit into 24 bits * * _Available since v4.7._ */ function toInt24(int256 value) internal pure returns (int24 downcasted) { downcasted = int24(value); require(downcasted == value, "SafeCast: value doesn't fit in 24 bits"); } /** * @dev Returns the downcasted int16 from int256, reverting on * overflow (when the input is less than smallest int16 or * greater than largest int16). * * Counterpart to Solidity's `int16` operator. * * Requirements: * * - input must fit into 16 bits * * _Available since v3.1._ */ function toInt16(int256 value) internal pure returns (int16 downcasted) { downcasted = int16(value); require(downcasted == value, "SafeCast: value doesn't fit in 16 bits"); } /** * @dev Returns the downcasted int8 from int256, reverting on * overflow (when the input is less than smallest int8 or * greater than largest int8). * * Counterpart to Solidity's `int8` operator. * * Requirements: * * - input must fit into 8 bits * * _Available since v3.1._ */ function toInt8(int256 value) internal pure returns (int8 downcasted) { downcasted = int8(value); require(downcasted == value, "SafeCast: value doesn't fit in 8 bits"); } /** * @dev Converts an unsigned uint256 into a signed int256. * * Requirements: * * - input must be less than or equal to maxInt256. * * _Available since v3.0._ */ function toInt256(uint256 value) internal pure returns (int256) { // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive require(value <= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256"); return int256(value); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol) pragma solidity ^0.8.0; /** * @dev Standard signed math utilities missing in the Solidity language. */ library SignedMath { /** * @dev Returns the largest of two signed numbers. */ function max(int256 a, int256 b) internal pure returns (int256) { return a > b ? a : b; } /** * @dev Returns the smallest of two signed numbers. */ function min(int256 a, int256 b) internal pure returns (int256) { return a < b ? a : b; } /** * @dev Returns the average of two signed numbers without overflow. * The result is rounded towards zero. */ function average(int256 a, int256 b) internal pure returns (int256) { // Formula from the book "Hacker's Delight" int256 x = (a & b) + ((a ^ b) >> 1); return x + (int256(uint256(x) >> 255) & (a ^ b)); } /** * @dev Returns the absolute unsigned value of a signed value. */ function abs(int256 n) internal pure returns (uint256) { unchecked { // must be unchecked in order to support `n = type(int256).min` return uint256(n >= 0 ? n : -n); } } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.22; import { SafeCast } from "@openzeppelin/contracts/utils/math/SafeCast.sol"; import { ILayerZeroEndpointV2 } from "@layerzerolabs/lz-evm-oapp-v2/contracts/oapp/interfaces/IOAppCore.sol"; import { Origin } from "@layerzerolabs/lz-evm-oapp-v2/contracts/oapp/OApp.sol"; // Solidity does not support splitting import across multiple lines // solhint-disable-next-line max-line-length import { OFTLimit, OFTFeeDetail, OFTReceipt, SendParam, MessagingReceipt, MessagingFee, IOFT } from "@layerzerolabs/lz-evm-oapp-v2/contracts/oft/interfaces/IOFT.sol"; import { OFTComposeMsgCodec } from "@layerzerolabs/lz-evm-oapp-v2/contracts/oft/libs/OFTComposeMsgCodec.sol"; import { IStargate, Ticket } from "./interfaces/IStargate.sol"; import { IStargateFeeLib, FeeParams } from "./interfaces/IStargateFeeLib.sol"; import { ITokenMessaging, RideBusParams, TaxiParams } from "./interfaces/ITokenMessaging.sol"; import { ITokenMessagingHandler } from "./interfaces/ITokenMessagingHandler.sol"; import { ICreditMessagingHandler, Credit, TargetCredit } from "./interfaces/ICreditMessagingHandler.sol"; import { Path } from "./libs/Path.sol"; import { Transfer } from "./libs/Transfer.sol"; /// @title The base contract for StargateOFT, StargatePool, StargatePoolMigratable, and StargatePoolNative. abstract contract StargateBase is Transfer, IStargate, ITokenMessagingHandler, ICreditMessagingHandler { using SafeCast for uint256; // Stargate status uint8 internal constant NOT_ENTERED = 1; uint8 internal constant ENTERED = 2; uint8 internal constant PAUSED = 3; /// @dev The token for the Pool or OFT. /// @dev address(0) indicates native coin, such as ETH. address public immutable override token; /// @dev The shared decimals (lowest common decimals between chains). uint8 public immutable override sharedDecimals; /// @dev The rate between local decimals and shared decimals. uint256 internal immutable convertRate; /// @dev The local LayerZero EndpointV2. ILayerZeroEndpointV2 public immutable endpoint; /// @dev The local LayerZero endpoint ID uint32 public immutable localEid; address internal feeLib; /// @dev The StargateBase status. Options include 1. NOT_ENTERED 2. ENTERED and 3. PAUSED. uint8 public status = NOT_ENTERED; /// @dev The treasury accrued fees, stored in SD. uint64 public treasuryFee; address internal creditMessaging; address internal lzToken; address internal planner; address internal tokenMessaging; address internal treasurer; /// @dev Mapping of paths from this chain to other chains identified by their endpoint ID. mapping(uint32 eid => Path path) public paths; /// @dev A store for tokens that could not be delivered because _outflow() failed. /// @dev retryReceiveToken() can be called to retry the receive. mapping(bytes32 guid => mapping(uint8 index => bytes32 hash)) public unreceivedTokens; modifier onlyCaller(address _caller) { if (msg.sender != _caller) revert Stargate_Unauthorized(); _; } modifier nonReentrantAndNotPaused() { // On the first call to nonReentrant, _status will be _NOT_ENTERED if (status != NOT_ENTERED) { if (status == ENTERED) revert Stargate_ReentrantCall(); revert Stargate_Paused(); } // Any calls to nonReentrant after this point will fail status = ENTERED; _; status = NOT_ENTERED; } error Stargate_ReentrantCall(); error Stargate_InvalidTokenDecimals(); error Stargate_Unauthorized(); error Stargate_SlippageTooHigh(); error Stargate_UnreceivedTokenNotFound(); error Stargate_OutflowFailed(); error Stargate_InvalidAmount(); error Stargate_InsufficientFare(); error Stargate_InvalidPath(); error Stargate_LzTokenUnavailable(); error Stargate_Paused(); error Stargate_RecoverTokenUnsupported(); event AddressConfigSet(AddressConfig config); event CreditsSent(uint32 dstEid, Credit[] credits); event CreditsReceived(uint32 srcEid, Credit[] credits); event UnreceivedTokenCached( bytes32 guid, uint8 index, uint32 srcEid, address receiver, uint256 amountLD, bytes composeMsg ); event OFTPathSet(uint32 dstEid, bool oft); event PauseSet(bool paused); event PlannerFeeWithdrawn(uint256 amount); event TreasuryFeeAdded(uint64 amountSD); event TreasuryFeeWithdrawn(address to, uint64 amountSD); struct AddressConfig { address feeLib; address planner; address treasurer; address tokenMessaging; address creditMessaging; address lzToken; } /// @notice Create a new Stargate contract /// @dev Reverts with InvalidTokenDecimals if the token decimals are smaller than the shared decimals. /// @param _token The token for the pool or oft. If the token is address(0), it is the native coin /// @param _tokenDecimals The number of decimals for this tokens implementation on this chain /// @param _sharedDecimals The number of decimals shared between all implementations of the OFT /// @param _endpoint The LZ endpoint contract /// @param _owner The owner of this contract constructor(address _token, uint8 _tokenDecimals, uint8 _sharedDecimals, address _endpoint, address _owner) { token = _token; if (_tokenDecimals < _sharedDecimals) revert Stargate_InvalidTokenDecimals(); convertRate = 10 ** (_tokenDecimals - _sharedDecimals); sharedDecimals = _sharedDecimals; endpoint = ILayerZeroEndpointV2(_endpoint); localEid = endpoint.eid(); _transferOwnership(_owner); } // ---------------------------------- Only Owner ------------------------------------------ /// @notice Configure the roles for this contract. /// @param _config An AddressConfig object containing the addresses for the different roles used by Stargate. function setAddressConfig(AddressConfig calldata _config) external onlyOwner { feeLib = _config.feeLib; planner = _config.planner; treasurer = _config.treasurer; tokenMessaging = _config.tokenMessaging; creditMessaging = _config.creditMessaging; lzToken = _config.lzToken; emit AddressConfigSet(_config); } /// @notice Sets a given Path as using OFT or resets it from OFT. /// @dev Set the path as OFT if the remote chain is using OFT. /// @dev When migrating from OFT to pool on remote chain (e.g. migrate USDC to circles), reset the path to non-OFT. /// @dev Reverts with InvalidPath if the destination chain is the same as local. /// @param _dstEid The destination chain endpoint ID /// @param _oft Whether to set or reset the path function setOFTPath(uint32 _dstEid, bool _oft) external onlyOwner { if (_dstEid == localEid) revert Stargate_InvalidPath(); paths[_dstEid].setOFTPath(_oft); emit OFTPathSet(_dstEid, _oft); } // ---------------------------------- Only Treasurer ------------------------------------------ /// @notice Withdraw from the accrued fees in the treasury. /// @param _to The destination account /// @param _amountSD The amount to withdraw in SD function withdrawTreasuryFee(address _to, uint64 _amountSD) external onlyCaller(treasurer) { treasuryFee -= _amountSD; _safeOutflow(_to, _sd2ld(_amountSD)); emit TreasuryFeeWithdrawn(_to, _amountSD); } /// @notice Add tokens to the treasury, from the senders account. /// @dev Only used for increasing the overall budget for transaction rewards /// @dev The treasuryFee is essentially the reward pool. /// @dev Rewards are capped to the treasury amount, which limits exposure so /// @dev Stargate does not pay beyond what it's charged. /// @param _amountLD The amount to add in LD function addTreasuryFee(uint256 _amountLD) external payable onlyCaller(treasurer) { _assertMsgValue(_amountLD); uint64 amountSD = _inflow(msg.sender, _amountLD); treasuryFee += amountSD; emit TreasuryFeeAdded(amountSD); } /// @dev Recover tokens sent to this contract by mistake. /// @dev Only the treasurer can recover the token. /// @dev Reverts with Stargate_RecoverTokenUnsupported if the treasurer attempts to withdraw StargateBase.token(). /// @param _token the token to recover. if 0x0 then it is native token /// @param _to the address to send the token to /// @param _amount the amount to send function recoverToken( address _token, address _to, uint256 _amount ) public virtual nonReentrantAndNotPaused onlyCaller(treasurer) returns (uint256) { /// @dev Excess native is considered planner accumulated fees. if (_token == address(0)) revert Stargate_RecoverTokenUnsupported(); Transfer.safeTransfer(_token, _to, _amount, false); return _amount; } // ---------------------------------- Only Planner ------------------------------------------ /// @notice Pause or unpause a Stargate /// @dev Be careful with this call, as it unsets the re-entry guard. /// @param _paused Whether to pause or unpause the stargate function setPause(bool _paused) external onlyCaller(planner) { if (status == ENTERED) revert Stargate_ReentrantCall(); status = _paused ? PAUSED : NOT_ENTERED; emit PauseSet(_paused); } function _plannerFee() internal view virtual returns (uint256) { return address(this).balance; } function plannerFee() external view returns (uint256 available) { available = _plannerFee(); } /// @notice Withdraw planner fees accumulated in StargateBase. /// @dev The planner fee is accumulated in StargateBase to avoid the cost of passing msg.value to TokenMessaging. function withdrawPlannerFee() external virtual onlyCaller(planner) { uint256 available = _plannerFee(); Transfer.safeTransferNative(msg.sender, available, false); emit PlannerFeeWithdrawn(available); } // ------------------------------- Public Functions --------------------------------------- /// @notice Send tokens through the Stargate /// @dev Emits OFTSent when the send is successful /// @param _sendParam The SendParam object detailing the transaction /// @param _fee The MessagingFee object describing the fee to pay /// @param _refundAddress The address to refund any LZ fees paid in excess /// @return msgReceipt The receipt proving the message was sent /// @return oftReceipt The receipt proving the OFT swap function send( SendParam calldata _sendParam, MessagingFee calldata _fee, address _refundAddress ) external payable override returns (MessagingReceipt memory msgReceipt, OFTReceipt memory oftReceipt) { (msgReceipt, oftReceipt, ) = sendToken(_sendParam, _fee, _refundAddress); } function sendToken( SendParam calldata _sendParam, MessagingFee calldata _fee, address _refundAddress ) public payable override nonReentrantAndNotPaused returns (MessagingReceipt memory msgReceipt, OFTReceipt memory oftReceipt, Ticket memory ticket) { // step 1: assets inflows and apply the fee to the input amount (bool isTaxi, uint64 amountInSD, uint64 amountOutSD) = _inflowAndCharge(_sendParam); // step 2: generate the oft receipt oftReceipt = OFTReceipt(_sd2ld(amountInSD), _sd2ld(amountOutSD)); // step 3: assert the messaging fee MessagingFee memory messagingFee = _assertMessagingFee(_fee, oftReceipt.amountSentLD); // step 4: send the token depending on the mode Taxi or Bus if (isTaxi) { msgReceipt = _taxi(_sendParam, messagingFee, amountOutSD, _refundAddress); } else { (msgReceipt, ticket) = _rideBus(_sendParam, messagingFee, amountOutSD, _refundAddress); } emit OFTSent( msgReceipt.guid, _sendParam.dstEid, msg.sender, oftReceipt.amountSentLD, oftReceipt.amountReceivedLD ); } /// @notice Retry receiving a token that initially failed. /// @dev The message has been delivered by the Messaging layer, so it is ok for anyone to retry. /// @dev try to receive the token if the previous attempt failed in lzReceive /// @dev Reverts with UnreceivedTokenNotFound if the message is not found in the cache /// @dev Emits OFTReceived if the receive succeeds /// @param _guid The global unique ID for the message that failed /// @param _index The index of the message that failed /// @param _srcEid The source endpoint ID for the message that failed /// @param _receiver The account receiver for the message that failed /// @param _amountLD The amount of tokens in LD to transfer to the account /// @param _composeMsg The bytes representing the compose message in the message that failed function retryReceiveToken( bytes32 _guid, uint8 _index, uint32 _srcEid, address _receiver, uint256 _amountLD, bytes calldata _composeMsg ) external nonReentrantAndNotPaused { if (unreceivedTokens[_guid][_index] != keccak256(abi.encodePacked(_srcEid, _receiver, _amountLD, _composeMsg))) revert Stargate_UnreceivedTokenNotFound(); delete unreceivedTokens[_guid][_index]; _safeOutflow(_receiver, _amountLD); _postOutflow(_ld2sd(_amountLD)); if (_composeMsg.length > 0) { endpoint.sendCompose(_receiver, _guid, 0, _composeMsg); } emit OFTReceived(_guid, _srcEid, _receiver, _amountLD); } // ------------------------------- Only Messaging --------------------------------------- /// @notice Entrypoint for receiving tokens /// @dev Emits OFTReceived when the OFT token is correctly received /// @dev Emits UnreceivedTokenCached when the OFT token is not received /// @param _origin The Origin struct describing the origin, useful for composing /// @param _guid The global unique ID for this message, useful for composing function receiveTokenBus( Origin calldata _origin, bytes32 _guid, uint8 _seatNumber, address _receiver, uint64 _amountSD ) external nonReentrantAndNotPaused onlyCaller(tokenMessaging) { uint256 amountLD = _sd2ld(_amountSD); bool success = _outflow(_receiver, amountLD); if (success) { _postOutflow(_amountSD); emit OFTReceived(_guid, _origin.srcEid, _receiver, amountLD); } else { /** * @dev The busRide mode does not support composeMsg in any form. Thus we hardcode it to "" */ unreceivedTokens[_guid][_seatNumber] = keccak256(abi.encodePacked(_origin.srcEid, _receiver, amountLD, "")); emit UnreceivedTokenCached(_guid, _seatNumber, _origin.srcEid, _receiver, amountLD, ""); } } // taxi mode function receiveTokenTaxi( Origin calldata _origin, bytes32 _guid, address _receiver, uint64 _amountSD, bytes calldata _composeMsg ) external nonReentrantAndNotPaused onlyCaller(tokenMessaging) { uint256 amountLD = _sd2ld(_amountSD); bool hasCompose = _composeMsg.length > 0; bytes memory composeMsg; if (hasCompose) { composeMsg = OFTComposeMsgCodec.encode(_origin.nonce, _origin.srcEid, amountLD, _composeMsg); } bool success = _outflow(_receiver, amountLD); if (success) { _postOutflow(_amountSD); // send the composeMsg to the endpoint if (hasCompose) { endpoint.sendCompose(_receiver, _guid, 0, composeMsg); } emit OFTReceived(_guid, _origin.srcEid, _receiver, amountLD); } else { /** * @dev We use the '0' index to represent the seat number. This is because for a type 'taxi' msg, * there is only ever one corresponding receiveTokenTaxi function per GUID. */ unreceivedTokens[_guid][0] = keccak256(abi.encodePacked(_origin.srcEid, _receiver, amountLD, composeMsg)); emit UnreceivedTokenCached(_guid, 0, _origin.srcEid, _receiver, amountLD, composeMsg); } } function sendCredits( uint32 _dstEid, TargetCredit[] calldata _credits ) external nonReentrantAndNotPaused onlyCaller(creditMessaging) returns (Credit[] memory) { Credit[] memory credits = new Credit[](_credits.length); uint256 index = 0; for (uint256 i = 0; i < _credits.length; i++) { TargetCredit calldata c = _credits[i]; uint64 decreased = paths[c.srcEid].tryDecreaseCredit(c.amount, c.minAmount); if (decreased > 0) credits[index++] = Credit(c.srcEid, decreased); } // resize the array to the actual number of credits assembly { mstore(credits, index) } emit CreditsSent(_dstEid, credits); return credits; } /// @notice Entrypoint for receiving credits into paths /// @dev Emits CreditsReceived when credits are received /// @param _srcEid The endpoint ID of the source of credits /// @param _credits An array indicating to which paths and how much credits to add function receiveCredits( uint32 _srcEid, Credit[] calldata _credits ) external nonReentrantAndNotPaused onlyCaller(creditMessaging) { for (uint256 i = 0; i < _credits.length; i++) { Credit calldata c = _credits[i]; paths[c.srcEid].increaseCredit(c.amount); } emit CreditsReceived(_srcEid, _credits); } // ---------------------------------- View Functions ------------------------------------------ /// @notice Provides a quote for sending OFT to another chain. /// @dev Implements the IOFT interface /// @param _sendParam The parameters for the send operation /// @return limit The information on OFT transfer limits /// @return oftFeeDetails The details of OFT transaction cost or reward /// @return receipt The OFT receipt information, indicating how many tokens would be sent and received function quoteOFT( SendParam calldata _sendParam ) external view returns (OFTLimit memory limit, OFTFeeDetail[] memory oftFeeDetails, OFTReceipt memory receipt) { // cap the transfer to the paths limit limit = OFTLimit(_sd2ld(1), _sd2ld(paths[_sendParam.dstEid].credit)); // get the expected amount in the destination chain from FeeLib uint64 amountInSD = _ld2sd(_sendParam.amountLD > limit.maxAmountLD ? limit.maxAmountLD : _sendParam.amountLD); FeeParams memory params = _buildFeeParams(_sendParam.dstEid, amountInSD, _isTaxiMode(_sendParam.oftCmd)); uint64 amountOutSD = IStargateFeeLib(feeLib).applyFeeView(params); // fill in the FeeDetails if there is a fee or reward if (amountOutSD != amountInSD) { oftFeeDetails = new OFTFeeDetail[](1); if (amountOutSD < amountInSD) { // fee oftFeeDetails[0] = OFTFeeDetail(-1 * _sd2ld(amountInSD - amountOutSD).toInt256(), "protocol fee"); } else if (amountOutSD > amountInSD) { // reward uint64 reward = amountOutSD - amountInSD; (amountOutSD, reward) = _capReward(amountOutSD, reward); if (amountOutSD == amountInSD) { // hide the Fee detail if the reward is capped to 0 oftFeeDetails = new OFTFeeDetail[](0); } else { oftFeeDetails[0] = OFTFeeDetail(_sd2ld(reward).toInt256(), "reward"); } } } receipt = OFTReceipt(_sd2ld(amountInSD), _sd2ld(amountOutSD)); } /// @notice Provides a quote for the send() operation. /// @dev Implements the IOFT interface. /// @dev Reverts with InvalidAmount if send mode is drive but value is specified. /// @param _sendParam The parameters for the send() operation /// @param _payInLzToken Flag indicating whether the caller is paying in the LZ token /// @return fee The calculated LayerZero messaging fee from the send() operation /// @dev MessagingFee: LayerZero message fee /// - nativeFee: The native fee. /// - lzTokenFee: The LZ token fee. function quoteSend( SendParam calldata _sendParam, bool _payInLzToken ) external view returns (MessagingFee memory fee) { uint64 amountSD = _ld2sd(_sendParam.amountLD); if (amountSD == 0) revert Stargate_InvalidAmount(); bool isTaxi = _isTaxiMode(_sendParam.oftCmd); if (isTaxi) { fee = ITokenMessaging(tokenMessaging).quoteTaxi( TaxiParams({ sender: msg.sender, dstEid: _sendParam.dstEid, receiver: _sendParam.to, amountSD: amountSD, composeMsg: _sendParam.composeMsg, extraOptions: _sendParam.extraOptions }), _payInLzToken ); } else { bool nativeDrop = _sendParam.extraOptions.length > 0; fee = ITokenMessaging(tokenMessaging).quoteRideBus(_sendParam.dstEid, nativeDrop); } } /// @notice Returns the current roles configured. /// @return An AddressConfig struct containing the current configuration function getAddressConfig() external view returns (AddressConfig memory) { return AddressConfig({ feeLib: feeLib, planner: planner, treasurer: treasurer, tokenMessaging: tokenMessaging, creditMessaging: creditMessaging, lzToken: lzToken }); } /// @notice Get the OFT version information /// @dev Implements the IOFT interface. /// @dev 0 version means the message encoding is not compatible with the default OFT. /// @return interfaceId The ERC165 interface ID for this contract /// @return version The cross-chain compatible message encoding version. function oftVersion() external pure override returns (bytes4 interfaceId, uint64 version) { return (type(IOFT).interfaceId, 0); } /// @notice Indicates whether the OFT contract requires approval of the 'token()' to send. /// @dev Implements the IOFT interface. /// @return Whether approval of the underlying token implementation is required function approvalRequired() external pure override returns (bool) { return true; } // ---------------------------------- Internal Functions ------------------------------------------ /// @notice Ingest value into the contract and charge the Stargate fee. /// @dev This is triggered when value is transferred from an account into Stargate to execute a swap. /// @param _sendParam A SendParam struct containing the swap information function _inflowAndCharge( SendParam calldata _sendParam ) internal returns (bool isTaxi, uint64 amountInSD, uint64 amountOutSD) { isTaxi = _isTaxiMode(_sendParam.oftCmd); amountInSD = _inflow(msg.sender, _sendParam.amountLD); FeeParams memory feeParams = _buildFeeParams(_sendParam.dstEid, amountInSD, isTaxi); amountOutSD = _chargeFee(feeParams, _ld2sd(_sendParam.minAmountLD)); paths[_sendParam.dstEid].decreaseCredit(amountOutSD); // remove the credit from the path _postInflow(amountOutSD); // post inflow actions with the amount deducted by the fee } /// @notice Consult the FeeLib the fee/reward for sending this token /// @dev Reverts with SlippageTooHigh when the slippage amount sent would be below the desired minimum or zero. /// @return amountOutSD The actual amount that would be sent after applying fees/rewards function _chargeFee(FeeParams memory _feeParams, uint64 _minAmountOutSD) internal returns (uint64 amountOutSD) { // get the output amount from the fee library amountOutSD = IStargateFeeLib(feeLib).applyFee(_feeParams); uint64 amountInSD = _feeParams.amountInSD; if (amountOutSD < amountInSD) { // fee treasuryFee += amountInSD - amountOutSD; } else if (amountOutSD > amountInSD) { // reward uint64 reward = amountOutSD - amountInSD; (amountOutSD, reward) = _capReward(amountOutSD, reward); if (reward > 0) treasuryFee -= reward; } if (amountOutSD < _minAmountOutSD || amountOutSD == 0) revert Stargate_SlippageTooHigh(); // 0 not allowed } function _taxi( SendParam calldata _sendParam, MessagingFee memory _messagingFee, uint64 _amountSD, address _refundAddress ) internal returns (MessagingReceipt memory receipt) { if (_messagingFee.lzTokenFee > 0) _payLzToken(_messagingFee.lzTokenFee); // handle lz token fee receipt = ITokenMessaging(tokenMessaging).taxi{ value: _messagingFee.nativeFee }( TaxiParams({ sender: msg.sender, dstEid: _sendParam.dstEid, receiver: _sendParam.to, amountSD: _amountSD, composeMsg: _sendParam.composeMsg, extraOptions: _sendParam.extraOptions }), _messagingFee, _refundAddress ); } function _rideBus( SendParam calldata _sendParam, MessagingFee memory _messagingFee, uint64 _amountSD, address _refundAddress ) internal virtual returns (MessagingReceipt memory receipt, Ticket memory ticket) { if (_messagingFee.lzTokenFee > 0) revert Stargate_LzTokenUnavailable(); (receipt, ticket) = ITokenMessaging(tokenMessaging).rideBus( RideBusParams({ sender: msg.sender, dstEid: _sendParam.dstEid, receiver: _sendParam.to, amountSD: _amountSD, nativeDrop: _sendParam.extraOptions.length > 0 }) ); uint256 busFare = receipt.fee.nativeFee; uint256 providedFare = _messagingFee.nativeFee; // assert sufficient nativeFee was provided to cover the fare if (busFare == providedFare) { // return; Do nothing in this case } else if (providedFare > busFare) { uint256 refund; unchecked { refund = providedFare - busFare; } Transfer.transferNative(_refundAddress, refund, false); // no gas limit to refund } else { revert Stargate_InsufficientFare(); } } /// @notice Pay the LZ fee in LZ tokens. /// @dev Reverts with LzTokenUnavailable if the LZ token OFT has not been set. /// @param _lzTokenFee The fee to pay in LZ tokens function _payLzToken(uint256 _lzTokenFee) internal { address lzTkn = lzToken; if (lzTkn == address(0)) revert Stargate_LzTokenUnavailable(); Transfer.safeTransferTokenFrom(lzTkn, msg.sender, address(endpoint), _lzTokenFee); } /// @notice Translate an amount in SD to LD /// @dev Since SD <= LD by definition, convertRate >= 1, so there is no rounding errors in this function. /// @param _amountSD The amount in SD /// @return amountLD The same value expressed in LD function _sd2ld(uint64 _amountSD) internal view returns (uint256 amountLD) { unchecked { amountLD = _amountSD * convertRate; } } /// @notice Translate an value in LD to SD /// @dev Since SD <= LD by definition, convertRate >= 1, so there might be rounding during the cast. /// @param _amountLD The value in LD /// @return amountSD The same value expressed in SD function _ld2sd(uint256 _amountLD) internal view returns (uint64 amountSD) { unchecked { amountSD = SafeCast.toUint64(_amountLD / convertRate); } } /// @dev if _cmd is empty, Taxi mode. Otherwise, Bus mode function _isTaxiMode(bytes calldata _oftCmd) internal pure returns (bool) { return _oftCmd.length == 0; } // ---------------------------------- Virtual Functions ------------------------------------------ /// @notice Limits the reward awarded when withdrawing value. /// @param _amountOutSD The amount of expected on the destination chain in SD /// @param _reward The initial calculated reward by FeeLib /// @return newAmountOutSD The actual amount to be delivered on the destination chain /// @return newReward The actual reward after applying any caps function _capReward( uint64 _amountOutSD, uint64 _reward ) internal view virtual returns (uint64 newAmountOutSD, uint64 newReward); /// @notice Hook called when there is ingress of value into the contract. /// @param _from The account from which to obtain the value /// @param _amountLD The amount of tokens to get from the account in LD /// @return amountSD The actual amount of tokens in SD that got into the Stargate function _inflow(address _from, uint256 _amountLD) internal virtual returns (uint64 amountSD); /// @notice Hook called when there is egress of value out of the contract. /// @return success Whether the outflow was successful function _outflow(address _to, uint256 _amountLD) internal virtual returns (bool success); /// @notice Hook called when there is egress of value out of the contract. /// @dev Reverts with OutflowFailed when the outflow hook fails function _safeOutflow(address _to, uint256 _amountLD) internal virtual { bool success = _outflow(_to, _amountLD); if (!success) revert Stargate_OutflowFailed(); } /// @notice Ensure that the value passed through the message equals the native fee /// @dev the native fee should be the same as msg value by default /// @dev Reverts with InvalidAmount if the native fee does not match the value passed. /// @param _fee The MessagingFee object containing the expected fee /// @return The messaging fee object function _assertMessagingFee( MessagingFee memory _fee, uint256 /*_amountInLD*/ ) internal view virtual returns (MessagingFee memory) { if (_fee.nativeFee != msg.value) revert Stargate_InvalidAmount(); return _fee; } /// @notice Ensure the msg.value is as expected. /// @dev Override this contract to provide a specific validation. /// @dev This implementation will revert if value is passed, because we do not expect value except for /// @dev the native token when adding to the treasury. /// @dev Reverts with InvalidAmount if msg.value > 0 function _assertMsgValue(uint256 /*_amountLD*/) internal view virtual { if (msg.value > 0) revert Stargate_InvalidAmount(); } /// @dev Build the FeeParams object for the FeeLib /// @param _dstEid The destination endpoint ID /// @param _amountInSD The amount to send in SD /// @param _isTaxi Whether this send is riding the bus or taxing function _buildFeeParams( uint32 _dstEid, uint64 _amountInSD, bool _isTaxi ) internal view virtual returns (FeeParams memory); /// @notice Hook called after the inflow of value into the contract by sendToken(). /// Function meant to be overridden // solhint-disable-next-line no-empty-blocks function _postInflow(uint64 _amountSD) internal virtual {} /// @notice Hook called after the outflow of value out of the contract by receiveToken(). /// Function meant to be overridden // solhint-disable-next-line no-empty-blocks function _postOutflow(uint64 _amountSD) internal virtual {} }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import { MessagingFee } from "@layerzerolabs/lz-evm-oapp-v2/contracts/oft/interfaces/IOFT.sol"; /// @notice Stores the information related to a batch of credit transfers. struct TargetCreditBatch { uint16 assetId; TargetCredit[] credits; } /// @notice Stores the information related to a single credit transfer. struct TargetCredit { uint32 srcEid; uint64 amount; // the amount of credits to intended to send uint64 minAmount; // the minimum amount of credits to keep on local chain after sending } /// @title Credit Messaging API /// @dev This interface defines the API for quoting and sending credits to other chains. interface ICreditMessaging { /// @notice Sends credits to the destination endpoint. /// @param _dstEid The destination LayerZero endpoint ID. /// @param _creditBatches The credit batch payloads to send to the destination LayerZero endpoint ID. function sendCredits(uint32 _dstEid, TargetCreditBatch[] calldata _creditBatches) external payable; /// @notice Quotes the fee for sending credits to the destination endpoint. /// @param _dstEid The destination LayerZero endpoint ID. /// @param _creditBatches The credit batch payloads to send to the destination LayerZero endpoint ID. /// @return fee The fee for sending the credits to the destination endpoint. function quoteSendCredits( uint32 _dstEid, TargetCreditBatch[] calldata _creditBatches ) external view returns (MessagingFee memory fee); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import { TargetCredit } from "./ICreditMessaging.sol"; struct Credit { uint32 srcEid; uint64 amount; } /// @dev This is an internal interface, defining functions to handle messages/calls from the credit messaging contract. interface ICreditMessagingHandler { function sendCredits(uint32 _dstEid, TargetCredit[] calldata _credits) external returns (Credit[] memory); function receiveCredits(uint32 _srcEid, Credit[] calldata _credits) external; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; // Solidity does not support splitting import across multiple lines // solhint-disable-next-line max-line-length import { IOFT, SendParam, MessagingFee, MessagingReceipt, OFTReceipt } from "@layerzerolabs/lz-evm-oapp-v2/contracts/oft/interfaces/IOFT.sol"; /// @notice Stargate implementation type. enum StargateType { Pool, OFT } /// @notice Ticket data for bus ride. struct Ticket { uint72 ticketId; bytes passengerBytes; } /// @title Interface for Stargate. /// @notice Defines an API for sending tokens to destination chains. interface IStargate is IOFT { /// @dev This function is same as `send` in OFT interface but returns the ticket data if in the bus ride mode, /// which allows the caller to ride and drive the bus in the same transaction. function sendToken( SendParam calldata _sendParam, MessagingFee calldata _fee, address _refundAddress ) external payable returns (MessagingReceipt memory msgReceipt, OFTReceipt memory oftReceipt, Ticket memory ticket); /// @notice Returns the Stargate implementation type. function stargateType() external pure returns (StargateType); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; /// @notice Parameters used to assess fees to send tokens to a destination endpoint. struct FeeParams { address sender; uint32 dstEid; uint64 amountInSD; uint64 deficitSD; bool toOFT; bool isTaxi; } /// @title Interface for assessing fees to send tokens to a destination endpoint. interface IStargateFeeLib { /// @notice Apply a fee for a given request, allowing for state modification. /// @dev This is included for future proofing potential implementations /// @dev where state is modified in the feeLib based on a FeeParams function applyFee(FeeParams calldata _params) external returns (uint64 amountOutSD); /// @notice Apply a fee for a given request, without modifying state. function applyFeeView(FeeParams calldata _params) external view returns (uint64 amountOutSD); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import { IStargate, SendParam, MessagingReceipt, MessagingFee, OFTReceipt } from "./IStargate.sol"; /// @title An interface for Stargate Pools /// @notice Stargate Pools are a type of IStargate that allows users to pool token liquidity. interface IStargatePool is IStargate { /// @notice Deposit token into the pool /// @param _receiver The account to mint the LP tokens to /// @param _amountLD The amount of tokens to deposit in LD /// @return amountLD The actual amount of tokens deposited in LD function deposit(address _receiver, uint256 _amountLD) external payable returns (uint256 amountLD); /// @notice Redeem an amount of LP tokens from the senders account, claiming rewards. /// @param _amountLD The amount of LP tokens to redeem /// @param _receiver The account to transfer the function redeem(uint256 _amountLD, address _receiver) external returns (uint256 amountLD); /// @notice Get how many LP tokens are redeemable for a given account /// @param _owner The address of the account to check /// @return amountLD The amount of LP tokens redeemable, in LD function redeemable(address _owner) external view returns (uint256 amountLD); /// @notice Redeem LP tokens and send the withdrawn tokens to a destination endpoint. /// @param _sendParam The SendParam payload describing the redeem and send /// @param _fee The MessagingFee to perform redeemSend /// @param _refundAddress The address to refund excess LayerZero messaging fees. /// @return receipt The MessagingReceipt describing the result of redeemSend /// @return oftReceipt The OFTReceipt describing the result of redeemSend function redeemSend( SendParam calldata _sendParam, MessagingFee calldata _fee, address _refundAddress ) external payable returns (MessagingReceipt memory receipt, OFTReceipt memory oftReceipt); /// @notice Quote the messaging fee for a redeemSend operation /// @param _sendParam The SendParam payload describing the redeem and send /// @param _payInLzToken Whether to pay the fee in LZ token /// @return messagingFee The MessagingFee for the redeemSend operation function quoteRedeemSend( SendParam calldata _sendParam, bool _payInLzToken ) external view returns (MessagingFee memory messagingFee); /// @notice Get the Total Value Locked in the pool. /// @return The total value locked function tvl() external view returns (uint256); /// @notice Get the available balance of the pool function poolBalance() external view returns (uint256); /// @notice Get the address of the LP token /// @return The address of the LP token contract. function lpToken() external view returns (address); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import { MessagingReceipt, MessagingFee, Ticket } from "./IStargate.sol"; /// @notice Payload for sending a taxi message. /// @dev A taxi message is sent immediately and is not stored on the bus. struct TaxiParams { address sender; uint32 dstEid; bytes32 receiver; uint64 amountSD; bytes composeMsg; bytes extraOptions; } /// @notice Payload for riding the bus. /// @dev Riding the bus is a two-step process: /// @dev - The message is sent to the bus, /// @dev - The bus is driven to the destination. struct RideBusParams { address sender; uint32 dstEid; bytes32 receiver; uint64 amountSD; bool nativeDrop; } /// @title Token Messaging API. /// @notice This interface defines the API for sending a taxi message, riding the bus, and driving the bus, along with /// corresponding quote functions. interface ITokenMessaging { /// @notice Sends a taxi message /// @param _params The taxi message payload /// @param _messagingFee The messaging fee for sending a taxi message /// @param _refundAddress The address to refund excess LayerZero MessagingFees /// @return receipt The MessagingReceipt resulting from sending the taxi function taxi( TaxiParams calldata _params, MessagingFee calldata _messagingFee, address _refundAddress ) external payable returns (MessagingReceipt memory receipt); /// @notice Quotes the messaging fee for sending a taxi message /// @param _params The taxi message payload /// @param _payInLzToken Whether to pay the fee in LZ token /// @return fee The MessagingFee for sending the taxi message function quoteTaxi(TaxiParams calldata _params, bool _payInLzToken) external view returns (MessagingFee memory fee); /// @notice Sends a message to ride the bus, queuing the passenger in preparation for the drive. /// @notice The planner will later driveBus to the destination endpoint. /// @param _params The rideBus message payload /// @return receipt The MessagingReceipt resulting from sending the rideBus message /// @return ticket The Ticket for riding the bus function rideBus( RideBusParams calldata _params ) external returns (MessagingReceipt memory receipt, Ticket memory ticket); /// @notice Quotes the messaging fee for riding the bus /// @param _dstEid The destination LayerZero endpoint ID. /// @param _nativeDrop Whether to pay for a native drop on the destination. /// @return fee The MessagingFee for riding the bus function quoteRideBus(uint32 _dstEid, bool _nativeDrop) external view returns (MessagingFee memory fee); /// @notice Drives the bus to the destination. /// @param _dstEid The destination LayerZero endpoint ID. /// @param _passengers The passengers to drive to the destination. /// @return receipt The MessagingReceipt resulting from driving the bus function driveBus( uint32 _dstEid, bytes calldata _passengers ) external payable returns (MessagingReceipt memory receipt); /// @notice Quotes the messaging fee for driving the bus to the destination. /// @param _dstEid The destination LayerZero endpoint ID. /// @param _passengers The passengers to drive to the destination. /// @return fee The MessagingFee for driving the bus function quoteDriveBus(uint32 _dstEid, bytes calldata _passengers) external view returns (MessagingFee memory fee); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import { Origin } from "@layerzerolabs/lz-evm-oapp-v2/contracts/oapp/OApp.sol"; /// @dev This is an internal interface, defining the function to handle token message from the token messaging contract. interface ITokenMessagingHandler { function receiveTokenBus( Origin calldata _origin, bytes32 _guid, uint8 _seatNumber, address _receiver, uint64 _amountSD ) external; function receiveTokenTaxi( Origin calldata _origin, bytes32 _guid, address _receiver, uint64 _amountSD, bytes calldata _composeMsg ) external; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.22; /// @dev The Path struct contains the bus base fare multiplier bps and the credit in the same slot for gas saving. struct Path { uint64 credit; // available credit for the path, in SD } using PathLib for Path global; /** * @title A library to operate on Paths. * @dev A Path is a route through which value can be sent. It entails the local chain and a destination chain, and has * a given amount of credit associated with it. Every time the value is sent from A to B, the credit on A is * decreased and credit on B is increased. If credit hits 0 then the path can no longer be used. */ library PathLib { uint64 internal constant UNLIMITED_CREDIT = type(uint64).max; // solhint-disable-next-line event-name-camelcase event Path_CreditBurned(uint64 amountSD); error Path_InsufficientCredit(); error Path_AlreadyHasCredit(); error Path_UnlimitedCredit(); /// @notice Increase credit for a given Path. /// @dev Reverts with Path_UnlimitedCredit if the increase would hit the maximum amount of credit (reserved value) /// @param _path The Path for which to increase credit /// @param _amountSD The amount by which to increase credit function increaseCredit(Path storage _path, uint64 _amountSD) internal { uint64 credit = _path.credit; if (credit == UNLIMITED_CREDIT) return; credit += _amountSD; if (credit == UNLIMITED_CREDIT) revert Path_UnlimitedCredit(); _path.credit = credit; } /// @notice Decrease credit for a given Path. /// @dev Reverts with InsufficientCredit if there is not enough credit /// @param _path The Path for which to decrease credit /// @param _amountSD The amount by which to decrease credit function decreaseCredit(Path storage _path, uint64 _amountSD) internal { uint64 currentCredit = _path.credit; if (currentCredit == UNLIMITED_CREDIT) return; if (currentCredit < _amountSD) revert Path_InsufficientCredit(); unchecked { _path.credit = currentCredit - _amountSD; } } /// @notice Decrease credit for a given path, even if only a partial amount is possible. /// @param _path The Path for which to decrease credit /// @param _amountSD The amount by which try to decrease credit /// @param _minKept The minimum amount of credit to keep after the decrease /// @return decreased The actual amount of credit decreased function tryDecreaseCredit( Path storage _path, uint64 _amountSD, uint64 _minKept ) internal returns (uint64 decreased) { uint64 currentCredit = _path.credit; // not allowed to try to decrease unlimited credit if (currentCredit == UNLIMITED_CREDIT) revert Path_UnlimitedCredit(); if (_minKept < currentCredit) { unchecked { uint64 maxDecreased = currentCredit - _minKept; decreased = _amountSD > maxDecreased ? maxDecreased : _amountSD; _path.credit = currentCredit - decreased; } } } /// @notice Set a given path as OFT or reset an OFT path to 0 credit. /// @dev A Path for which the asset is using an OFT on destination gets unlimited credit because value transfers /// @dev do not spend value. /// @dev Such a path is expected to not have credit before. /// @dev Reverts with AlreadyHasCredit if the Path already had credit assigned to it /// @param _path The Path to set /// @param _oft Whether to set it as OFT or reset it from OFT function setOFTPath(Path storage _path, bool _oft) internal { uint64 currentCredit = _path.credit; if (_oft) { // only allow un-limiting from 0 if (currentCredit != 0) revert Path_AlreadyHasCredit(); _path.credit = UNLIMITED_CREDIT; } else { // only allow resetting from unlimited if (currentCredit != UNLIMITED_CREDIT) revert Path_AlreadyHasCredit(); _path.credit = 0; } } /// @notice Check whether a given Path is set as OFT. /// @param _path The path to examine /// @return whether the Path is set as OFT function isOFTPath(Path storage _path) internal view returns (bool) { return _path.credit == UNLIMITED_CREDIT; } /// @notice Burn credit for a given Path during bridged token migration. function burnCredit(Path storage _path, uint64 _amountSD) internal { decreaseCredit(_path, _amountSD); emit Path_CreditBurned(_amountSD); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.22; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; /// @dev WARNING: Transferring tokens, when the token address is wrong, will fail silently. contract Transfer is Ownable { error Transfer_TransferFailed(); error Transfer_ApproveFailed(); // @dev default this to 2300, but it is modifiable // @dev this is intended to provide just enough gas to receive native tokens. // @dev ie. empty fallbacks or EOA addresses uint256 internal transferGasLimit = 2300; function getTransferGasLimit() external view returns (uint256) { return transferGasLimit; } function setTransferGasLimit(uint256 _gasLimit) external onlyOwner { transferGasLimit = _gasLimit; } /// @notice Transfer native coin to an account /// @dev If gas is unlimited, we pass 63/64 of the gasleft() /// @dev This call may revert due to out of gas instead of returning false. /// @param _to The account to transfer native coin to /// @param _value The amount of native coin to transfer /// @param _gasLimited Whether to limit gas available for the 'fall-back' /// @return success Whether the transfer was successful function transferNative(address _to, uint256 _value, bool _gasLimited) internal returns (bool success) { uint256 gasForCall = _gasLimited ? transferGasLimit : gasleft(); // @dev We dont care about the data returned here, only success or not. assembly { success := call(gasForCall, _to, _value, 0, 0, 0, 0) } } /// @notice Transfer an ERC20 token from the sender to an account /// @param _token The address of the ERC20 token to send /// @param _to The receiving account /// @param _value The amount of tokens to transfer /// @return success Whether the transfer was successful or not function transferToken(address _token, address _to, uint256 _value) internal returns (bool success) { success = _call(_token, abi.encodeWithSelector(IERC20(_token).transfer.selector, _to, _value)); } /// @notice Transfer an ERC20 token from one account to another /// @param _token The address of the ERC20 token to send /// @param _from The source account /// @param _to The destination account /// @param _value The amount of tokens to transfer /// @return success Whether the transfer was successful or not function transferTokenFrom( address _token, address _from, address _to, uint256 _value ) internal returns (bool success) { success = _call(_token, abi.encodeWithSelector(IERC20(_token).transferFrom.selector, _from, _to, _value)); } /// @notice Transfer either native coin or ERC20 token from the sender to an account /// @param _token The ERC20 address or 0x0 if native is desired /// @param _to The destination account /// @param _value the amount to transfer /// @param _gasLimited Whether to limit the amount of gas when doing a native transfer /// @return success Whether the transfer was successful or not function transfer(address _token, address _to, uint256 _value, bool _gasLimited) internal returns (bool success) { if (_token == address(0)) { success = transferNative(_to, _value, _gasLimited); } else { success = transferToken(_token, _to, _value); } } /// @notice Approve a given amount of token for an account /// @param _token The OFT contract to use for approval /// @param _spender The account to approve /// @param _value The amount of tokens to approve /// @return success Whether the approval succeeded function approveToken(address _token, address _spender, uint256 _value) internal returns (bool success) { success = _call(_token, abi.encodeWithSelector(IERC20(_token).approve.selector, _spender, _value)); } /// @notice Transfer native coin to an account or revert /// @dev Reverts with TransferFailed if the transfer failed /// @param _to The account to transfer native coin to /// @param _value The amount of native coin to transfer /// @param _gasLimited Whether to limit the amount of gas to 2300 function safeTransferNative(address _to, uint256 _value, bool _gasLimited) internal { if (!transferNative(_to, _value, _gasLimited)) revert Transfer_TransferFailed(); } /// @notice Transfer an ERC20 token from one account to another or revert /// @dev Reverts with TransferFailed when the transfer fails /// @param _token The address of the ERC20 token to send /// @param _to The destination account /// @param _value The amount of tokens to transfer function safeTransferToken(address _token, address _to, uint256 _value) internal { if (!transferToken(_token, _to, _value)) revert Transfer_TransferFailed(); } /// @notice Transfer an ERC20 token from one account to another /// @dev Reverts with TransferFailed when the transfer fails /// @param _token The address of the ERC20 token to send /// @param _from The source account /// @param _to The destination account /// @param _value The amount of tokens to transfer function safeTransferTokenFrom(address _token, address _from, address _to, uint256 _value) internal { if (!transferTokenFrom(_token, _from, _to, _value)) revert Transfer_TransferFailed(); } /// @notice Transfer either native coin or ERC20 token from the sender to an account /// @dev Reverts with TransferFailed when the transfer fails /// @param _token The ERC20 address or 0x0 if native is desired /// @param _to The destination account /// @param _value the amount to transfer /// @param _gasLimited Whether to limit the amount of gas when doing a native transfer function safeTransfer(address _token, address _to, uint256 _value, bool _gasLimited) internal { if (!transfer(_token, _to, _value, _gasLimited)) revert Transfer_TransferFailed(); } /// @notice Approve a given amount of token for an account or revert /// @dev Reverts with ApproveFailed if the approval failed /// @dev Consider using forceApproveToken(...) to ensure the approval is set correctly. /// @param _token The OFT contract to use for approval /// @param _spender The account to approve /// @param _value The amount of tokens to approve function safeApproveToken(address _token, address _spender, uint256 _value) internal { if (!approveToken(_token, _spender, _value)) revert Transfer_ApproveFailed(); } /// @notice Force approve a given amount of token for an account by first resetting the approval /// @dev Some tokens that require the approval to be set to zero before setting it to a non-zero value, e.g. USDT. /// @param _token The OFT contract to use for approval /// @param _spender The account to approve /// @param _value The amount of tokens to approve function forceApproveToken(address _token, address _spender, uint256 _value) internal { if (!approveToken(_token, _spender, _value)) { safeApproveToken(_token, _spender, 0); safeApproveToken(_token, _spender, _value); } } function _call(address _token, bytes memory _data) private returns (bool success) { // solhint-disable-next-line avoid-low-level-calls (bool s, bytes memory returndata) = _token.call(_data); success = s ? returndata.length == 0 || abi.decode(returndata, (bool)) : false; } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.22; import { ERC20Permit, ERC20 } from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol"; /// @title A contract representing an ERC20Permit used for representing liquidity pool ownership. contract LPToken is ERC20Permit { address public immutable stargate; uint8 internal immutable tokenDecimals; error LPToken_Unauthorized(); modifier onlyStargate() { if (msg.sender != stargate) revert LPToken_Unauthorized(); _; } /** * @notice Create a LP token to represent partial pool ownership. * @dev The sender of the message is set to the Stargate role. This is because it is expected that each * StargatePool will create its own LPToken. * @param _name The name of the ERC20 * @param _symbol The symbol for the ERC20 * @param _decimals How many decimals does the ERC20 has */ constructor(string memory _name, string memory _symbol, uint8 _decimals) ERC20(_name, _symbol) ERC20Permit(_name) { stargate = msg.sender; tokenDecimals = _decimals; } /// @notice Mint new LP tokens and transfer them to an account. /// @param _to The account to send the newly minted tokens to /// @param _amount How many tokens to mint function mint(address _to, uint256 _amount) external onlyStargate { _mint(_to, _amount); } /// @notice Burn tokens currently owned by an account. /// @param _from The account to burn the tokens from /// @param _amount How many tokens to burn function burnFrom(address _from, uint256 _amount) external onlyStargate { _burn(_from, _amount); } /// @notice How many decimals are used by this token. /// @return The amount of decimals function decimals() public view override returns (uint8) { return tokenDecimals; } }
{ "evmVersion": "paris", "optimizer": { "enabled": true, "runs": 5000 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"string","name":"_lpTokenName","type":"string"},{"internalType":"string","name":"_lpTokenSymbol","type":"string"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint8","name":"_tokenDecimals","type":"uint8"},{"internalType":"uint8","name":"_sharedDecimals","type":"uint8"},{"internalType":"address","name":"_endpoint","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"InvalidLocalDecimals","type":"error"},{"inputs":[],"name":"Path_AlreadyHasCredit","type":"error"},{"inputs":[],"name":"Path_InsufficientCredit","type":"error"},{"inputs":[],"name":"Path_UnlimitedCredit","type":"error"},{"inputs":[{"internalType":"uint256","name":"amountLD","type":"uint256"},{"internalType":"uint256","name":"minAmountLD","type":"uint256"}],"name":"SlippageExceeded","type":"error"},{"inputs":[],"name":"Stargate_InsufficientFare","type":"error"},{"inputs":[],"name":"Stargate_InvalidAmount","type":"error"},{"inputs":[],"name":"Stargate_InvalidPath","type":"error"},{"inputs":[],"name":"Stargate_InvalidTokenDecimals","type":"error"},{"inputs":[],"name":"Stargate_LzTokenUnavailable","type":"error"},{"inputs":[],"name":"Stargate_OnlyTaxi","type":"error"},{"inputs":[],"name":"Stargate_OutflowFailed","type":"error"},{"inputs":[],"name":"Stargate_Paused","type":"error"},{"inputs":[],"name":"Stargate_RecoverTokenUnsupported","type":"error"},{"inputs":[],"name":"Stargate_ReentrantCall","type":"error"},{"inputs":[],"name":"Stargate_SlippageTooHigh","type":"error"},{"inputs":[],"name":"Stargate_Unauthorized","type":"error"},{"inputs":[],"name":"Stargate_UnreceivedTokenNotFound","type":"error"},{"inputs":[],"name":"Transfer_ApproveFailed","type":"error"},{"inputs":[],"name":"Transfer_TransferFailed","type":"error"},{"anonymous":false,"inputs":[{"components":[{"internalType":"address","name":"feeLib","type":"address"},{"internalType":"address","name":"planner","type":"address"},{"internalType":"address","name":"treasurer","type":"address"},{"internalType":"address","name":"tokenMessaging","type":"address"},{"internalType":"address","name":"creditMessaging","type":"address"},{"internalType":"address","name":"lzToken","type":"address"}],"indexed":false,"internalType":"struct StargateBase.AddressConfig","name":"config","type":"tuple"}],"name":"AddressConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"srcEid","type":"uint32"},{"components":[{"internalType":"uint32","name":"srcEid","type":"uint32"},{"internalType":"uint64","name":"amount","type":"uint64"}],"indexed":false,"internalType":"struct Credit[]","name":"credits","type":"tuple[]"}],"name":"CreditsReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"dstEid","type":"uint32"},{"components":[{"internalType":"uint32","name":"srcEid","type":"uint32"},{"internalType":"uint64","name":"amount","type":"uint64"}],"indexed":false,"internalType":"struct Credit[]","name":"credits","type":"tuple[]"}],"name":"CreditsSent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"payer","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountLD","type":"uint256"}],"name":"Deposited","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"dstEid","type":"uint32"},{"indexed":false,"internalType":"bool","name":"oft","type":"bool"}],"name":"OFTPathSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"guid","type":"bytes32"},{"indexed":false,"internalType":"uint32","name":"srcEid","type":"uint32"},{"indexed":true,"internalType":"address","name":"toAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountReceivedLD","type":"uint256"}],"name":"OFTReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"guid","type":"bytes32"},{"indexed":false,"internalType":"uint32","name":"dstEid","type":"uint32"},{"indexed":true,"internalType":"address","name":"fromAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountSentLD","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountReceivedLD","type":"uint256"}],"name":"OFTSent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"paused","type":"bool"}],"name":"PauseSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"PlannerFeeWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"payer","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountLD","type":"uint256"}],"name":"Redeemed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"amountSD","type":"uint64"}],"name":"TreasuryFeeAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint64","name":"amountSD","type":"uint64"}],"name":"TreasuryFeeWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"guid","type":"bytes32"},{"indexed":false,"internalType":"uint8","name":"index","type":"uint8"},{"indexed":false,"internalType":"uint32","name":"srcEid","type":"uint32"},{"indexed":false,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountLD","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"composeMsg","type":"bytes"}],"name":"UnreceivedTokenCached","type":"event"},{"inputs":[{"internalType":"uint256","name":"_amountLD","type":"uint256"}],"name":"addTreasuryFee","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"approvalRequired","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"deficitOffset","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_receiver","type":"address"},{"internalType":"uint256","name":"_amountLD","type":"uint256"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"amountLD","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"endpoint","outputs":[{"internalType":"contract ILayerZeroEndpointV2","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAddressConfig","outputs":[{"components":[{"internalType":"address","name":"feeLib","type":"address"},{"internalType":"address","name":"planner","type":"address"},{"internalType":"address","name":"treasurer","type":"address"},{"internalType":"address","name":"tokenMessaging","type":"address"},{"internalType":"address","name":"creditMessaging","type":"address"},{"internalType":"address","name":"lzToken","type":"address"}],"internalType":"struct StargateBase.AddressConfig","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTransferGasLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"localEid","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lpToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"oftVersion","outputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"},{"internalType":"uint64","name":"version","type":"uint64"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"eid","type":"uint32"}],"name":"paths","outputs":[{"internalType":"uint64","name":"credit","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"plannerFee","outputs":[{"internalType":"uint256","name":"available","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poolBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstEid","type":"uint32"},{"internalType":"bytes32","name":"to","type":"bytes32"},{"internalType":"uint256","name":"amountLD","type":"uint256"},{"internalType":"uint256","name":"minAmountLD","type":"uint256"},{"internalType":"bytes","name":"extraOptions","type":"bytes"},{"internalType":"bytes","name":"composeMsg","type":"bytes"},{"internalType":"bytes","name":"oftCmd","type":"bytes"}],"internalType":"struct SendParam","name":"_sendParam","type":"tuple"}],"name":"quoteOFT","outputs":[{"components":[{"internalType":"uint256","name":"minAmountLD","type":"uint256"},{"internalType":"uint256","name":"maxAmountLD","type":"uint256"}],"internalType":"struct OFTLimit","name":"limit","type":"tuple"},{"components":[{"internalType":"int256","name":"feeAmountLD","type":"int256"},{"internalType":"string","name":"description","type":"string"}],"internalType":"struct OFTFeeDetail[]","name":"oftFeeDetails","type":"tuple[]"},{"components":[{"internalType":"uint256","name":"amountSentLD","type":"uint256"},{"internalType":"uint256","name":"amountReceivedLD","type":"uint256"}],"internalType":"struct OFTReceipt","name":"receipt","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstEid","type":"uint32"},{"internalType":"bytes32","name":"to","type":"bytes32"},{"internalType":"uint256","name":"amountLD","type":"uint256"},{"internalType":"uint256","name":"minAmountLD","type":"uint256"},{"internalType":"bytes","name":"extraOptions","type":"bytes"},{"internalType":"bytes","name":"composeMsg","type":"bytes"},{"internalType":"bytes","name":"oftCmd","type":"bytes"}],"internalType":"struct SendParam","name":"_sendParam","type":"tuple"},{"internalType":"bool","name":"_payInLzToken","type":"bool"}],"name":"quoteRedeemSend","outputs":[{"components":[{"internalType":"uint256","name":"nativeFee","type":"uint256"},{"internalType":"uint256","name":"lzTokenFee","type":"uint256"}],"internalType":"struct MessagingFee","name":"fee","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstEid","type":"uint32"},{"internalType":"bytes32","name":"to","type":"bytes32"},{"internalType":"uint256","name":"amountLD","type":"uint256"},{"internalType":"uint256","name":"minAmountLD","type":"uint256"},{"internalType":"bytes","name":"extraOptions","type":"bytes"},{"internalType":"bytes","name":"composeMsg","type":"bytes"},{"internalType":"bytes","name":"oftCmd","type":"bytes"}],"internalType":"struct SendParam","name":"_sendParam","type":"tuple"},{"internalType":"bool","name":"_payInLzToken","type":"bool"}],"name":"quoteSend","outputs":[{"components":[{"internalType":"uint256","name":"nativeFee","type":"uint256"},{"internalType":"uint256","name":"lzTokenFee","type":"uint256"}],"internalType":"struct MessagingFee","name":"fee","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"_srcEid","type":"uint32"},{"components":[{"internalType":"uint32","name":"srcEid","type":"uint32"},{"internalType":"uint64","name":"amount","type":"uint64"}],"internalType":"struct Credit[]","name":"_credits","type":"tuple[]"}],"name":"receiveCredits","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"srcEid","type":"uint32"},{"internalType":"bytes32","name":"sender","type":"bytes32"},{"internalType":"uint64","name":"nonce","type":"uint64"}],"internalType":"struct Origin","name":"_origin","type":"tuple"},{"internalType":"bytes32","name":"_guid","type":"bytes32"},{"internalType":"uint8","name":"_seatNumber","type":"uint8"},{"internalType":"address","name":"_receiver","type":"address"},{"internalType":"uint64","name":"_amountSD","type":"uint64"}],"name":"receiveTokenBus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"srcEid","type":"uint32"},{"internalType":"bytes32","name":"sender","type":"bytes32"},{"internalType":"uint64","name":"nonce","type":"uint64"}],"internalType":"struct Origin","name":"_origin","type":"tuple"},{"internalType":"bytes32","name":"_guid","type":"bytes32"},{"internalType":"address","name":"_receiver","type":"address"},{"internalType":"uint64","name":"_amountSD","type":"uint64"},{"internalType":"bytes","name":"_composeMsg","type":"bytes"}],"name":"receiveTokenTaxi","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"recoverToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amountLD","type":"uint256"},{"internalType":"address","name":"_receiver","type":"address"}],"name":"redeem","outputs":[{"internalType":"uint256","name":"amountLD","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstEid","type":"uint32"},{"internalType":"bytes32","name":"to","type":"bytes32"},{"internalType":"uint256","name":"amountLD","type":"uint256"},{"internalType":"uint256","name":"minAmountLD","type":"uint256"},{"internalType":"bytes","name":"extraOptions","type":"bytes"},{"internalType":"bytes","name":"composeMsg","type":"bytes"},{"internalType":"bytes","name":"oftCmd","type":"bytes"}],"internalType":"struct SendParam","name":"_sendParam","type":"tuple"},{"components":[{"internalType":"uint256","name":"nativeFee","type":"uint256"},{"internalType":"uint256","name":"lzTokenFee","type":"uint256"}],"internalType":"struct MessagingFee","name":"_fee","type":"tuple"},{"internalType":"address","name":"_refundAddress","type":"address"}],"name":"redeemSend","outputs":[{"components":[{"internalType":"bytes32","name":"guid","type":"bytes32"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"components":[{"internalType":"uint256","name":"nativeFee","type":"uint256"},{"internalType":"uint256","name":"lzTokenFee","type":"uint256"}],"internalType":"struct MessagingFee","name":"fee","type":"tuple"}],"internalType":"struct MessagingReceipt","name":"msgReceipt","type":"tuple"},{"components":[{"internalType":"uint256","name":"amountSentLD","type":"uint256"},{"internalType":"uint256","name":"amountReceivedLD","type":"uint256"}],"internalType":"struct OFTReceipt","name":"oftReceipt","type":"tuple"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"redeemable","outputs":[{"internalType":"uint256","name":"amountLD","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_guid","type":"bytes32"},{"internalType":"uint8","name":"_index","type":"uint8"},{"internalType":"uint32","name":"_srcEid","type":"uint32"},{"internalType":"address","name":"_receiver","type":"address"},{"internalType":"uint256","name":"_amountLD","type":"uint256"},{"internalType":"bytes","name":"_composeMsg","type":"bytes"}],"name":"retryReceiveToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstEid","type":"uint32"},{"internalType":"bytes32","name":"to","type":"bytes32"},{"internalType":"uint256","name":"amountLD","type":"uint256"},{"internalType":"uint256","name":"minAmountLD","type":"uint256"},{"internalType":"bytes","name":"extraOptions","type":"bytes"},{"internalType":"bytes","name":"composeMsg","type":"bytes"},{"internalType":"bytes","name":"oftCmd","type":"bytes"}],"internalType":"struct SendParam","name":"_sendParam","type":"tuple"},{"components":[{"internalType":"uint256","name":"nativeFee","type":"uint256"},{"internalType":"uint256","name":"lzTokenFee","type":"uint256"}],"internalType":"struct MessagingFee","name":"_fee","type":"tuple"},{"internalType":"address","name":"_refundAddress","type":"address"}],"name":"send","outputs":[{"components":[{"internalType":"bytes32","name":"guid","type":"bytes32"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"components":[{"internalType":"uint256","name":"nativeFee","type":"uint256"},{"internalType":"uint256","name":"lzTokenFee","type":"uint256"}],"internalType":"struct MessagingFee","name":"fee","type":"tuple"}],"internalType":"struct MessagingReceipt","name":"msgReceipt","type":"tuple"},{"components":[{"internalType":"uint256","name":"amountSentLD","type":"uint256"},{"internalType":"uint256","name":"amountReceivedLD","type":"uint256"}],"internalType":"struct OFTReceipt","name":"oftReceipt","type":"tuple"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_dstEid","type":"uint32"},{"components":[{"internalType":"uint32","name":"srcEid","type":"uint32"},{"internalType":"uint64","name":"amount","type":"uint64"},{"internalType":"uint64","name":"minAmount","type":"uint64"}],"internalType":"struct TargetCredit[]","name":"_credits","type":"tuple[]"}],"name":"sendCredits","outputs":[{"components":[{"internalType":"uint32","name":"srcEid","type":"uint32"},{"internalType":"uint64","name":"amount","type":"uint64"}],"internalType":"struct Credit[]","name":"","type":"tuple[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstEid","type":"uint32"},{"internalType":"bytes32","name":"to","type":"bytes32"},{"internalType":"uint256","name":"amountLD","type":"uint256"},{"internalType":"uint256","name":"minAmountLD","type":"uint256"},{"internalType":"bytes","name":"extraOptions","type":"bytes"},{"internalType":"bytes","name":"composeMsg","type":"bytes"},{"internalType":"bytes","name":"oftCmd","type":"bytes"}],"internalType":"struct SendParam","name":"_sendParam","type":"tuple"},{"components":[{"internalType":"uint256","name":"nativeFee","type":"uint256"},{"internalType":"uint256","name":"lzTokenFee","type":"uint256"}],"internalType":"struct MessagingFee","name":"_fee","type":"tuple"},{"internalType":"address","name":"_refundAddress","type":"address"}],"name":"sendToken","outputs":[{"components":[{"internalType":"bytes32","name":"guid","type":"bytes32"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"components":[{"internalType":"uint256","name":"nativeFee","type":"uint256"},{"internalType":"uint256","name":"lzTokenFee","type":"uint256"}],"internalType":"struct MessagingFee","name":"fee","type":"tuple"}],"internalType":"struct MessagingReceipt","name":"msgReceipt","type":"tuple"},{"components":[{"internalType":"uint256","name":"amountSentLD","type":"uint256"},{"internalType":"uint256","name":"amountReceivedLD","type":"uint256"}],"internalType":"struct OFTReceipt","name":"oftReceipt","type":"tuple"},{"components":[{"internalType":"uint72","name":"ticketId","type":"uint72"},{"internalType":"bytes","name":"passengerBytes","type":"bytes"}],"internalType":"struct Ticket","name":"ticket","type":"tuple"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"feeLib","type":"address"},{"internalType":"address","name":"planner","type":"address"},{"internalType":"address","name":"treasurer","type":"address"},{"internalType":"address","name":"tokenMessaging","type":"address"},{"internalType":"address","name":"creditMessaging","type":"address"},{"internalType":"address","name":"lzToken","type":"address"}],"internalType":"struct StargateBase.AddressConfig","name":"_config","type":"tuple"}],"name":"setAddressConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_deficitOffsetLD","type":"uint256"}],"name":"setDeficitOffset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_dstEid","type":"uint32"},{"internalType":"bool","name":"_oft","type":"bool"}],"name":"setOFTPath","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_paused","type":"bool"}],"name":"setPause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_gasLimit","type":"uint256"}],"name":"setTransferGasLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"sharedDecimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stargateType","outputs":[{"internalType":"enum StargateType","name":"","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"status","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"token","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":"treasuryFee","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tvl","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"guid","type":"bytes32"},{"internalType":"uint8","name":"index","type":"uint8"}],"name":"unreceivedTokens","outputs":[{"internalType":"bytes32","name":"hash","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdrawPlannerFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint64","name":"_amountSD","type":"uint64"}],"name":"withdrawTreasuryFee","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
6101406040526108fc6001556002805460ff60a01b1916600160a01b1790553480156200002b57600080fd5b5060405162007bb138038062007bb18339810160408190526200004e91620002f3565b84848484846200005e3362000199565b6001600160a01b03851660805260ff80841690851610156200009357604051632e4b554360e01b815260040160405180910390fd5b6200009f8385620003d0565b620000ac90600a620004ef565b60c05260ff831660a0526001600160a01b03821660e08190526040805163416ecebf60e01b8152905163416ecebf916004808201926020929091908290030181865afa15801562000101573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000127919062000507565b63ffffffff16610100526200013c8162000199565b50505050508686856040516200015290620001e9565b62000160939291906200055d565b604051809103906000f0801580156200017d573d6000803e3d6000fd5b506001600160a01b031661012052506200059a95505050505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b611c0f8062005fa283390190565b634e487b7160e01b600052604160045260246000fd5b60005b838110156200022a57818101518382015260200162000210565b50506000910152565b600082601f8301126200024557600080fd5b81516001600160401b0380821115620002625762000262620001f7565b604051601f8301601f19908116603f011681019082821181831017156200028d576200028d620001f7565b81604052838152866020858801011115620002a757600080fd5b620002ba8460208301602089016200020d565b9695505050505050565b80516001600160a01b0381168114620002dc57600080fd5b919050565b805160ff81168114620002dc57600080fd5b600080600080600080600060e0888a0312156200030f57600080fd5b87516001600160401b03808211156200032757600080fd5b620003358b838c0162000233565b985060208a01519150808211156200034c57600080fd5b506200035b8a828b0162000233565b9650506200036c60408901620002c4565b94506200037c60608901620002e1565b93506200038c60808901620002e1565b92506200039c60a08901620002c4565b9150620003ac60c08901620002c4565b905092959891949750929550565b634e487b7160e01b600052601160045260246000fd5b60ff8281168282160390811115620003ec57620003ec620003ba565b92915050565b600181815b8085111562000433578160001904821115620004175762000417620003ba565b808516156200042557918102915b93841c9390800290620003f7565b509250929050565b6000826200044c57506001620003ec565b816200045b57506000620003ec565b81600181146200047457600281146200047f576200049f565b6001915050620003ec565b60ff841115620004935762000493620003ba565b50506001821b620003ec565b5060208310610133831016604e8410600b8410161715620004c4575081810a620003ec565b620004d08383620003f2565b8060001904821115620004e757620004e7620003ba565b029392505050565b60006200050060ff8416836200043b565b9392505050565b6000602082840312156200051a57600080fd5b815163ffffffff811681146200050057600080fd5b60008151808452620005498160208601602086016200020d565b601f01601f19169290920160200192915050565b6060815260006200057260608301866200052f565b82810360208401526200058681866200052f565b91505060ff83166040830152949350505050565b60805160a05160c05160e05161010051610120516158b5620006ed600039600081816106d8015281816120ce0152818161228c0152818161245d015261293201526000818161072301528181611b08015281816121e0015281816125e6015281816126a50152818161288e015261391401526000818161068f015281816115ee01528181612dc001526145a0015260008181610854015281816108de01528181610a5d01528181610d8801528181610df301528181610feb0152818161114f015281816111ec015281816112160152818161150f01528181611c61015281816120610152818161221b015281816123fa0152818161277d015281816128cf0152818161307c015281816131a1015281816131cb0152818161342d015261379f015260006107ad015260008181610ab201528181612bbf015281816136be0152818161377c0152613fb101526158b56000f3fe6080604052600436106102e75760003560e01c8063764f6a7811610184578063a88835d7116100d6578063cbef2aa91161008a578063e5328e0611610064578063e5328e0614610a3e578063f2fde38b14610a80578063fc0c546a14610aa057600080fd5b8063cbef2aa9146109aa578063cc32d176146109cc578063d621ad3f14610a0657600080fd5b8063bedb86fb116100bb578063bedb86fb14610957578063c7c7f5b314610977578063c859c4831461098a57600080fd5b8063a88835d714610922578063b0d7ca5d1461094257600080fd5b80638da5cb5b116101385780639f68b964116101125780639f68b96414610890578063a7229fd9146108ac578063a85dc7f2146108cc57600080fd5b80638da5cb5b146108045780639561b12f1461082257806396365d441461084257600080fd5b8063857749b011610169578063857749b01461079b57806388543f0e146107cf5780638c70830b146107e457600080fd5b8063764f6a781461075a5780637bde82f21461077b57600080fd5b80633b6f743b1161023d578063484267a4116101f15780635fcbd285116101cb5780635fcbd285146106c9578063715018a6146106fc578063726075371461071157600080fd5b8063484267a41461064a5780635114bf091461066a5780635e280f111461067d57600080fd5b8063434def5511610222578063434def55146105e9578063461bb0b91461060957806347e7ef241461062957600080fd5b80633b6f743b146105a95780633faa12c5146105c957600080fd5b8063192adc5d1161029f5780632bc5114c116102795780632bc5114c14610450578063341a46481461054657806338da6b8e1461055957600080fd5b8063192adc5d146103d0578063200d2ed2146103fd578063203bd15f1461043057600080fd5b806313bc4bc7116102d057806313bc4bc714610351578063156a0d0f1461037357806316909bca146103b457600080fd5b80630141e41b146102ec5780630d35b41514610322575b600080fd5b3480156102f857600080fd5b5061030c61030736600461476b565b610ad4565b6040516103199190614848565b60405180910390f35b34801561032e57600080fd5b5061034261033d36600461486d565b610d48565b604051610319939291906148f2565b34801561035d57600080fd5b5061037161036c3660046149a9565b61124e565b005b34801561037f57600080fd5b50604080517f02e49c2c0000000000000000000000000000000000000000000000000000000081526000602082015201610319565b3480156103c057600080fd5b50600060405161031991906149c2565b3480156103dc57600080fd5b506103f06103eb366004614a11565b6112af565b6040516103199190614a63565b34801561040957600080fd5b5060025461041e90600160a01b900460ff1681565b60405160ff9091168152602001610319565b34801561043c57600080fd5b5061037161044b366004614afb565b611480565b34801561045c57600080fd5b506104e56040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a0810191909152506040805160c0810182526002546001600160a01b03908116825260055481166020830152600754811692820192909252600654821660608201526003548216608082015260045490911660a082015290565b6040516103199190600060c0820190506001600160a01b038084511683528060208501511660208401528060408501511660408401528060608501511660608401528060808501511660808401528060a08501511660a08401525092915050565b6103716105543660046149a9565b611777565b34801561056557600080fd5b50610590610574366004614b7d565b60086020526000908152604090205467ffffffffffffffff1681565b60405167ffffffffffffffff9091168152602001610319565b3480156105b557600080fd5b506103f06105c4366004614a11565b611851565b3480156105d557600080fd5b506103716105e4366004614b98565b611afe565b3480156105f557600080fd5b50610371610604366004614bd5565b611bd2565b34801561061557600080fd5b50610371610624366004614c38565b611e38565b61063c610637366004614c4a565b611fe6565b604051908152602001610319565b34801561065657600080fd5b5061063c610665366004614c74565b6121d9565b34801561067657600080fd5b504761063c565b34801561068957600080fd5b506106b17f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610319565b3480156106d557600080fd5b507f00000000000000000000000000000000000000000000000000000000000000006106b1565b34801561070857600080fd5b50610371612319565b34801561071d57600080fd5b506107457f000000000000000000000000000000000000000000000000000000000000000081565b60405163ffffffff9091168152602001610319565b61076d610768366004614c8f565b61232d565b604051610319929190614d2d565b34801561078757600080fd5b5061063c610796366004614d51565b612823565b3480156107a757600080fd5b5061041e7f000000000000000000000000000000000000000000000000000000000000000081565b3480156107db57600080fd5b5060015461063c565b3480156107f057600080fd5b506103716107ff3660046149a9565b612a2c565b34801561081057600080fd5b506000546001600160a01b03166106b1565b34801561082e57600080fd5b5061037161083d366004614d7d565b612a39565b34801561084e57600080fd5b50600a547f00000000000000000000000000000000000000000000000000000000000000006801000000000000000090910467ffffffffffffffff160261063c565b34801561089c57600080fd5b5060405160018152602001610319565b3480156108b857600080fd5b5061063c6108c7366004614df0565b612b8e565b3480156108d857600080fd5b50600a547f000000000000000000000000000000000000000000000000000000000000000070010000000000000000000000000000000090910467ffffffffffffffff160261063c565b34801561092e57600080fd5b5061037161093d366004614e2c565b612c7c565b34801561094e57600080fd5b50610371612e99565b34801561096357600080fd5b50610371610972366004614eb5565b612f02565b61076d610985366004614c8f565b612fbd565b34801561099657600080fd5b506103716109a5366004614ed2565b612ff1565b6109bd6109b8366004614c8f565b6130ec565b60405161031993929190614efe565b3480156109d857600080fd5b50600254610590907501000000000000000000000000000000000000000000900467ffffffffffffffff1681565b348015610a1257600080fd5b5061063c610a21366004614f59565b600960209081526000928352604080842090915290825290205481565b348015610a4a57600080fd5b5061063c600a5467ffffffffffffffff167f00000000000000000000000000000000000000000000000000000000000000000290565b348015610a8c57600080fd5b50610371610a9b366004614c74565b6132c1565b348015610aac57600080fd5b506106b17f000000000000000000000000000000000000000000000000000000000000000081565b600254606090600160a01b900460ff16600114610b4c57600254600119600160a01b90910460ff1601610b1a576040516376a9ad7360e01b815260040160405180910390fd5b6040517fdb22c33c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002805460ff60a01b1916600160a11b1790556003546001600160a01b0316338114610b8b57604051635bd25eff60e01b815260040160405180910390fd5b60008367ffffffffffffffff811115610ba657610ba6614f7c565b604051908082528060200260200182016040528015610beb57816020015b6040805180820190915260008082526020820152815260200190600190039081610bc45790505b5090506000805b85811015610ced5736878783818110610c0d57610c0d614fab565b90506060020190506000610c77826020016020810190610c2d9190614fda565b610c3d6060850160408601614fda565b60086000610c4e6020880188614b7d565b63ffffffff1663ffffffff1681526020019081526020016000206133709092919063ffffffff16565b905067ffffffffffffffff811615610ce3576040805180820190915280610ca16020850185614b7d565b63ffffffff16815267ffffffffffffffff83166020909101528585610cc581615026565b965081518110610cd757610cd7614fab565b60200260200101819052505b5050600101610bf2565b508082527fce105e156370093e6600169f7c01277f740d45fbcf95435227ce6f43ad0c3abd8783604051610d2292919061505e565b60405180910390a1509150506002805460ff60a01b1916600160a01b1790559392505050565b60408051808201909152600080825260208201526060610d7b604051806040016040528060008152602001600081525090565b60408051808201909152807f00000000000000000000000000000000000000000000000000000000000000008152602001610e1660086000886000016020810190610dc69190614b7d565b63ffffffff16815260208101919091526040016000205467ffffffffffffffff1667ffffffffffffffff167f00000000000000000000000000000000000000000000000000000000000000000290565b81525092506000610e438460200151866040013511610e39578560400135613426565b8460200151613426565b90506000610e73610e576020880188614b7d565b83610e6e610e6860c08b018b61507d565b15919050565b613466565b600254604080517f81993cd000000000000000000000000000000000000000000000000000000000815283516001600160a01b039081166004830152602085015163ffffffff1660248301529184015167ffffffffffffffff9081166044830152606085015116606482015260808401511515608482015260a0840151151560a48201529293506000929116906381993cd09060c401602060405180830381865afa158015610f26573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f4a91906150e2565b90508267ffffffffffffffff168167ffffffffffffffff16146111d15760408051600180825281830190925290816020015b604080518082019091526000815260606020820152815260200190600190039081610f7c5790505094508267ffffffffffffffff168167ffffffffffffffff16101561109e57604051806040016040528061101361100e8487610fdf91906150ff565b67ffffffffffffffff167f00000000000000000000000000000000000000000000000000000000000000000290565b61357b565b61103d907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff615120565b81526020016040518060400160405280600c81526020017f70726f746f636f6c2066656500000000000000000000000000000000000000008152508152508560008151811061108e5761108e614fab565b60200260200101819052506111d1565b8267ffffffffffffffff168167ffffffffffffffff1611156111d15760006110c684836150ff565b90506110d28282613631565b909250905067ffffffffffffffff80851690831603611131576040805160008082526020820190925290611129565b6040805180820190915260008152606060208201528152602001906001900390816111015790505b5095506111cf565b604051806040016040528061117261100e8467ffffffffffffffff167f00000000000000000000000000000000000000000000000000000000000000000290565b81526020016040518060400160405280600681526020017f7265776172640000000000000000000000000000000000000000000000000000815250815250866000815181106111c3576111c3614fab565b60200260200101819052505b505b604051806040016040528061120f8567ffffffffffffffff167f00000000000000000000000000000000000000000000000000000000000000000290565b81526020017f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff8416029052959794965050505050565b6005546001600160a01b031633811461127a57604051635bd25eff60e01b815260040160405180910390fd5b61128382613426565b600a60106101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055505050565b60408051808201909152600080825260208201526112d3610e6860c085018561507d565b611309576040517f2d9560be00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006113188460400135613426565b6006546040805160c081019091523381529192506001600160a01b031690633292cf029060208082019061134e90890189614b7d565b63ffffffff1681526020888101359082015267ffffffffffffffff8516604082015260600161138060a089018961507d565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050908252506020016113c7608089018961507d565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050509152506040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b168152611438919087906004016151db565b6040805180830381865afa158015611454573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114789190615289565b949350505050565b600254600160a01b900460ff166001146114c357600254600119600160a01b90910460ff1601610b1a576040516376a9ad7360e01b815260040160405180910390fd5b6002805460ff60a01b1916600160a11b1790556006546001600160a01b031633811461150257604051635bd25eff60e01b815260040160405180910390fd5b67ffffffffffffffff84167f000000000000000000000000000000000000000000000000000000000000000002821580159060609061159b5761159861154e60608c0160408d01614fda565b61155b60208d018d614b7d565b8589898080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061368592505050565b90505b60006115a789856136b7565b905080156116b9576115b8886136e4565b821561165d576040517f7cb590120000000000000000000000000000000000000000000000000000000081526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690637cb590129061162a908c908e9060009088906004016152a5565b600060405180830381600087803b15801561164457600080fd5b505af1158015611658573d6000803e3d6000fd5b505050505b6001600160a01b0389168a7fefed6d3500546b29533b128a29e3a94d70788727f0507505ac12eaf2e578fd9c61169660208f018f614b7d565b6040805163ffffffff9092168252602082018990520160405180910390a3611757565b6116c660208c018c614b7d565b8985846040516020016116dc94939291906152d7565b60408051601f19818403018152918152815160209283012060008d8152600984528281208180528452918220557e7c17198cd078035dc663f9a0961f84cb6265411d0b4c793f96d432f6af4b55918c9190611739908f018f614b7d565b8c888760405161174e96959493929190615355565b60405180910390a15b50506002805460ff60a01b1916600160a01b179055505050505050505050565b6007546001600160a01b03163381146117a357604051635bd25eff60e01b815260040160405180910390fd5b6117ac82613732565b60006117b8338461376a565b905080600260158282829054906101000a900467ffffffffffffffff166117df91906153a4565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055507fa064a2faa279f4d67c85c8fc69d4ebb7de2739a9e6dd864dfdd1b9e066d4bfd081604051611844919067ffffffffffffffff91909116815260200190565b60405180910390a1505050565b604080518082019091526000808252602082015260006118748460400135613426565b90508067ffffffffffffffff166000036118ba576040517f3442dd9500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006118cc610e6860c087018761507d565b90508015611a3a576006546040805160c081019091523381526001600160a01b0390911690633292cf0290602080820190611909908a018a614b7d565b63ffffffff1681526020898101359082015267ffffffffffffffff8616604082015260600161193b60a08a018a61507d565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050509082525060200161198260808a018a61507d565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050509152506040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526119f3919088906004016151db565b6040805180830381865afa158015611a0f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a339190615289565b9250611af6565b600080611a4a608088018861507d565b60065492109250506001600160a01b03166375d2208c611a6d6020890189614b7d565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815263ffffffff91909116600482015283151560248201526044016040805180830381865afa158015611ace573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611af29190615289565b9350505b505092915050565b611b066137cf565b7f000000000000000000000000000000000000000000000000000000000000000063ffffffff168263ffffffff1603611b6b576040517fada8342400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b63ffffffff8083166000908152600860205260409020611b8d91839061384316565b6040805163ffffffff8416815282151560208201527faf6b8dd4c5a827e03f548d06181b36aaba61e22436ff1cfa9bc409d576366a6091015b60405180910390a15050565b600254600160a01b900460ff16600114611c1557600254600119600160a01b90910460ff1601610b1a576040516376a9ad7360e01b815260040160405180910390fd5b6002805460ff60a01b1916600160a11b1790556006546001600160a01b0316338114611c5457604051635bd25eff60e01b815260040160405180910390fd5b67ffffffffffffffff82167f0000000000000000000000000000000000000000000000000000000000000000026000611c8d85836136b7565b90508015611cfa57611c9e846136e4565b6001600160a01b038516877fefed6d3500546b29533b128a29e3a94d70788727f0507505ac12eaf2e578fd9c611cd760208c018c614b7d565b6040805163ffffffff9092168252602082018790520160405180910390a3611e1b565b611d076020890189614b7d565b60405160e09190911b7fffffffff00000000000000000000000000000000000000000000000000000000166020820152606086901b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660248201526038810183905260580160408051601f19818403018152918152815160209283012060008a81526009845282812060ff8b168252845291909120557e7c17198cd078035dc663f9a0961f84cb6265411d0b4c793f96d432f6af4b559088908890611dcf908c018c614b7d565b6040805193845260ff909216602084015263ffffffff16908201526001600160a01b03871660608201526080810184905260c060a0820181905260009082015260e00160405180910390a15b50506002805460ff60a01b1916600160a01b179055505050505050565b611e406137cf565b611e4d6020820182614c74565b6002805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055611e8a6040820160208301614c74565b6005805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055611ec76060820160408301614c74565b6007805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055611f046080820160608301614c74565b6006805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055611f4160a0820160808301614c74565b6003805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055611f7e60c0820160a08301614c74565b6004805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03929092169190911790556040517f9774229668135b546675daf425e41c0848f60aa32d0951881245f4f528cc33f090611fdb9083906153c5565b60405180910390a150565b600254600090600160a01b900460ff1660011461202c57600254600119600160a01b90910460ff1601610b1a576040516376a9ad7360e01b815260040160405180910390fd5b6002805460ff60a01b1916600160a11b17905561204882613732565b6000612054338461376a565b905061205f8161390d565b7f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff8216026040517f40c10f190000000000000000000000000000000000000000000000000000000081526001600160a01b038681166004830152602482018390529193507f0000000000000000000000000000000000000000000000000000000000000000909116906340c10f1990604401600060405180830381600087803b15801561211457600080fd5b505af1158015612128573d6000803e3d6000fd5b5050600a805484935090915060009061214c90849067ffffffffffffffff166153a4565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550836001600160a01b0316336001600160a01b03167f8752a472e571a816aea92eec8dae9baf628e840f4929fbcc2d155e6233ff68a7846040516121b791815260200190565b60405180910390a3506002805460ff60a01b1916600160a01b17905592915050565b63ffffffff7f00000000000000000000000000000000000000000000000000000000000000001660009081526008602052604081205467ffffffffffffffff167f0000000000000000000000000000000000000000000000000000000000000000026001600160a01b0383166122515780915061230e565b6040517f70a082310000000000000000000000000000000000000000000000000000000081526001600160a01b0384811660048301526000917f0000000000000000000000000000000000000000000000000000000000000000909116906370a0823190602401602060405180830381865afa1580156122d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122f99190615444565b9050808211612308578161230a565b805b9250505b50919050565b905090565b6123216137cf565b61232b6000613974565b565b61233561470a565b6040805180820190915260008082526020820152600254600160a01b900460ff1660011461238c57600254600119600160a01b90910460ff1601610b1a576040516376a9ad7360e01b815260040160405180910390fd5b6002805460ff60a01b1916600160a11b1790556123af610e6860c087018761507d565b6123e5576040517f2d9560be00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006123f48660400135613426565b905060007f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff8316026040517f79cc6790000000000000000000000000000000000000000000000000000000008152336004820152602481018290529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906379cc679090604401600060405180830381600087803b1580156124a957600080fd5b505af11580156124bd573d6000803e3d6000fd5b5050604051838152600092503391507f27d4634c833b7622a0acddbf7f746183625f105945e95c723ad1d5a9f2a0b6fc9060200160405180910390a3600061251361250b60208a018a614b7d565b846001613466565b9050600061252d826125288b60600135613426565b6139d1565b600a8054919250859160009061254e90849067ffffffffffffffff166150ff565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055506125b781600860008c600001602081019061258f9190614b7d565b63ffffffff1663ffffffff168152602001908152602001600020613c2f90919063ffffffff16565b8067ffffffffffffffff168467ffffffffffffffff1611156126765760006125df82866150ff565b63ffffffff7f00000000000000000000000000000000000000000000000000000000000000008116600090815260086020526040902091925061262591908390613c2f16565b80600a60088282829054906101000a900467ffffffffffffffff1661264a91906150ff565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555050612731565b8067ffffffffffffffff168467ffffffffffffffff16101561273157600061269e85836150ff565b63ffffffff7f0000000000000000000000000000000000000000000000000000000000000000811660009081526008602052604090209192506126e491908390613cbd16565b80600a60088282829054906101000a900467ffffffffffffffff1661270991906153a4565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550505b600061274c612745368b90038b018b61545d565b6000613d57565b905061275a8a82848b613dac565b965060405180604001604052808581526020016127a08467ffffffffffffffff167f00000000000000000000000000000000000000000000000000000000000000000290565b9052875190965033907f85496b760a4b7f8d66384b9df21b381f5d1b1e79f229a47aaf4c232edc2fe59a6127d760208e018e614b7d565b60208a8101516040805163ffffffff90941684529183018a90529082015260600160405180910390a350506002805460ff60a01b1916600160a01b179055509296919550909350505050565b600254600090600160a01b900460ff1660011461286957600254600119600160a01b90910460ff1601610b1a576040516376a9ad7360e01b815260040160405180910390fd5b6002805460ff60a01b1916600160a11b179055600061288784613426565b63ffffffff7f0000000000000000000000000000000000000000000000000000000000000000811660009081526008602052604090209192506128cd91908390613c2f16565b7f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff8216026040517f79cc6790000000000000000000000000000000000000000000000000000000008152336004820152602481018290529092507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906379cc679090604401600060405180830381600087803b15801561297e57600080fd5b505af1158015612992573d6000803e3d6000fd5b5050600a80548493509091506000906129b690849067ffffffffffffffff166150ff565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055506129e68383613f3b565b6129ef816136e4565b6040518281526001600160a01b0384169033907f27d4634c833b7622a0acddbf7f746183625f105945e95c723ad1d5a9f2a0b6fc906020016121b7565b612a346137cf565b600155565b600254600160a01b900460ff16600114612a7c57600254600119600160a01b90910460ff1601610b1a576040516376a9ad7360e01b815260040160405180910390fd5b6002805460ff60a01b1916600160a11b1790556003546001600160a01b0316338114612abb57604051635bd25eff60e01b815260040160405180910390fd5b60005b82811015612b395736848483818110612ad957612ad9614fab565b9050604002019050612b30816020016020810190612af79190614fda565b60086000612b086020860186614b7d565b63ffffffff1663ffffffff168152602001908152602001600020613cbd90919063ffffffff16565b50600101612abe565b507f10c5f2b007767d266c6c75c86ae9ed0c74e6320b30bda231af7396a990e7263c848484604051612b6d9392919061548f565b60405180910390a150506002805460ff60a01b1916600160a01b1790555050565b6007546000906001600160a01b0316338114612bbd57604051635bd25eff60e01b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316856001600160a01b031603612c6657600254600a54600091612c3f91610fdf9167ffffffffffffffff7501000000000000000000000000000000000000000000909104811691680100000000000000009004166153a4565b612c47613f80565b612c519190615502565b9050808411612c605783612c62565b805b9350505b612c71858585614024565b91505b509392505050565b600254600160a01b900460ff16600114612cbf57600254600119600160a01b90910460ff1601610b1a576040516376a9ad7360e01b815260040160405180910390fd5b6002805460ff60a01b1916600160a11b179055604051612ceb9086908690869086908690602001615515565b60408051601f19818403018152918152815160209283012060008a81526009845282812060ff8b16825290935291205414612d52576040517faba8b6ef00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600087815260096020908152604080832060ff8a168452909152812055612d798484613f3b565b612d8a612d8584613426565b6136e4565b8015612e31576040517f7cb590120000000000000000000000000000000000000000000000000000000081526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690637cb5901290612dfe9087908b9060009088908890600401615587565b600060405180830381600087803b158015612e1857600080fd5b505af1158015612e2c573d6000803e3d6000fd5b505050505b6040805163ffffffff87168152602081018590526001600160a01b0386169189917fefed6d3500546b29533b128a29e3a94d70788727f0507505ac12eaf2e578fd9c910160405180910390a350506002805460ff60a01b1916600160a01b1790555050505050565b6005546001600160a01b0316338114612ec557604051635bd25eff60e01b815260040160405180910390fd5b47612ed233826000614111565b6040518181527f19e23b96a5e0d494b59baca97d1fe386cf8e80a978dfd8845d25f1a9d5c7e18390602001611bc6565b6005546001600160a01b0316338114612f2e57604051635bd25eff60e01b815260040160405180910390fd5b600254600119600160a01b90910460ff1601612f5d576040516376a9ad7360e01b815260040160405180910390fd5b81612f69576001612f6c565b60035b6002805460ff92909216600160a01b0260ff60a01b1990921691909117905560405182151581527f878ac8a2ca79520471f8f3c8494fa802c03ce3bf034252aad7f22318984fdbdb90602001611bc6565b612fc561470a565b6040805180820190915260008082526020820152612fe48585856130ec565b5090969095509350505050565b6007546001600160a01b031633811461301d57604051635bd25eff60e01b815260040160405180910390fd5b81600260158282829054906101000a900467ffffffffffffffff1661304291906150ff565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055506130a48361309f8467ffffffffffffffff167f00000000000000000000000000000000000000000000000000000000000000000290565b613f3b565b604080516001600160a01b038516815267ffffffffffffffff841660208201527fa46907b6b80b882da80d6e36cc905dde57fafff0a5442c8898526fe952d1e6539101611844565b6130f461470a565b6040805180820190915260008082526020820152604080518082019091526000815260606020820152600254600160a01b900460ff1660011461316057600254600119600160a01b90910460ff1601610b1a576040516376a9ad7360e01b815260040160405180910390fd5b6002805460ff60a01b1916600160a11b1790556000808061318089614152565b92509250925060405180604001604052806131c48467ffffffffffffffff167f00000000000000000000000000000000000000000000000000000000000000000290565b81526020017f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff84160290529450600061321561320e368b90038b018b61545d565b8751613d57565b90508315613230576132298a82848b613dac565b9650613242565b61323c8a82848b6141cc565b90975094505b865133907f85496b760a4b7f8d66384b9df21b381f5d1b1e79f229a47aaf4c232edc2fe59a61327460208e018e614b7d565b89516020808c01516040805163ffffffff90951685529184019290925282015260600160405180910390a350506002805460ff60a01b1916600160a01b1790555092969195509350915050565b6132c96137cf565b6001600160a01b038116613364576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b61336d81613974565b50565b825460009067ffffffffffffffff1667fffffffffffffffe1981016133c1576040517f5a5cc94600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8067ffffffffffffffff168367ffffffffffffffff161015612c745782810367ffffffffffffffff808216908616116133fa57846133fc565b805b865467ffffffffffffffff8285031667ffffffffffffffff19909116178755925050509392505050565b60006134607f0000000000000000000000000000000000000000000000000000000000000000838161345a5761345a6155d8565b046143c8565b92915050565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a0810191909152600a546000906134c89067ffffffffffffffff7001000000000000000000000000000000008204811691166153a4565b600a5490915060009067ffffffffffffffff680100000000000000009091048116908316116134f857600061351b565b600a5461351b9068010000000000000000900467ffffffffffffffff16836150ff565b6040805160c08101825233815263ffffffff8916602080830182905267ffffffffffffffff8a811684860152948516606084015260009182526008905291909120548216909114608082015284151560a0820152925050505b9392505050565b60007f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82111561362d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602860248201527f53616665436173743a2076616c756520646f65736e27742066697420696e206160448201527f6e20696e74323536000000000000000000000000000000000000000000000000606482015260840161335b565b5090565b600254600090819067ffffffffffffffff750100000000000000000000000000000000000000000090910481169084168110156136765783850381019250905061367e565b848492509250505b9250929050565b60608484848460405160200161369e9493929190615607565b6040516020818303038152906040529050949350505050565b60006135747f00000000000000000000000000000000000000000000000000000000000000008484614462565b80600a60088282829054906101000a900467ffffffffffffffff1661370991906150ff565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555050565b341561336d576040517f3442dd9500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061377582613426565b90506134607f000000000000000000000000000000000000000000000000000000000000000084307f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff86160261450e565b6000546001600160a01b0316331461232b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161335b565b815467ffffffffffffffff1681156138b55767ffffffffffffffff811615613897576040517fca2bc39800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b825467ffffffffffffffff191667ffffffffffffffff178355505050565b67ffffffffffffffff818116146138f8576040517fca2bc39800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b825467ffffffffffffffff191683555b505050565b63ffffffff7f00000000000000000000000000000000000000000000000000000000000000008116600090815260086020526040902061394f918390613cbd16565b80600a60088282829054906101000a900467ffffffffffffffff1661370991906153a4565b600080546001600160a01b0383811673ffffffffffffffffffffffffffffffffffffffff19831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600254604080517f43d9564d00000000000000000000000000000000000000000000000000000000815284516001600160a01b039081166004830152602086015163ffffffff1660248301529185015167ffffffffffffffff9081166044830152606086015116606482015260808501511515608482015260a0850151151560a482015260009291909116906343d9564d9060c4016020604051808303816000875af1158015613a85573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613aa991906150e2565b604084015190915067ffffffffffffffff8082169083161015613b3057613ad082826150ff565b60028054601590613b059084907501000000000000000000000000000000000000000000900467ffffffffffffffff166153a4565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550613bc7565b8067ffffffffffffffff168267ffffffffffffffff161115613bc7576000613b5882846150ff565b9050613b648382613631565b909350905067ffffffffffffffff811615613bc55780600260158282829054906101000a900467ffffffffffffffff16613b9e91906150ff565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055505b505b8267ffffffffffffffff168267ffffffffffffffff161080613bf1575067ffffffffffffffff8216155b15613c28576040517fa1e8654500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5092915050565b815467ffffffffffffffff1667fffffffffffffffe198101613c5057505050565b8167ffffffffffffffff168167ffffffffffffffff161015613c9e576040517f2b4d0ad500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b825467ffffffffffffffff191691900367ffffffffffffffff16179055565b815467ffffffffffffffff1667fffffffffffffffe198101613cde57505050565b613ce882826153a4565b905067fffffffffffffffe1967ffffffffffffffff821601613d36576040517f5a5cc94600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b825467ffffffffffffffff191667ffffffffffffffff919091161790915550565b604080518082019091526000808252602082015282513414613da5576040517f3442dd9500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5090919050565b613db461470a565b602084015115613dcb57613dcb8460200151614556565b60065484516040805160c081019091523381526001600160a01b039092169163ff6fb3009190602080820190613e03908b018b614b7d565b63ffffffff16815260208a8101359082015267ffffffffffffffff88166040820152606001613e3560a08b018b61507d565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250505090825250602001613e7c60808b018b61507d565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050509152506040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b168152613eef919089908890600401615685565b60806040518083038185885af1158015613f0d573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190613f329190615735565b95945050505050565b6000613f4783836136b7565b905080613908576040517f06a6167e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015614000573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123149190615444565b600254600090600160a01b900460ff1660011461406a57600254600119600160a01b90910460ff1601610b1a576040516376a9ad7360e01b815260040160405180910390fd5b6002805460ff60a01b1916600160a11b1790556007546001600160a01b03163381146140a957604051635bd25eff60e01b815260040160405180910390fd5b6001600160a01b0385166140e9576040517f809fc44b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6140f685858560006145c9565b50506002805460ff60a01b1916600160a01b17905592915050565b61411c8383836145d5565b613908576040517f7c75c3d200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008080614166610e6860c086018661507d565b925061417633856040013561376a565b9150600061419161418a6020870187614b7d565b8486613466565b90506141a4816125288760600135613426565b91506141bb826008600061258f60208a018a614b7d565b6141c48261390d565b509193909250565b6141d461470a565b604080518082019091526000815260606020820152602085015115614225576040517fb5e0bf8d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6006546040805160a081019091523381526001600160a01b03909116906385afd4539060208082019061425a908b018b614b7d565b63ffffffff16815260208a8101359082015267ffffffffffffffff88166040820152606001600061428e60808c018c61507d565b9190911190915250604080517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815282516001600160a01b03166004820152602083015163ffffffff166024820152908201516044820152606082015167ffffffffffffffff1660648201526080909101511515608482015260a4016000604051808303816000875af115801561432f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526143579190810190615751565b6040820151518751929450909250908082146143bd578181111561438b57818103614384868260006145d5565b50506143bd565b6040517fa028531600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505094509492505050565b600067ffffffffffffffff82111561362d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203660448201527f3420626974730000000000000000000000000000000000000000000000000000606482015260840161335b565b6040516001600160a01b0383166024820152604481018290526000906114789085907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091526145fc565b61451a84848484614689565b614550576040517f7c75c3d200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050565b6004546001600160a01b031680614599576040517fb5e0bf8d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6145c581337f00000000000000000000000000000000000000000000000000000000000000008561450e565b5050565b61451a848484846146dd565b600080826145e3575a6145e7565b6001545b9050600080600080878986f195945050505050565b6000806000846001600160a01b0316846040516146199190615846565b6000604051808303816000865af19150503d8060008114614656576040519150601f19603f3d011682016040523d82523d6000602084013e61465b565b606091505b50915091508161466c576000613f32565b80511580613f32575080806020019051810190613f329190615862565b6040516001600160a01b0380851660248301528316604482015260648101829052600090613f329086907f23b872dd00000000000000000000000000000000000000000000000000000000906084016144aa565b60006001600160a01b0385166146ff576146f88484846145d5565b9050611478565b613f32858585614462565b604051806060016040528060008019168152602001600067ffffffffffffffff16815260200161474d604051806040016040528060008152602001600081525090565b905290565b803563ffffffff8116811461476657600080fd5b919050565b60008060006040848603121561478057600080fd5b61478984614752565b9250602084013567ffffffffffffffff808211156147a657600080fd5b818601915086601f8301126147ba57600080fd5b8135818111156147c957600080fd5b8760206060830285010111156147de57600080fd5b6020830194508093505050509250925092565b60008151808452602080850194506020840160005b8381101561483d578151805163ffffffff16885283015167ffffffffffffffff168388015260409096019590820190600101614806565b509495945050505050565b60208152600061357460208301846147f1565b600060e0828403121561230e57600080fd5b60006020828403121561487f57600080fd5b813567ffffffffffffffff81111561489657600080fd5b6114788482850161485b565b60005b838110156148bd5781810151838201526020016148a5565b50506000910152565b600081518084526148de8160208601602086016148a2565b601f01601f19169290920160200192915050565b8351815260208085015190820152600060a08201604060a0604085015281865180845260c08601915060c08160051b8701019350602080890160005b8381101561498b578887037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff40018552815180518852830151838801879052614978878901826148c6565b975050938201939082019060010161492e565b50508751606088015250505060208501516080850152509050611478565b6000602082840312156149bb57600080fd5b5035919050565b60208101600283106149fd577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b91905290565b801515811461336d57600080fd5b60008060408385031215614a2457600080fd5b823567ffffffffffffffff811115614a3b57600080fd5b614a478582860161485b565b9250506020830135614a5881614a03565b809150509250929050565b815181526020808301519082015260408101613460565b60006060828403121561230e57600080fd5b80356001600160a01b038116811461476657600080fd5b67ffffffffffffffff8116811461336d57600080fd5b60008083601f840112614acb57600080fd5b50813567ffffffffffffffff811115614ae357600080fd5b60208301915083602082850101111561367e57600080fd5b60008060008060008060e08789031215614b1457600080fd5b614b1e8888614a7a565b955060608701359450614b3360808801614a8c565b935060a0870135614b4381614aa3565b925060c087013567ffffffffffffffff811115614b5f57600080fd5b614b6b89828a01614ab9565b979a9699509497509295939492505050565b600060208284031215614b8f57600080fd5b61357482614752565b60008060408385031215614bab57600080fd5b614bb483614752565b91506020830135614a5881614a03565b803560ff8116811461476657600080fd5b600080600080600060e08688031215614bed57600080fd5b614bf78787614a7a565b945060608601359350614c0c60808701614bc4565b9250614c1a60a08701614a8c565b915060c0860135614c2a81614aa3565b809150509295509295909350565b600060c0828403121561230e57600080fd5b60008060408385031215614c5d57600080fd5b614c6683614a8c565b946020939093013593505050565b600060208284031215614c8657600080fd5b61357482614a8c565b60008060008385036080811215614ca557600080fd5b843567ffffffffffffffff811115614cbc57600080fd5b614cc88782880161485b565b9450506040601f1982011215614cdd57600080fd5b50602084019150614cf060608501614a8c565b90509250925092565b8051825267ffffffffffffffff60208201511660208301526040810151613908604084018280518252602090810151910152565b60c08101614d3b8285614cf9565b82516080830152602083015160a0830152613574565b60008060408385031215614d6457600080fd5b82359150614d7460208401614a8c565b90509250929050565b600080600060408486031215614d9257600080fd5b614d9b84614752565b9250602084013567ffffffffffffffff80821115614db857600080fd5b818601915086601f830112614dcc57600080fd5b813581811115614ddb57600080fd5b8760208260061b85010111156147de57600080fd5b600080600060608486031215614e0557600080fd5b614e0e84614a8c565b9250614e1c60208501614a8c565b9150604084013590509250925092565b600080600080600080600060c0888a031215614e4757600080fd5b87359650614e5760208901614bc4565b9550614e6560408901614752565b9450614e7360608901614a8c565b93506080880135925060a088013567ffffffffffffffff811115614e9657600080fd5b614ea28a828b01614ab9565b989b979a50959850939692959293505050565b600060208284031215614ec757600080fd5b813561357481614a03565b60008060408385031215614ee557600080fd5b614eee83614a8c565b91506020830135614a5881614aa3565b614f088185614cf9565b82516080820152602083015160a082015260e060c082015268ffffffffffffffffff82511660e0820152600060208301516040610100840152614f4f6101208401826148c6565b9695505050505050565b60008060408385031215614f6c57600080fd5b82359150614d7460208401614bc4565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060208284031215614fec57600080fd5b813561357481614aa3565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361505757615057614ff7565b5060010190565b63ffffffff8316815260406020820152600061147860408301846147f1565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126150b257600080fd5b83018035915067ffffffffffffffff8211156150cd57600080fd5b60200191503681900382131561367e57600080fd5b6000602082840312156150f457600080fd5b815161357481614aa3565b67ffffffffffffffff828116828216039080821115613c2857613c28614ff7565b808202600082127f80000000000000000000000000000000000000000000000000000000000000008414161561515857615158614ff7565b818105831482151761346057613460614ff7565b6001600160a01b03815116825263ffffffff60208201511660208301526040810151604083015267ffffffffffffffff60608201511660608301526000608082015160c060808501526151c260c08501826148c6565b905060a083015184820360a0860152613f3282826148c6565b6040815260006151ee604083018561516c565b905082151560208301529392505050565b6040805190810167ffffffffffffffff8111828210171561522257615222614f7c565b60405290565b604051601f8201601f1916810167ffffffffffffffff8111828210171561525157615251614f7c565b604052919050565b60006040828403121561526b57600080fd5b6152736151ff565b9050815181526020820151602082015292915050565b60006040828403121561529b57600080fd5b6135748383615259565b6001600160a01b038516815283602082015261ffff83166040820152608060608201526000614f4f60808301846148c6565b7fffffffff000000000000000000000000000000000000000000000000000000008560e01b1681527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008460601b166004820152826018820152600082516153458160388501602087016148a2565b9190910160380195945050505050565b86815260ff8616602082015263ffffffff851660408201526001600160a01b038416606082015282608082015260c060a0820152600061539860c08301846148c6565b98975050505050505050565b67ffffffffffffffff818116838216019080821115613c2857613c28614ff7565b60c081016001600160a01b03806153db85614a8c565b168352806153eb60208601614a8c565b166020840152806153fe60408601614a8c565b1660408401528061541160608601614a8c565b1660608401528061542460808601614a8c565b1660808401528061543760a08601614a8c565b1660a08401525092915050565b60006020828403121561545657600080fd5b5051919050565b60006040828403121561546f57600080fd5b6154776151ff565b82358152602083013560208201528091505092915050565b63ffffffff848116825260406020808401829052838201859052600092869160608601855b888110156154f457836154c686614752565b168252828501356154d681614aa3565b67ffffffffffffffff168284015293850193908501906001016154b4565b509998505050505050505050565b8181038181111561346057613460614ff7565b7fffffffff000000000000000000000000000000000000000000000000000000008660e01b1681527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008560601b1660048201528360188201528183603883013760009101603801908152949350505050565b6001600160a01b038616815284602082015261ffff8416604082015260806060820152816080820152818360a0830137600081830160a090810191909152601f909201601f19160101949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7fffffffffffffffff0000000000000000000000000000000000000000000000008560c01b1681527fffffffff000000000000000000000000000000000000000000000000000000008460e01b16600882015282600c8201526000825161567581602c8501602087016148a2565b91909101602c0195945050505050565b608081526000615698608083018661516c565b90506156b1602083018580518252602090810151910152565b6001600160a01b0383166060830152949350505050565b6000608082840312156156da57600080fd5b6040516060810181811067ffffffffffffffff821117156156fd576156fd614f7c565b806040525080915082518152602083015161571781614aa3565b60208201526157298460408501615259565b60408201525092915050565b60006080828403121561574757600080fd5b61357483836156c8565b60008060a0838503121561576457600080fd5b61576e84846156c8565b9150608083015167ffffffffffffffff8082111561578b57600080fd5b908401906040828703121561579f57600080fd5b6157a76151ff565b825168ffffffffffffffffff811681146157c057600080fd5b8152602083810151838111156157d557600080fd5b80850194505087601f8501126157ea57600080fd5b8351838111156157fc576157fc614f7c565b61580e82601f19601f84011601615228565b9350808452888282870101111561582457600080fd5b615833818386018488016148a2565b5081019190915292959294509192505050565b600082516158588184602087016148a2565b9190910192915050565b60006020828403121561587457600080fd5b815161357481614a0356fea2646970667358221220344b30d2c92d88fb6dfd2663e3a197653b4f4962501044fa2236a8f9e886ad4064736f6c634300081600336101a06040523480156200001257600080fd5b5060405162001c0f38038062001c0f833981016040819052620000359162000292565b6040805180820190915260018152603160f81b60208201528390819081856003620000618382620003a8565b506004620000708282620003a8565b50620000829150839050600562000140565b610120526200009381600662000140565b61014052815160208084019190912060e052815190820120610100524660a0526200012160e05161010051604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201529081019290925260608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b60805250503060c05250336101605260ff166101805250620004ce9050565b60006020835110156200016057620001588362000179565b905062000173565b816200016d8482620003a8565b5060ff90505b92915050565b600080829050601f81511115620001b0578260405163305a27a960e01b8152600401620001a7919062000474565b60405180910390fd5b8051620001bd82620004a9565b179392505050565b634e487b7160e01b600052604160045260246000fd5b60005b83811015620001f8578181015183820152602001620001de565b50506000910152565b600082601f8301126200021357600080fd5b81516001600160401b0380821115620002305762000230620001c5565b604051601f8301601f19908116603f011681019082821181831017156200025b576200025b620001c5565b816040528381528660208588010111156200027557600080fd5b62000288846020830160208901620001db565b9695505050505050565b600080600060608486031215620002a857600080fd5b83516001600160401b0380821115620002c057600080fd5b620002ce8783880162000201565b94506020860151915080821115620002e557600080fd5b50620002f48682870162000201565b925050604084015160ff811681146200030c57600080fd5b809150509250925092565b600181811c908216806200032c57607f821691505b6020821081036200034d57634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620003a3576000816000526020600020601f850160051c810160208610156200037e5750805b601f850160051c820191505b818110156200039f578281556001016200038a565b5050505b505050565b81516001600160401b03811115620003c457620003c4620001c5565b620003dc81620003d5845462000317565b8462000353565b602080601f831160018114620004145760008415620003fb5750858301515b600019600386901b1c1916600185901b1785556200039f565b600085815260208120601f198616915b82811015620004455788860151825594840194600190910190840162000424565b5085821015620004645787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b602081526000825180602084015262000495816040850160208701620001db565b601f01601f19169190910160400192915050565b805160208083015191908110156200034d5760001960209190910360031b1b16919050565b60805160a05160c05160e05161010051610120516101405161016051610180516116c26200054d60003960006101a80152600081816102070152818161044e01526104be015260006105760152600061054b01526000610ce201526000610cba01526000610c1501526000610c3f01526000610c6901526116c26000f3fe608060405234801561001057600080fd5b50600436106101365760003560e01c806370a08231116100b257806395d89b4111610081578063a9059cbb11610066578063a9059cbb146102c6578063d505accf146102d9578063dd62ed3e146102ec57600080fd5b806395d89b41146102ab578063a457c2d7146102b357600080fd5b806370a082311461024157806379cc67901461026a5780637ecebe001461027d57806384b0196e1461029057600080fd5b8063313ce5671161010957806339509351116100ee57806339509351146101da57806340c10f19146101ed5780636c099dee1461020257600080fd5b8063313ce567146101a15780633644e515146101d257600080fd5b806306fdde031461013b578063095ea7b31461015957806318160ddd1461017c57806323b872dd1461018e575b600080fd5b610143610325565b60405161015091906113c4565b60405180910390f35b61016c6101673660046113fa565b6103b7565b6040519015158152602001610150565b6002545b604051908152602001610150565b61016c61019c366004611424565b6103d1565b60405160ff7f0000000000000000000000000000000000000000000000000000000000000000168152602001610150565b6101806103f5565b61016c6101e83660046113fa565b610404565b6102006101fb3660046113fa565b610443565b005b6102297f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610150565b61018061024f366004611460565b6001600160a01b031660009081526020819052604090205490565b6102006102783660046113fa565b6104b3565b61018061028b366004611460565b61051f565b61029861053d565b604051610150979695949392919061147b565b6101436105e2565b61016c6102c13660046113fa565b6105f1565b61016c6102d43660046113fa565b6106a0565b6102006102e7366004611530565b6106ae565b6101806102fa3660046115a3565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b606060038054610334906115d6565b80601f0160208091040260200160405190810160405280929190818152602001828054610360906115d6565b80156103ad5780601f10610382576101008083540402835291602001916103ad565b820191906000526020600020905b81548152906001019060200180831161039057829003601f168201915b5050505050905090565b6000336103c5818585610812565b60019150505b92915050565b6000336103df85828561096b565b6103ea858585610a1b565b506001949350505050565b60006103ff610c08565b905090565b3360008181526001602090815260408083206001600160a01b03871684529091528120549091906103c5908290869061043e908790611623565b610812565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146104a5576040517fba06efeb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6104af8282610d33565b5050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610515576040517fba06efeb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6104af8282610df2565b6001600160a01b0381166000908152600760205260408120546103cb565b6000606080828080836105717f00000000000000000000000000000000000000000000000000000000000000006005610f53565b61059c7f00000000000000000000000000000000000000000000000000000000000000006006610f53565b604080516000808252602082019092527f0f000000000000000000000000000000000000000000000000000000000000009b939a50919850469750309650945092509050565b606060048054610334906115d6565b3360008181526001602090815260408083206001600160a01b0387168452909152812054909190838110156106935760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760448201527f207a65726f00000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b6103ea8286868403610812565b6000336103c5818585610a1b565b834211156106fe5760405162461bcd60e51b815260206004820152601d60248201527f45524332305065726d69743a206578706972656420646561646c696e65000000604482015260640161068a565b60007f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c988888861072d8c610ffe565b6040805160208101969096526001600160a01b0394851690860152929091166060840152608083015260a082015260c0810186905260e001604051602081830303815290604052805190602001209050600061078882611026565b905060006107988287878761106e565b9050896001600160a01b0316816001600160a01b0316146107fb5760405162461bcd60e51b815260206004820152601e60248201527f45524332305065726d69743a20696e76616c6964207369676e61747572650000604482015260640161068a565b6108068a8a8a610812565b50505050505050505050565b6001600160a01b03831661088d5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460448201527f7265737300000000000000000000000000000000000000000000000000000000606482015260840161068a565b6001600160a01b0382166109095760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f20616464726560448201527f7373000000000000000000000000000000000000000000000000000000000000606482015260840161068a565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b6001600160a01b038381166000908152600160209081526040808320938616835292905220547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114610a155781811015610a085760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e6365000000604482015260640161068a565b610a158484848403610812565b50505050565b6001600160a01b038316610a975760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f20616460448201527f6472657373000000000000000000000000000000000000000000000000000000606482015260840161068a565b6001600160a01b038216610b135760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201527f6573730000000000000000000000000000000000000000000000000000000000606482015260840161068a565b6001600160a01b03831660009081526020819052604090205481811015610ba25760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e742065786365656473206260448201527f616c616e63650000000000000000000000000000000000000000000000000000606482015260840161068a565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3610a15565b6000306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148015610c6157507f000000000000000000000000000000000000000000000000000000000000000046145b15610c8b57507f000000000000000000000000000000000000000000000000000000000000000090565b6103ff604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f0000000000000000000000000000000000000000000000000000000000000000918101919091527f000000000000000000000000000000000000000000000000000000000000000060608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b6001600160a01b038216610d895760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015260640161068a565b8060026000828254610d9b9190611623565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b6001600160a01b038216610e6e5760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f2061646472657360448201527f7300000000000000000000000000000000000000000000000000000000000000606482015260840161068a565b6001600160a01b03821660009081526020819052604090205481811015610efd5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e60448201527f6365000000000000000000000000000000000000000000000000000000000000606482015260840161068a565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910161095e565b606060ff8314610f6d57610f6683611096565b90506103cb565b818054610f79906115d6565b80601f0160208091040260200160405190810160405280929190818152602001828054610fa5906115d6565b8015610ff25780601f10610fc757610100808354040283529160200191610ff2565b820191906000526020600020905b815481529060010190602001808311610fd557829003601f168201915b505050505090506103cb565b6001600160a01b03811660009081526007602052604090208054600181018255905b50919050565b60006103cb611033610c08565b836040517f19010000000000000000000000000000000000000000000000000000000000008152600281019290925260228201526042902090565b600080600061107f878787876110d5565b9150915061108c816111b7565b5095945050505050565b606060006110a38361131f565b604080516020808252818301909252919250600091906020820181803683375050509182525060208101929092525090565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a083111561110c57506000905060036111ae565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015611160573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001519150506001600160a01b0381166111a7576000600192509250506111ae565b9150600090505b94509492505050565b60008160048111156111cb576111cb61165d565b036111d35750565b60018160048111156111e7576111e761165d565b036112345760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e61747572650000000000000000604482015260640161068a565b60028160048111156112485761124861165d565b036112955760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e67746800604482015260640161068a565b60038160048111156112a9576112a961165d565b0361131c5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f7565000000000000000000000000000000000000000000000000000000000000606482015260840161068a565b50565b600060ff8216601f8111156103cb576040517fb3512b0c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000815180845260005b818110156113865760208185018101518683018201520161136a565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b6020815260006113d76020830184611360565b9392505050565b80356001600160a01b03811681146113f557600080fd5b919050565b6000806040838503121561140d57600080fd5b611416836113de565b946020939093013593505050565b60008060006060848603121561143957600080fd5b611442846113de565b9250611450602085016113de565b9150604084013590509250925092565b60006020828403121561147257600080fd5b6113d7826113de565b7fff00000000000000000000000000000000000000000000000000000000000000881681526000602060e060208401526114b860e084018a611360565b83810360408501526114ca818a611360565b606085018990526001600160a01b038816608086015260a0850187905284810360c08601528551808252602080880193509091019060005b8181101561151e57835183529284019291840191600101611502565b50909c9b505050505050505050505050565b600080600080600080600060e0888a03121561154b57600080fd5b611554886113de565b9650611562602089016113de565b95506040880135945060608801359350608088013560ff8116811461158657600080fd5b9699959850939692959460a0840135945060c09093013592915050565b600080604083850312156115b657600080fd5b6115bf836113de565b91506115cd602084016113de565b90509250929050565b600181811c908216806115ea57607f821691505b602082108103611020577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b808201808211156103cb577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fdfea2646970667358221220b01be794a387189911d440646b5ba0a63c9fb90dcea8cee9cb89be9b6970d81b64736f6c6343000816003300000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000d5f7838f5c461feff7fe49ea5ebaf7728bb0adfa000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000060000000000000000000000001a44076050125825900e736c501f859c50fe728c0000000000000000000000004a79adc4539905376d339c69b6a7092d0598cc2400000000000000000000000000000000000000000000000000000000000000076d4554482d4c50000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006532a6d4554480000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x6080604052600436106102e75760003560e01c8063764f6a7811610184578063a88835d7116100d6578063cbef2aa91161008a578063e5328e0611610064578063e5328e0614610a3e578063f2fde38b14610a80578063fc0c546a14610aa057600080fd5b8063cbef2aa9146109aa578063cc32d176146109cc578063d621ad3f14610a0657600080fd5b8063bedb86fb116100bb578063bedb86fb14610957578063c7c7f5b314610977578063c859c4831461098a57600080fd5b8063a88835d714610922578063b0d7ca5d1461094257600080fd5b80638da5cb5b116101385780639f68b964116101125780639f68b96414610890578063a7229fd9146108ac578063a85dc7f2146108cc57600080fd5b80638da5cb5b146108045780639561b12f1461082257806396365d441461084257600080fd5b8063857749b011610169578063857749b01461079b57806388543f0e146107cf5780638c70830b146107e457600080fd5b8063764f6a781461075a5780637bde82f21461077b57600080fd5b80633b6f743b1161023d578063484267a4116101f15780635fcbd285116101cb5780635fcbd285146106c9578063715018a6146106fc578063726075371461071157600080fd5b8063484267a41461064a5780635114bf091461066a5780635e280f111461067d57600080fd5b8063434def5511610222578063434def55146105e9578063461bb0b91461060957806347e7ef241461062957600080fd5b80633b6f743b146105a95780633faa12c5146105c957600080fd5b8063192adc5d1161029f5780632bc5114c116102795780632bc5114c14610450578063341a46481461054657806338da6b8e1461055957600080fd5b8063192adc5d146103d0578063200d2ed2146103fd578063203bd15f1461043057600080fd5b806313bc4bc7116102d057806313bc4bc714610351578063156a0d0f1461037357806316909bca146103b457600080fd5b80630141e41b146102ec5780630d35b41514610322575b600080fd5b3480156102f857600080fd5b5061030c61030736600461476b565b610ad4565b6040516103199190614848565b60405180910390f35b34801561032e57600080fd5b5061034261033d36600461486d565b610d48565b604051610319939291906148f2565b34801561035d57600080fd5b5061037161036c3660046149a9565b61124e565b005b34801561037f57600080fd5b50604080517f02e49c2c0000000000000000000000000000000000000000000000000000000081526000602082015201610319565b3480156103c057600080fd5b50600060405161031991906149c2565b3480156103dc57600080fd5b506103f06103eb366004614a11565b6112af565b6040516103199190614a63565b34801561040957600080fd5b5060025461041e90600160a01b900460ff1681565b60405160ff9091168152602001610319565b34801561043c57600080fd5b5061037161044b366004614afb565b611480565b34801561045c57600080fd5b506104e56040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a0810191909152506040805160c0810182526002546001600160a01b03908116825260055481166020830152600754811692820192909252600654821660608201526003548216608082015260045490911660a082015290565b6040516103199190600060c0820190506001600160a01b038084511683528060208501511660208401528060408501511660408401528060608501511660608401528060808501511660808401528060a08501511660a08401525092915050565b6103716105543660046149a9565b611777565b34801561056557600080fd5b50610590610574366004614b7d565b60086020526000908152604090205467ffffffffffffffff1681565b60405167ffffffffffffffff9091168152602001610319565b3480156105b557600080fd5b506103f06105c4366004614a11565b611851565b3480156105d557600080fd5b506103716105e4366004614b98565b611afe565b3480156105f557600080fd5b50610371610604366004614bd5565b611bd2565b34801561061557600080fd5b50610371610624366004614c38565b611e38565b61063c610637366004614c4a565b611fe6565b604051908152602001610319565b34801561065657600080fd5b5061063c610665366004614c74565b6121d9565b34801561067657600080fd5b504761063c565b34801561068957600080fd5b506106b17f0000000000000000000000001a44076050125825900e736c501f859c50fe728c81565b6040516001600160a01b039091168152602001610319565b3480156106d557600080fd5b507f000000000000000000000000d646cd9dff77097b454a5a148beae6615e3bc2e26106b1565b34801561070857600080fd5b50610371612319565b34801561071d57600080fd5b506107457f000000000000000000000000000000000000000000000000000000000000759581565b60405163ffffffff9091168152602001610319565b61076d610768366004614c8f565b61232d565b604051610319929190614d2d565b34801561078757600080fd5b5061063c610796366004614d51565b612823565b3480156107a757600080fd5b5061041e7f000000000000000000000000000000000000000000000000000000000000000681565b3480156107db57600080fd5b5060015461063c565b3480156107f057600080fd5b506103716107ff3660046149a9565b612a2c565b34801561081057600080fd5b506000546001600160a01b03166106b1565b34801561082e57600080fd5b5061037161083d366004614d7d565b612a39565b34801561084e57600080fd5b50600a547f000000000000000000000000000000000000000000000000000000e8d4a510006801000000000000000090910467ffffffffffffffff160261063c565b34801561089c57600080fd5b5060405160018152602001610319565b3480156108b857600080fd5b5061063c6108c7366004614df0565b612b8e565b3480156108d857600080fd5b50600a547f000000000000000000000000000000000000000000000000000000e8d4a5100070010000000000000000000000000000000090910467ffffffffffffffff160261063c565b34801561092e57600080fd5b5061037161093d366004614e2c565b612c7c565b34801561094e57600080fd5b50610371612e99565b34801561096357600080fd5b50610371610972366004614eb5565b612f02565b61076d610985366004614c8f565b612fbd565b34801561099657600080fd5b506103716109a5366004614ed2565b612ff1565b6109bd6109b8366004614c8f565b6130ec565b60405161031993929190614efe565b3480156109d857600080fd5b50600254610590907501000000000000000000000000000000000000000000900467ffffffffffffffff1681565b348015610a1257600080fd5b5061063c610a21366004614f59565b600960209081526000928352604080842090915290825290205481565b348015610a4a57600080fd5b5061063c600a5467ffffffffffffffff167f000000000000000000000000000000000000000000000000000000e8d4a510000290565b348015610a8c57600080fd5b50610371610a9b366004614c74565b6132c1565b348015610aac57600080fd5b506106b17f000000000000000000000000d5f7838f5c461feff7fe49ea5ebaf7728bb0adfa81565b600254606090600160a01b900460ff16600114610b4c57600254600119600160a01b90910460ff1601610b1a576040516376a9ad7360e01b815260040160405180910390fd5b6040517fdb22c33c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002805460ff60a01b1916600160a11b1790556003546001600160a01b0316338114610b8b57604051635bd25eff60e01b815260040160405180910390fd5b60008367ffffffffffffffff811115610ba657610ba6614f7c565b604051908082528060200260200182016040528015610beb57816020015b6040805180820190915260008082526020820152815260200190600190039081610bc45790505b5090506000805b85811015610ced5736878783818110610c0d57610c0d614fab565b90506060020190506000610c77826020016020810190610c2d9190614fda565b610c3d6060850160408601614fda565b60086000610c4e6020880188614b7d565b63ffffffff1663ffffffff1681526020019081526020016000206133709092919063ffffffff16565b905067ffffffffffffffff811615610ce3576040805180820190915280610ca16020850185614b7d565b63ffffffff16815267ffffffffffffffff83166020909101528585610cc581615026565b965081518110610cd757610cd7614fab565b60200260200101819052505b5050600101610bf2565b508082527fce105e156370093e6600169f7c01277f740d45fbcf95435227ce6f43ad0c3abd8783604051610d2292919061505e565b60405180910390a1509150506002805460ff60a01b1916600160a01b1790559392505050565b60408051808201909152600080825260208201526060610d7b604051806040016040528060008152602001600081525090565b60408051808201909152807f000000000000000000000000000000000000000000000000000000e8d4a510008152602001610e1660086000886000016020810190610dc69190614b7d565b63ffffffff16815260208101919091526040016000205467ffffffffffffffff1667ffffffffffffffff167f000000000000000000000000000000000000000000000000000000e8d4a510000290565b81525092506000610e438460200151866040013511610e39578560400135613426565b8460200151613426565b90506000610e73610e576020880188614b7d565b83610e6e610e6860c08b018b61507d565b15919050565b613466565b600254604080517f81993cd000000000000000000000000000000000000000000000000000000000815283516001600160a01b039081166004830152602085015163ffffffff1660248301529184015167ffffffffffffffff9081166044830152606085015116606482015260808401511515608482015260a0840151151560a48201529293506000929116906381993cd09060c401602060405180830381865afa158015610f26573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f4a91906150e2565b90508267ffffffffffffffff168167ffffffffffffffff16146111d15760408051600180825281830190925290816020015b604080518082019091526000815260606020820152815260200190600190039081610f7c5790505094508267ffffffffffffffff168167ffffffffffffffff16101561109e57604051806040016040528061101361100e8487610fdf91906150ff565b67ffffffffffffffff167f000000000000000000000000000000000000000000000000000000e8d4a510000290565b61357b565b61103d907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff615120565b81526020016040518060400160405280600c81526020017f70726f746f636f6c2066656500000000000000000000000000000000000000008152508152508560008151811061108e5761108e614fab565b60200260200101819052506111d1565b8267ffffffffffffffff168167ffffffffffffffff1611156111d15760006110c684836150ff565b90506110d28282613631565b909250905067ffffffffffffffff80851690831603611131576040805160008082526020820190925290611129565b6040805180820190915260008152606060208201528152602001906001900390816111015790505b5095506111cf565b604051806040016040528061117261100e8467ffffffffffffffff167f000000000000000000000000000000000000000000000000000000e8d4a510000290565b81526020016040518060400160405280600681526020017f7265776172640000000000000000000000000000000000000000000000000000815250815250866000815181106111c3576111c3614fab565b60200260200101819052505b505b604051806040016040528061120f8567ffffffffffffffff167f000000000000000000000000000000000000000000000000000000e8d4a510000290565b81526020017f000000000000000000000000000000000000000000000000000000e8d4a5100067ffffffffffffffff8416029052959794965050505050565b6005546001600160a01b031633811461127a57604051635bd25eff60e01b815260040160405180910390fd5b61128382613426565b600a60106101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055505050565b60408051808201909152600080825260208201526112d3610e6860c085018561507d565b611309576040517f2d9560be00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006113188460400135613426565b6006546040805160c081019091523381529192506001600160a01b031690633292cf029060208082019061134e90890189614b7d565b63ffffffff1681526020888101359082015267ffffffffffffffff8516604082015260600161138060a089018961507d565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050908252506020016113c7608089018961507d565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050509152506040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b168152611438919087906004016151db565b6040805180830381865afa158015611454573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114789190615289565b949350505050565b600254600160a01b900460ff166001146114c357600254600119600160a01b90910460ff1601610b1a576040516376a9ad7360e01b815260040160405180910390fd5b6002805460ff60a01b1916600160a11b1790556006546001600160a01b031633811461150257604051635bd25eff60e01b815260040160405180910390fd5b67ffffffffffffffff84167f000000000000000000000000000000000000000000000000000000e8d4a5100002821580159060609061159b5761159861154e60608c0160408d01614fda565b61155b60208d018d614b7d565b8589898080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061368592505050565b90505b60006115a789856136b7565b905080156116b9576115b8886136e4565b821561165d576040517f7cb590120000000000000000000000000000000000000000000000000000000081526001600160a01b037f0000000000000000000000001a44076050125825900e736c501f859c50fe728c1690637cb590129061162a908c908e9060009088906004016152a5565b600060405180830381600087803b15801561164457600080fd5b505af1158015611658573d6000803e3d6000fd5b505050505b6001600160a01b0389168a7fefed6d3500546b29533b128a29e3a94d70788727f0507505ac12eaf2e578fd9c61169660208f018f614b7d565b6040805163ffffffff9092168252602082018990520160405180910390a3611757565b6116c660208c018c614b7d565b8985846040516020016116dc94939291906152d7565b60408051601f19818403018152918152815160209283012060008d8152600984528281208180528452918220557e7c17198cd078035dc663f9a0961f84cb6265411d0b4c793f96d432f6af4b55918c9190611739908f018f614b7d565b8c888760405161174e96959493929190615355565b60405180910390a15b50506002805460ff60a01b1916600160a01b179055505050505050505050565b6007546001600160a01b03163381146117a357604051635bd25eff60e01b815260040160405180910390fd5b6117ac82613732565b60006117b8338461376a565b905080600260158282829054906101000a900467ffffffffffffffff166117df91906153a4565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055507fa064a2faa279f4d67c85c8fc69d4ebb7de2739a9e6dd864dfdd1b9e066d4bfd081604051611844919067ffffffffffffffff91909116815260200190565b60405180910390a1505050565b604080518082019091526000808252602082015260006118748460400135613426565b90508067ffffffffffffffff166000036118ba576040517f3442dd9500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006118cc610e6860c087018761507d565b90508015611a3a576006546040805160c081019091523381526001600160a01b0390911690633292cf0290602080820190611909908a018a614b7d565b63ffffffff1681526020898101359082015267ffffffffffffffff8616604082015260600161193b60a08a018a61507d565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050509082525060200161198260808a018a61507d565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050509152506040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526119f3919088906004016151db565b6040805180830381865afa158015611a0f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a339190615289565b9250611af6565b600080611a4a608088018861507d565b60065492109250506001600160a01b03166375d2208c611a6d6020890189614b7d565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815263ffffffff91909116600482015283151560248201526044016040805180830381865afa158015611ace573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611af29190615289565b9350505b505092915050565b611b066137cf565b7f000000000000000000000000000000000000000000000000000000000000759563ffffffff168263ffffffff1603611b6b576040517fada8342400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b63ffffffff8083166000908152600860205260409020611b8d91839061384316565b6040805163ffffffff8416815282151560208201527faf6b8dd4c5a827e03f548d06181b36aaba61e22436ff1cfa9bc409d576366a6091015b60405180910390a15050565b600254600160a01b900460ff16600114611c1557600254600119600160a01b90910460ff1601610b1a576040516376a9ad7360e01b815260040160405180910390fd5b6002805460ff60a01b1916600160a11b1790556006546001600160a01b0316338114611c5457604051635bd25eff60e01b815260040160405180910390fd5b67ffffffffffffffff82167f000000000000000000000000000000000000000000000000000000e8d4a51000026000611c8d85836136b7565b90508015611cfa57611c9e846136e4565b6001600160a01b038516877fefed6d3500546b29533b128a29e3a94d70788727f0507505ac12eaf2e578fd9c611cd760208c018c614b7d565b6040805163ffffffff9092168252602082018790520160405180910390a3611e1b565b611d076020890189614b7d565b60405160e09190911b7fffffffff00000000000000000000000000000000000000000000000000000000166020820152606086901b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660248201526038810183905260580160408051601f19818403018152918152815160209283012060008a81526009845282812060ff8b168252845291909120557e7c17198cd078035dc663f9a0961f84cb6265411d0b4c793f96d432f6af4b559088908890611dcf908c018c614b7d565b6040805193845260ff909216602084015263ffffffff16908201526001600160a01b03871660608201526080810184905260c060a0820181905260009082015260e00160405180910390a15b50506002805460ff60a01b1916600160a01b179055505050505050565b611e406137cf565b611e4d6020820182614c74565b6002805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055611e8a6040820160208301614c74565b6005805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055611ec76060820160408301614c74565b6007805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055611f046080820160608301614c74565b6006805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055611f4160a0820160808301614c74565b6003805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0392909216919091179055611f7e60c0820160a08301614c74565b6004805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03929092169190911790556040517f9774229668135b546675daf425e41c0848f60aa32d0951881245f4f528cc33f090611fdb9083906153c5565b60405180910390a150565b600254600090600160a01b900460ff1660011461202c57600254600119600160a01b90910460ff1601610b1a576040516376a9ad7360e01b815260040160405180910390fd5b6002805460ff60a01b1916600160a11b17905561204882613732565b6000612054338461376a565b905061205f8161390d565b7f000000000000000000000000000000000000000000000000000000e8d4a5100067ffffffffffffffff8216026040517f40c10f190000000000000000000000000000000000000000000000000000000081526001600160a01b038681166004830152602482018390529193507f000000000000000000000000d646cd9dff77097b454a5a148beae6615e3bc2e2909116906340c10f1990604401600060405180830381600087803b15801561211457600080fd5b505af1158015612128573d6000803e3d6000fd5b5050600a805484935090915060009061214c90849067ffffffffffffffff166153a4565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550836001600160a01b0316336001600160a01b03167f8752a472e571a816aea92eec8dae9baf628e840f4929fbcc2d155e6233ff68a7846040516121b791815260200190565b60405180910390a3506002805460ff60a01b1916600160a01b17905592915050565b63ffffffff7f00000000000000000000000000000000000000000000000000000000000075951660009081526008602052604081205467ffffffffffffffff167f000000000000000000000000000000000000000000000000000000e8d4a51000026001600160a01b0383166122515780915061230e565b6040517f70a082310000000000000000000000000000000000000000000000000000000081526001600160a01b0384811660048301526000917f000000000000000000000000d646cd9dff77097b454a5a148beae6615e3bc2e2909116906370a0823190602401602060405180830381865afa1580156122d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122f99190615444565b9050808211612308578161230a565b805b9250505b50919050565b905090565b6123216137cf565b61232b6000613974565b565b61233561470a565b6040805180820190915260008082526020820152600254600160a01b900460ff1660011461238c57600254600119600160a01b90910460ff1601610b1a576040516376a9ad7360e01b815260040160405180910390fd5b6002805460ff60a01b1916600160a11b1790556123af610e6860c087018761507d565b6123e5576040517f2d9560be00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006123f48660400135613426565b905060007f000000000000000000000000000000000000000000000000000000e8d4a5100067ffffffffffffffff8316026040517f79cc6790000000000000000000000000000000000000000000000000000000008152336004820152602481018290529091507f000000000000000000000000d646cd9dff77097b454a5a148beae6615e3bc2e26001600160a01b0316906379cc679090604401600060405180830381600087803b1580156124a957600080fd5b505af11580156124bd573d6000803e3d6000fd5b5050604051838152600092503391507f27d4634c833b7622a0acddbf7f746183625f105945e95c723ad1d5a9f2a0b6fc9060200160405180910390a3600061251361250b60208a018a614b7d565b846001613466565b9050600061252d826125288b60600135613426565b6139d1565b600a8054919250859160009061254e90849067ffffffffffffffff166150ff565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055506125b781600860008c600001602081019061258f9190614b7d565b63ffffffff1663ffffffff168152602001908152602001600020613c2f90919063ffffffff16565b8067ffffffffffffffff168467ffffffffffffffff1611156126765760006125df82866150ff565b63ffffffff7f00000000000000000000000000000000000000000000000000000000000075958116600090815260086020526040902091925061262591908390613c2f16565b80600a60088282829054906101000a900467ffffffffffffffff1661264a91906150ff565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555050612731565b8067ffffffffffffffff168467ffffffffffffffff16101561273157600061269e85836150ff565b63ffffffff7f0000000000000000000000000000000000000000000000000000000000007595811660009081526008602052604090209192506126e491908390613cbd16565b80600a60088282829054906101000a900467ffffffffffffffff1661270991906153a4565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550505b600061274c612745368b90038b018b61545d565b6000613d57565b905061275a8a82848b613dac565b965060405180604001604052808581526020016127a08467ffffffffffffffff167f000000000000000000000000000000000000000000000000000000e8d4a510000290565b9052875190965033907f85496b760a4b7f8d66384b9df21b381f5d1b1e79f229a47aaf4c232edc2fe59a6127d760208e018e614b7d565b60208a8101516040805163ffffffff90941684529183018a90529082015260600160405180910390a350506002805460ff60a01b1916600160a01b179055509296919550909350505050565b600254600090600160a01b900460ff1660011461286957600254600119600160a01b90910460ff1601610b1a576040516376a9ad7360e01b815260040160405180910390fd5b6002805460ff60a01b1916600160a11b179055600061288784613426565b63ffffffff7f0000000000000000000000000000000000000000000000000000000000007595811660009081526008602052604090209192506128cd91908390613c2f16565b7f000000000000000000000000000000000000000000000000000000e8d4a5100067ffffffffffffffff8216026040517f79cc6790000000000000000000000000000000000000000000000000000000008152336004820152602481018290529092507f000000000000000000000000d646cd9dff77097b454a5a148beae6615e3bc2e26001600160a01b0316906379cc679090604401600060405180830381600087803b15801561297e57600080fd5b505af1158015612992573d6000803e3d6000fd5b5050600a80548493509091506000906129b690849067ffffffffffffffff166150ff565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055506129e68383613f3b565b6129ef816136e4565b6040518281526001600160a01b0384169033907f27d4634c833b7622a0acddbf7f746183625f105945e95c723ad1d5a9f2a0b6fc906020016121b7565b612a346137cf565b600155565b600254600160a01b900460ff16600114612a7c57600254600119600160a01b90910460ff1601610b1a576040516376a9ad7360e01b815260040160405180910390fd5b6002805460ff60a01b1916600160a11b1790556003546001600160a01b0316338114612abb57604051635bd25eff60e01b815260040160405180910390fd5b60005b82811015612b395736848483818110612ad957612ad9614fab565b9050604002019050612b30816020016020810190612af79190614fda565b60086000612b086020860186614b7d565b63ffffffff1663ffffffff168152602001908152602001600020613cbd90919063ffffffff16565b50600101612abe565b507f10c5f2b007767d266c6c75c86ae9ed0c74e6320b30bda231af7396a990e7263c848484604051612b6d9392919061548f565b60405180910390a150506002805460ff60a01b1916600160a01b1790555050565b6007546000906001600160a01b0316338114612bbd57604051635bd25eff60e01b815260040160405180910390fd5b7f000000000000000000000000d5f7838f5c461feff7fe49ea5ebaf7728bb0adfa6001600160a01b0316856001600160a01b031603612c6657600254600a54600091612c3f91610fdf9167ffffffffffffffff7501000000000000000000000000000000000000000000909104811691680100000000000000009004166153a4565b612c47613f80565b612c519190615502565b9050808411612c605783612c62565b805b9350505b612c71858585614024565b91505b509392505050565b600254600160a01b900460ff16600114612cbf57600254600119600160a01b90910460ff1601610b1a576040516376a9ad7360e01b815260040160405180910390fd5b6002805460ff60a01b1916600160a11b179055604051612ceb9086908690869086908690602001615515565b60408051601f19818403018152918152815160209283012060008a81526009845282812060ff8b16825290935291205414612d52576040517faba8b6ef00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600087815260096020908152604080832060ff8a168452909152812055612d798484613f3b565b612d8a612d8584613426565b6136e4565b8015612e31576040517f7cb590120000000000000000000000000000000000000000000000000000000081526001600160a01b037f0000000000000000000000001a44076050125825900e736c501f859c50fe728c1690637cb5901290612dfe9087908b9060009088908890600401615587565b600060405180830381600087803b158015612e1857600080fd5b505af1158015612e2c573d6000803e3d6000fd5b505050505b6040805163ffffffff87168152602081018590526001600160a01b0386169189917fefed6d3500546b29533b128a29e3a94d70788727f0507505ac12eaf2e578fd9c910160405180910390a350506002805460ff60a01b1916600160a01b1790555050505050565b6005546001600160a01b0316338114612ec557604051635bd25eff60e01b815260040160405180910390fd5b47612ed233826000614111565b6040518181527f19e23b96a5e0d494b59baca97d1fe386cf8e80a978dfd8845d25f1a9d5c7e18390602001611bc6565b6005546001600160a01b0316338114612f2e57604051635bd25eff60e01b815260040160405180910390fd5b600254600119600160a01b90910460ff1601612f5d576040516376a9ad7360e01b815260040160405180910390fd5b81612f69576001612f6c565b60035b6002805460ff92909216600160a01b0260ff60a01b1990921691909117905560405182151581527f878ac8a2ca79520471f8f3c8494fa802c03ce3bf034252aad7f22318984fdbdb90602001611bc6565b612fc561470a565b6040805180820190915260008082526020820152612fe48585856130ec565b5090969095509350505050565b6007546001600160a01b031633811461301d57604051635bd25eff60e01b815260040160405180910390fd5b81600260158282829054906101000a900467ffffffffffffffff1661304291906150ff565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055506130a48361309f8467ffffffffffffffff167f000000000000000000000000000000000000000000000000000000e8d4a510000290565b613f3b565b604080516001600160a01b038516815267ffffffffffffffff841660208201527fa46907b6b80b882da80d6e36cc905dde57fafff0a5442c8898526fe952d1e6539101611844565b6130f461470a565b6040805180820190915260008082526020820152604080518082019091526000815260606020820152600254600160a01b900460ff1660011461316057600254600119600160a01b90910460ff1601610b1a576040516376a9ad7360e01b815260040160405180910390fd5b6002805460ff60a01b1916600160a11b1790556000808061318089614152565b92509250925060405180604001604052806131c48467ffffffffffffffff167f000000000000000000000000000000000000000000000000000000e8d4a510000290565b81526020017f000000000000000000000000000000000000000000000000000000e8d4a5100067ffffffffffffffff84160290529450600061321561320e368b90038b018b61545d565b8751613d57565b90508315613230576132298a82848b613dac565b9650613242565b61323c8a82848b6141cc565b90975094505b865133907f85496b760a4b7f8d66384b9df21b381f5d1b1e79f229a47aaf4c232edc2fe59a61327460208e018e614b7d565b89516020808c01516040805163ffffffff90951685529184019290925282015260600160405180910390a350506002805460ff60a01b1916600160a01b1790555092969195509350915050565b6132c96137cf565b6001600160a01b038116613364576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b61336d81613974565b50565b825460009067ffffffffffffffff1667fffffffffffffffe1981016133c1576040517f5a5cc94600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8067ffffffffffffffff168367ffffffffffffffff161015612c745782810367ffffffffffffffff808216908616116133fa57846133fc565b805b865467ffffffffffffffff8285031667ffffffffffffffff19909116178755925050509392505050565b60006134607f000000000000000000000000000000000000000000000000000000e8d4a51000838161345a5761345a6155d8565b046143c8565b92915050565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a0810191909152600a546000906134c89067ffffffffffffffff7001000000000000000000000000000000008204811691166153a4565b600a5490915060009067ffffffffffffffff680100000000000000009091048116908316116134f857600061351b565b600a5461351b9068010000000000000000900467ffffffffffffffff16836150ff565b6040805160c08101825233815263ffffffff8916602080830182905267ffffffffffffffff8a811684860152948516606084015260009182526008905291909120548216909114608082015284151560a0820152925050505b9392505050565b60007f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82111561362d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602860248201527f53616665436173743a2076616c756520646f65736e27742066697420696e206160448201527f6e20696e74323536000000000000000000000000000000000000000000000000606482015260840161335b565b5090565b600254600090819067ffffffffffffffff750100000000000000000000000000000000000000000090910481169084168110156136765783850381019250905061367e565b848492509250505b9250929050565b60608484848460405160200161369e9493929190615607565b6040516020818303038152906040529050949350505050565b60006135747f000000000000000000000000d5f7838f5c461feff7fe49ea5ebaf7728bb0adfa8484614462565b80600a60088282829054906101000a900467ffffffffffffffff1661370991906150ff565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555050565b341561336d576040517f3442dd9500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061377582613426565b90506134607f000000000000000000000000d5f7838f5c461feff7fe49ea5ebaf7728bb0adfa84307f000000000000000000000000000000000000000000000000000000e8d4a5100067ffffffffffffffff86160261450e565b6000546001600160a01b0316331461232b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161335b565b815467ffffffffffffffff1681156138b55767ffffffffffffffff811615613897576040517fca2bc39800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b825467ffffffffffffffff191667ffffffffffffffff178355505050565b67ffffffffffffffff818116146138f8576040517fca2bc39800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b825467ffffffffffffffff191683555b505050565b63ffffffff7f00000000000000000000000000000000000000000000000000000000000075958116600090815260086020526040902061394f918390613cbd16565b80600a60088282829054906101000a900467ffffffffffffffff1661370991906153a4565b600080546001600160a01b0383811673ffffffffffffffffffffffffffffffffffffffff19831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600254604080517f43d9564d00000000000000000000000000000000000000000000000000000000815284516001600160a01b039081166004830152602086015163ffffffff1660248301529185015167ffffffffffffffff9081166044830152606086015116606482015260808501511515608482015260a0850151151560a482015260009291909116906343d9564d9060c4016020604051808303816000875af1158015613a85573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613aa991906150e2565b604084015190915067ffffffffffffffff8082169083161015613b3057613ad082826150ff565b60028054601590613b059084907501000000000000000000000000000000000000000000900467ffffffffffffffff166153a4565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550613bc7565b8067ffffffffffffffff168267ffffffffffffffff161115613bc7576000613b5882846150ff565b9050613b648382613631565b909350905067ffffffffffffffff811615613bc55780600260158282829054906101000a900467ffffffffffffffff16613b9e91906150ff565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055505b505b8267ffffffffffffffff168267ffffffffffffffff161080613bf1575067ffffffffffffffff8216155b15613c28576040517fa1e8654500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5092915050565b815467ffffffffffffffff1667fffffffffffffffe198101613c5057505050565b8167ffffffffffffffff168167ffffffffffffffff161015613c9e576040517f2b4d0ad500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b825467ffffffffffffffff191691900367ffffffffffffffff16179055565b815467ffffffffffffffff1667fffffffffffffffe198101613cde57505050565b613ce882826153a4565b905067fffffffffffffffe1967ffffffffffffffff821601613d36576040517f5a5cc94600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b825467ffffffffffffffff191667ffffffffffffffff919091161790915550565b604080518082019091526000808252602082015282513414613da5576040517f3442dd9500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5090919050565b613db461470a565b602084015115613dcb57613dcb8460200151614556565b60065484516040805160c081019091523381526001600160a01b039092169163ff6fb3009190602080820190613e03908b018b614b7d565b63ffffffff16815260208a8101359082015267ffffffffffffffff88166040820152606001613e3560a08b018b61507d565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250505090825250602001613e7c60808b018b61507d565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050509152506040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b168152613eef919089908890600401615685565b60806040518083038185885af1158015613f0d573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190613f329190615735565b95945050505050565b6000613f4783836136b7565b905080613908576040517f06a6167e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000d5f7838f5c461feff7fe49ea5ebaf7728bb0adfa6001600160a01b0316906370a0823190602401602060405180830381865afa158015614000573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123149190615444565b600254600090600160a01b900460ff1660011461406a57600254600119600160a01b90910460ff1601610b1a576040516376a9ad7360e01b815260040160405180910390fd5b6002805460ff60a01b1916600160a11b1790556007546001600160a01b03163381146140a957604051635bd25eff60e01b815260040160405180910390fd5b6001600160a01b0385166140e9576040517f809fc44b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6140f685858560006145c9565b50506002805460ff60a01b1916600160a01b17905592915050565b61411c8383836145d5565b613908576040517f7c75c3d200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008080614166610e6860c086018661507d565b925061417633856040013561376a565b9150600061419161418a6020870187614b7d565b8486613466565b90506141a4816125288760600135613426565b91506141bb826008600061258f60208a018a614b7d565b6141c48261390d565b509193909250565b6141d461470a565b604080518082019091526000815260606020820152602085015115614225576040517fb5e0bf8d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6006546040805160a081019091523381526001600160a01b03909116906385afd4539060208082019061425a908b018b614b7d565b63ffffffff16815260208a8101359082015267ffffffffffffffff88166040820152606001600061428e60808c018c61507d565b9190911190915250604080517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815282516001600160a01b03166004820152602083015163ffffffff166024820152908201516044820152606082015167ffffffffffffffff1660648201526080909101511515608482015260a4016000604051808303816000875af115801561432f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526143579190810190615751565b6040820151518751929450909250908082146143bd578181111561438b57818103614384868260006145d5565b50506143bd565b6040517fa028531600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505094509492505050565b600067ffffffffffffffff82111561362d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203660448201527f3420626974730000000000000000000000000000000000000000000000000000606482015260840161335b565b6040516001600160a01b0383166024820152604481018290526000906114789085907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091526145fc565b61451a84848484614689565b614550576040517f7c75c3d200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050565b6004546001600160a01b031680614599576040517fb5e0bf8d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6145c581337f0000000000000000000000001a44076050125825900e736c501f859c50fe728c8561450e565b5050565b61451a848484846146dd565b600080826145e3575a6145e7565b6001545b9050600080600080878986f195945050505050565b6000806000846001600160a01b0316846040516146199190615846565b6000604051808303816000865af19150503d8060008114614656576040519150601f19603f3d011682016040523d82523d6000602084013e61465b565b606091505b50915091508161466c576000613f32565b80511580613f32575080806020019051810190613f329190615862565b6040516001600160a01b0380851660248301528316604482015260648101829052600090613f329086907f23b872dd00000000000000000000000000000000000000000000000000000000906084016144aa565b60006001600160a01b0385166146ff576146f88484846145d5565b9050611478565b613f32858585614462565b604051806060016040528060008019168152602001600067ffffffffffffffff16815260200161474d604051806040016040528060008152602001600081525090565b905290565b803563ffffffff8116811461476657600080fd5b919050565b60008060006040848603121561478057600080fd5b61478984614752565b9250602084013567ffffffffffffffff808211156147a657600080fd5b818601915086601f8301126147ba57600080fd5b8135818111156147c957600080fd5b8760206060830285010111156147de57600080fd5b6020830194508093505050509250925092565b60008151808452602080850194506020840160005b8381101561483d578151805163ffffffff16885283015167ffffffffffffffff168388015260409096019590820190600101614806565b509495945050505050565b60208152600061357460208301846147f1565b600060e0828403121561230e57600080fd5b60006020828403121561487f57600080fd5b813567ffffffffffffffff81111561489657600080fd5b6114788482850161485b565b60005b838110156148bd5781810151838201526020016148a5565b50506000910152565b600081518084526148de8160208601602086016148a2565b601f01601f19169290920160200192915050565b8351815260208085015190820152600060a08201604060a0604085015281865180845260c08601915060c08160051b8701019350602080890160005b8381101561498b578887037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff40018552815180518852830151838801879052614978878901826148c6565b975050938201939082019060010161492e565b50508751606088015250505060208501516080850152509050611478565b6000602082840312156149bb57600080fd5b5035919050565b60208101600283106149fd577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b91905290565b801515811461336d57600080fd5b60008060408385031215614a2457600080fd5b823567ffffffffffffffff811115614a3b57600080fd5b614a478582860161485b565b9250506020830135614a5881614a03565b809150509250929050565b815181526020808301519082015260408101613460565b60006060828403121561230e57600080fd5b80356001600160a01b038116811461476657600080fd5b67ffffffffffffffff8116811461336d57600080fd5b60008083601f840112614acb57600080fd5b50813567ffffffffffffffff811115614ae357600080fd5b60208301915083602082850101111561367e57600080fd5b60008060008060008060e08789031215614b1457600080fd5b614b1e8888614a7a565b955060608701359450614b3360808801614a8c565b935060a0870135614b4381614aa3565b925060c087013567ffffffffffffffff811115614b5f57600080fd5b614b6b89828a01614ab9565b979a9699509497509295939492505050565b600060208284031215614b8f57600080fd5b61357482614752565b60008060408385031215614bab57600080fd5b614bb483614752565b91506020830135614a5881614a03565b803560ff8116811461476657600080fd5b600080600080600060e08688031215614bed57600080fd5b614bf78787614a7a565b945060608601359350614c0c60808701614bc4565b9250614c1a60a08701614a8c565b915060c0860135614c2a81614aa3565b809150509295509295909350565b600060c0828403121561230e57600080fd5b60008060408385031215614c5d57600080fd5b614c6683614a8c565b946020939093013593505050565b600060208284031215614c8657600080fd5b61357482614a8c565b60008060008385036080811215614ca557600080fd5b843567ffffffffffffffff811115614cbc57600080fd5b614cc88782880161485b565b9450506040601f1982011215614cdd57600080fd5b50602084019150614cf060608501614a8c565b90509250925092565b8051825267ffffffffffffffff60208201511660208301526040810151613908604084018280518252602090810151910152565b60c08101614d3b8285614cf9565b82516080830152602083015160a0830152613574565b60008060408385031215614d6457600080fd5b82359150614d7460208401614a8c565b90509250929050565b600080600060408486031215614d9257600080fd5b614d9b84614752565b9250602084013567ffffffffffffffff80821115614db857600080fd5b818601915086601f830112614dcc57600080fd5b813581811115614ddb57600080fd5b8760208260061b85010111156147de57600080fd5b600080600060608486031215614e0557600080fd5b614e0e84614a8c565b9250614e1c60208501614a8c565b9150604084013590509250925092565b600080600080600080600060c0888a031215614e4757600080fd5b87359650614e5760208901614bc4565b9550614e6560408901614752565b9450614e7360608901614a8c565b93506080880135925060a088013567ffffffffffffffff811115614e9657600080fd5b614ea28a828b01614ab9565b989b979a50959850939692959293505050565b600060208284031215614ec757600080fd5b813561357481614a03565b60008060408385031215614ee557600080fd5b614eee83614a8c565b91506020830135614a5881614aa3565b614f088185614cf9565b82516080820152602083015160a082015260e060c082015268ffffffffffffffffff82511660e0820152600060208301516040610100840152614f4f6101208401826148c6565b9695505050505050565b60008060408385031215614f6c57600080fd5b82359150614d7460208401614bc4565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060208284031215614fec57600080fd5b813561357481614aa3565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361505757615057614ff7565b5060010190565b63ffffffff8316815260406020820152600061147860408301846147f1565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126150b257600080fd5b83018035915067ffffffffffffffff8211156150cd57600080fd5b60200191503681900382131561367e57600080fd5b6000602082840312156150f457600080fd5b815161357481614aa3565b67ffffffffffffffff828116828216039080821115613c2857613c28614ff7565b808202600082127f80000000000000000000000000000000000000000000000000000000000000008414161561515857615158614ff7565b818105831482151761346057613460614ff7565b6001600160a01b03815116825263ffffffff60208201511660208301526040810151604083015267ffffffffffffffff60608201511660608301526000608082015160c060808501526151c260c08501826148c6565b905060a083015184820360a0860152613f3282826148c6565b6040815260006151ee604083018561516c565b905082151560208301529392505050565b6040805190810167ffffffffffffffff8111828210171561522257615222614f7c565b60405290565b604051601f8201601f1916810167ffffffffffffffff8111828210171561525157615251614f7c565b604052919050565b60006040828403121561526b57600080fd5b6152736151ff565b9050815181526020820151602082015292915050565b60006040828403121561529b57600080fd5b6135748383615259565b6001600160a01b038516815283602082015261ffff83166040820152608060608201526000614f4f60808301846148c6565b7fffffffff000000000000000000000000000000000000000000000000000000008560e01b1681527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008460601b166004820152826018820152600082516153458160388501602087016148a2565b9190910160380195945050505050565b86815260ff8616602082015263ffffffff851660408201526001600160a01b038416606082015282608082015260c060a0820152600061539860c08301846148c6565b98975050505050505050565b67ffffffffffffffff818116838216019080821115613c2857613c28614ff7565b60c081016001600160a01b03806153db85614a8c565b168352806153eb60208601614a8c565b166020840152806153fe60408601614a8c565b1660408401528061541160608601614a8c565b1660608401528061542460808601614a8c565b1660808401528061543760a08601614a8c565b1660a08401525092915050565b60006020828403121561545657600080fd5b5051919050565b60006040828403121561546f57600080fd5b6154776151ff565b82358152602083013560208201528091505092915050565b63ffffffff848116825260406020808401829052838201859052600092869160608601855b888110156154f457836154c686614752565b168252828501356154d681614aa3565b67ffffffffffffffff168284015293850193908501906001016154b4565b509998505050505050505050565b8181038181111561346057613460614ff7565b7fffffffff000000000000000000000000000000000000000000000000000000008660e01b1681527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008560601b1660048201528360188201528183603883013760009101603801908152949350505050565b6001600160a01b038616815284602082015261ffff8416604082015260806060820152816080820152818360a0830137600081830160a090810191909152601f909201601f19160101949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7fffffffffffffffff0000000000000000000000000000000000000000000000008560c01b1681527fffffffff000000000000000000000000000000000000000000000000000000008460e01b16600882015282600c8201526000825161567581602c8501602087016148a2565b91909101602c0195945050505050565b608081526000615698608083018661516c565b90506156b1602083018580518252602090810151910152565b6001600160a01b0383166060830152949350505050565b6000608082840312156156da57600080fd5b6040516060810181811067ffffffffffffffff821117156156fd576156fd614f7c565b806040525080915082518152602083015161571781614aa3565b60208201526157298460408501615259565b60408201525092915050565b60006080828403121561574757600080fd5b61357483836156c8565b60008060a0838503121561576457600080fd5b61576e84846156c8565b9150608083015167ffffffffffffffff8082111561578b57600080fd5b908401906040828703121561579f57600080fd5b6157a76151ff565b825168ffffffffffffffffff811681146157c057600080fd5b8152602083810151838111156157d557600080fd5b80850194505087601f8501126157ea57600080fd5b8351838111156157fc576157fc614f7c565b61580e82601f19601f84011601615228565b9350808452888282870101111561582457600080fd5b615833818386018488016148a2565b5081019190915292959294509192505050565b600082516158588184602087016148a2565b9190910192915050565b60006020828403121561587457600080fd5b815161357481614a0356fea2646970667358221220344b30d2c92d88fb6dfd2663e3a197653b4f4962501044fa2236a8f9e886ad4064736f6c63430008160033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000d5f7838f5c461feff7fe49ea5ebaf7728bb0adfa000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000060000000000000000000000001a44076050125825900e736c501f859c50fe728c0000000000000000000000004a79adc4539905376d339c69b6a7092d0598cc2400000000000000000000000000000000000000000000000000000000000000076d4554482d4c50000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006532a6d4554480000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : _lpTokenName (string): mETH-LP
Arg [1] : _lpTokenSymbol (string): S*mETH
Arg [2] : _token (address): 0xd5F7838F5C461fefF7FE49ea5ebaF7728bB0ADfa
Arg [3] : _tokenDecimals (uint8): 18
Arg [4] : _sharedDecimals (uint8): 6
Arg [5] : _endpoint (address): 0x1a44076050125825900e736c501f859c50fE728c
Arg [6] : _owner (address): 0x4A79AdC4539905376D339C69b6a7092D0598cc24
-----Encoded View---------------
11 Constructor Arguments found :
Arg [0] : 00000000000000000000000000000000000000000000000000000000000000e0
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000120
Arg [2] : 000000000000000000000000d5f7838f5c461feff7fe49ea5ebaf7728bb0adfa
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000012
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000006
Arg [5] : 0000000000000000000000001a44076050125825900e736c501f859c50fe728c
Arg [6] : 0000000000000000000000004a79adc4539905376d339c69b6a7092d0598cc24
Arg [7] : 0000000000000000000000000000000000000000000000000000000000000007
Arg [8] : 6d4554482d4c5000000000000000000000000000000000000000000000000000
Arg [9] : 0000000000000000000000000000000000000000000000000000000000000006
Arg [10] : 532a6d4554480000000000000000000000000000000000000000000000000000
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ 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.