Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
Advanced mode: Intended for advanced users or developers and will display all Internal Transactions including zero value transfers.
Latest 6 internal transactions
Advanced mode:
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
PendleCrossChainSwapHub
Compiler Version
v0.8.30+commit.73712a01
Optimization Enabled:
Yes with 1000000 runs
Other Settings:
shanghai EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.30;
import {
IOFT,
MessagingFee,
MessagingReceipt,
OFTReceipt,
SendParam
} from "@layerzerolabs/oft-evm/contracts/interfaces/IOFT.sol";
import {PMath} from "../../core/libraries/math/PMath.sol";
import {ApprovedCall, IPDepositBox} from "../../interfaces/IPDepositBox.sol";
import {SwapData} from "./swap/IPSwapExecutor.sol";
import {SwapHubBase} from "./SwapHubBase.sol";
contract PendleCrossChainSwapHub is SwapHubBase {
constructor(address beaconProxyCodeContract_, address depositBoxBeacon_)
SwapHubBase(beaconProxyCodeContract_, depositBoxBeacon_)
{
_disableInitializers();
}
function initialize(address _owner) external initializer {
__EIP712_init("Pendle Cross Chain Swap Hub", "1");
__BoringOwnableV2_init(_owner);
}
function withdrawToken(WithdrawTokenMessage memory ms, bytes memory sig) external onlyExecutor {
_verifyOwnerSigAndNonce(ms.owner, ms.expiry, ms.nonce, hashTypedData(ms), sig);
IPDepositBox box = _checkAndDeployBox(ms.owner, ms.boxId);
box.withdrawTo(ms.receiver, ms.token, ms.withdrawAmount);
box.payTreasury(ms.token, ms.feeAmount);
emit WithdrawToken(ms.owner, ms.boxId, ms.receiver, ms.token, ms.withdrawAmount, ms.feeAmount);
}
function bridgeToken(BridgeTokenMessage memory ms, bytes memory sig) external payable onlyExecutor {
_verifyOwnerSigAndNonce(ms.owner, ms.expiry, ms.nonce, hashTypedData(ms), sig);
IPDepositBox box = _checkAndDeployBox(ms.owner, ms.boxId);
_bridgeToken(ms, box, msg.value);
box.payTreasury(ms.token, ms.feeAmount);
emit BridgeToken(ms.owner, ms.boxId, ms.bridgeExtRouter, ms.token, ms.bridgeAmount, ms.feeAmount);
}
function swapToken(SwapTokenMessage memory ms, bytes memory sig) external onlyExecutor {
_verifyOwnerSigAndNonce(ms.owner, ms.expiry, ms.nonce, hashTypedData(ms), sig);
IPDepositBox box = _checkAndDeployBox(ms.owner, ms.boxId);
uint256 netTokenReceived = _swapToken(ms, box) - ms.feeAmount;
box.payTreasury(ms.tokenReceived, ms.feeAmount);
require(netTokenReceived >= ms.minReceived, InsufficientTokenReceived());
emit SwapToken(ms.owner, ms.boxId, ms.tokenSpent, ms.amountSpent, ms.tokenReceived, netTokenReceived);
}
function buyCrossChainPt(
BuyCrossChainPtIntent memory intent,
bytes memory intentSig,
ExecuteBuyCrossChainPtMessage memory execMsg,
bytes memory execSig
) external payable onlyExecutor {
_verifyOwnerSig(intent.owner, intent.expiry, hashTypedData(intent), intentSig);
_verifyValidatorSig(execMsg.validator, execMsg.expiry, hashTypedData(execMsg), execSig);
bytes32 intentHash = keccak256(abi.encode(intent));
_verifyIntentHashAndMarkExecuted(execMsg.intentHash, intentHash);
IPDepositBox box = _checkAndDeployBox(intent.owner, intent.boxId);
uint256 netPtReceived = _buyPt(intent, execMsg, box) - execMsg.feeAmount;
box.payTreasury(intent.pt, execMsg.feeAmount);
if (intent.ptAdapter == address(0)) {
require(msg.value == 0, ExcessiveNativeFee());
} else {
netPtReceived = _bridgePt(intent, box, netPtReceived, msg.value);
}
require(netPtReceived >= intent.minPtReceived, InsufficientTokenReceived());
emit BuyCrossChainPt(
intent.owner,
intent.boxId,
intentHash,
intent.tokenSpent,
execMsg.amountSpent,
intent.pt,
intent.ptAdapter,
netPtReceived
);
}
function _bridgeToken(BridgeTokenMessage memory ms, IPDepositBox box, uint256 nativeFee) internal {
// forgefmt: disable-next-item
ApprovedCall memory call = ApprovedCall({
token: ms.token,
amount: ms.bridgeAmount,
spender: ms.bridgeExtRouter,
data: ms.bridgeCalldata
});
box.approveAndCall{value: nativeFee}(call, msg.sender);
}
function _swapToken(SwapTokenMessage memory ms, IPDepositBox box) internal returns (uint256 rawTokenReceived) {
SwapData memory swapData = SwapData({
tokenIn: ms.tokenSpent,
amountIn: ms.amountSpent,
tokenOut: ms.tokenReceived,
extRouter: ms.swapExtRouter,
extCalldata: ms.swapCalldata
});
rawTokenReceived = _swapFromBox(box, ms.swapExecutor, swapData);
}
function _buyPt(BuyCrossChainPtIntent memory intent, ExecuteBuyCrossChainPtMessage memory execMsg, IPDepositBox box)
internal
returns (uint256 rawPtReceived)
{
require(
execMsg.amountSpent <= PMath.min(intent.maxAmountSpent, _balanceOf(address(box), intent.tokenSpent)),
InvalidAmountIn()
);
SwapData memory swapData = SwapData({
tokenIn: intent.tokenSpent,
amountIn: execMsg.amountSpent,
tokenOut: intent.pt,
extRouter: execMsg.swapExtRouter,
extCalldata: execMsg.swapCalldata
});
rawPtReceived = _swapFromBox(box, execMsg.swapExecutor, swapData);
}
function _bridgePt(BuyCrossChainPtIntent memory intent, IPDepositBox box, uint256 amount, uint256 nativeFee)
internal
returns (uint256 netPtReceived)
{
SendParam memory sendParam = SendParam({
dstEid: intent.dstLzEid,
to: intent.receiver,
amountLD: amount,
minAmountLD: 0,
extraOptions: "",
composeMsg: "",
oftCmd: ""
});
MessagingFee memory sendFee = MessagingFee({nativeFee: nativeFee, lzTokenFee: 0});
ApprovedCall memory call = ApprovedCall({
token: intent.pt,
amount: amount,
spender: intent.ptAdapter,
data: abi.encodeCall(IOFT.send, (sendParam, sendFee, msg.sender))
});
(, OFTReceipt memory oftReceipt) =
abi.decode(box.approveAndCall{value: nativeFee}(call, msg.sender), (MessagingReceipt, OFTReceipt));
netPtReceived = oftReceipt.amountReceivedLD;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import { MessagingReceipt, MessagingFee } from "@layerzerolabs/oapp-evm/contracts/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 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);
error AmountSDOverflowed(uint256 amountSD);
// 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 the fee breakdown and settings data for an OFT. Unused in the default implementation.
* @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: GPL-3.0-or-later
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
pragma solidity ^0.8.0;
/* solhint-disable private-vars-leading-underscore, reason-string */
library PMath {
uint256 internal constant ONE = 1e18; // 18 decimal places
int256 internal constant IONE = 1e18; // 18 decimal places
function subMax0(uint256 a, uint256 b) internal pure returns (uint256) {
unchecked {
return (a >= b ? a - b : 0);
}
}
function subNoNeg(int256 a, int256 b) internal pure returns (int256) {
require(a >= b, "negative");
return a - b; // no unchecked since if b is very negative, a - b might overflow
}
function mulDown(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 product = a * b;
unchecked {
return product / ONE;
}
}
function mulDown(int256 a, int256 b) internal pure returns (int256) {
int256 product = a * b;
unchecked {
return product / IONE;
}
}
function divDown(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 aInflated = a * ONE;
unchecked {
return aInflated / b;
}
}
function divDown(int256 a, int256 b) internal pure returns (int256) {
int256 aInflated = a * IONE;
unchecked {
return aInflated / b;
}
}
function rawDivUp(uint256 a, uint256 b) internal pure returns (uint256) {
return (a + b - 1) / b;
}
function rawDivUp(int256 a, int256 b) internal pure returns (int256) {
return (a + b - 1) / b;
}
function tweakUp(uint256 a, uint256 factor) internal pure returns (uint256) {
return mulDown(a, ONE + factor);
}
function tweakDown(uint256 a, uint256 factor) internal pure returns (uint256) {
return mulDown(a, ONE - factor);
}
/// @return res = min(a + b, bound)
/// @dev This function should handle arithmetic operation and bound check without overflow/underflow
function addWithUpperBound(uint256 a, uint256 b, uint256 bound) internal pure returns (uint256 res) {
unchecked {
if (type(uint256).max - b < a) res = bound;
else res = min(bound, a + b);
}
}
/// @return res = max(a - b, bound)
/// @dev This function should handle arithmetic operation and bound check without overflow/underflow
function subWithLowerBound(uint256 a, uint256 b, uint256 bound) internal pure returns (uint256 res) {
unchecked {
if (b > a) res = bound;
else res = max(a - b, bound);
}
}
function clamp(uint256 x, uint256 lower, uint256 upper) internal pure returns (uint256 res) {
res = x;
if (x < lower) res = lower;
else if (x > upper) res = upper;
}
// @author Uniswap
function sqrt(uint256 y) internal pure returns (uint256 z) {
if (y > 3) {
z = y;
uint256 x = y / 2 + 1;
while (x < z) {
z = x;
x = (y / x + x) / 2;
}
} else if (y != 0) {
z = 1;
}
}
function square(uint256 x) internal pure returns (uint256) {
return x * x;
}
function squareDown(uint256 x) internal pure returns (uint256) {
return mulDown(x, x);
}
function abs(int256 x) internal pure returns (uint256) {
return uint256(x > 0 ? x : -x);
}
function neg(int256 x) internal pure returns (int256) {
return x * (-1);
}
function neg(uint256 x) internal pure returns (int256) {
return Int(x) * (-1);
}
function max(uint256 x, uint256 y) internal pure returns (uint256) {
return (x > y ? x : y);
}
function max(int256 x, int256 y) internal pure returns (int256) {
return (x > y ? x : y);
}
function min(uint256 x, uint256 y) internal pure returns (uint256) {
return (x < y ? x : y);
}
function min(int256 x, int256 y) internal pure returns (int256) {
return (x < y ? x : y);
}
/*///////////////////////////////////////////////////////////////
SIGNED CASTS
//////////////////////////////////////////////////////////////*/
function Int(uint256 x) internal pure returns (int256) {
require(x <= uint256(type(int256).max));
return int256(x);
}
function Int128(int256 x) internal pure returns (int128) {
require(type(int128).min <= x && x <= type(int128).max);
return int128(x);
}
function Int128(uint256 x) internal pure returns (int128) {
return Int128(Int(x));
}
/*///////////////////////////////////////////////////////////////
UNSIGNED CASTS
//////////////////////////////////////////////////////////////*/
function Uint(int256 x) internal pure returns (uint256) {
require(x >= 0);
return uint256(x);
}
function Uint32(uint256 x) internal pure returns (uint32) {
require(x <= type(uint32).max);
return uint32(x);
}
function Uint64(uint256 x) internal pure returns (uint64) {
require(x <= type(uint64).max);
return uint64(x);
}
function Uint112(uint256 x) internal pure returns (uint112) {
require(x <= type(uint112).max);
return uint112(x);
}
function Uint96(uint256 x) internal pure returns (uint96) {
require(x <= type(uint96).max);
return uint96(x);
}
function Uint128(uint256 x) internal pure returns (uint128) {
require(x <= type(uint128).max);
return uint128(x);
}
function Uint192(uint256 x) internal pure returns (uint192) {
require(x <= type(uint192).max);
return uint192(x);
}
function Uint80(uint256 x) internal pure returns (uint80) {
require(x <= type(uint80).max);
return uint80(x);
}
function isAApproxB(uint256 a, uint256 b, uint256 eps) internal pure returns (bool) {
return mulDown(b, ONE - eps) <= a && a <= mulDown(b, ONE + eps);
}
function isAGreaterApproxB(uint256 a, uint256 b, uint256 eps) internal pure returns (bool) {
return a >= b && a <= mulDown(b, ONE + eps);
}
function isASmallerApproxB(uint256 a, uint256 b, uint256 eps) internal pure returns (bool) {
return a <= b && a >= mulDown(b, ONE - eps);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
struct ApprovedCall {
address token;
uint256 amount;
address spender;
bytes data;
}
interface IPDepositBox {
function HUB() external view returns (address);
function TREASURY() external view returns (address);
function OWNER() external view returns (address);
function BOX_ID() external view returns (uint32);
function payTreasury(address token, uint256 amount) external;
function withdrawTo(address to, address token, uint256 amount) external;
function approveAndCall(ApprovedCall memory call, address nativeRefund) external payable returns (bytes memory);
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.0;
struct SwapData {
address tokenIn;
uint256 amountIn;
address tokenOut;
address extRouter;
bytes extCalldata;
}
interface IPSwapExecutor {
function swap(address receiver, SwapData memory swapData) external payable;
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.30;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {Create2} from "@openzeppelin/contracts/utils/Create2.sol";
import {SignatureChecker} from "@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol";
import {EIP712Upgradeable} from "@openzeppelin/contracts-upgradeable/utils/cryptography/EIP712Upgradeable.sol";
import {BoringOwnableUpgradeableV2} from "../../core/libraries/BoringOwnableUpgradeableV2.sol";
import {TokenHelper} from "../../core/libraries/TokenHelper.sol";
import {IPCrossChainSwapHub} from "../../interfaces/IPCrossChainSwapHub.sol";
import {IPDepositBox} from "../../interfaces/IPDepositBox.sol";
import {IPSwapExecutor, SwapData} from "./swap/IPSwapExecutor.sol";
import {DepositBox} from "./DepositBox.sol";
abstract contract SwapHubBase is IPCrossChainSwapHub, EIP712Upgradeable, BoringOwnableUpgradeableV2, TokenHelper {
// forgefmt: disable-next-item
bytes32 internal constant WITHDRAW_TOKEN_MESSAGE_TYPEHASH = keccak256(
"WithdrawTokenMessage("
"address owner,"
"uint32 boxId,"
"uint256 expiry,"
"uint256 nonce,"
//
"address receiver,"
"address token,"
"uint256 withdrawAmount,"
"uint256 feeAmount"
")"
);
// forgefmt: disable-next-item
bytes32 internal constant BRIDGE_TOKEN_MESSAGE_TYPEHASH = keccak256(
"BridgeTokenMessage("
"address owner,"
"uint32 boxId,"
"uint256 expiry,"
"uint256 nonce,"
//
"address token,"
"uint256 bridgeAmount,"
"uint256 feeAmount,"
//
"address bridgeExtRouter,"
"bytes bridgeCalldata"
")"
);
// forgefmt: disable-next-item
bytes32 internal constant SWAP_TOKEN_MESSAGE_TYPEHASH = keccak256(
"SwapTokenMessage("
"address owner,"
"uint32 boxId,"
"uint256 expiry,"
"uint256 nonce,"
//
"address tokenSpent,"
"uint256 amountSpent,"
"address tokenReceived,"
"uint256 minReceived,"
"uint256 feeAmount,"
//
"address swapExecutor,"
"address swapExtRouter,"
"bytes swapCalldata"
")"
);
// forgefmt: disable-next-item
bytes32 internal constant BUY_CROSS_CHAIN_PT_INTENT_TYPEHASH = keccak256(
"BuyCrossChainPtIntent("
"address owner,"
"uint32 boxId,"
"uint256 salt,"
"uint256 expiry,"
//
"address tokenSpent,"
"uint256 maxAmountSpent,"
"address pt,"
"address ptAdapter,"
"uint256 minPtReceived,"
"uint32 dstLzEid,"
"bytes32 receiver"
")"
);
// forgefmt: disable-next-item
bytes32 internal constant EXECUTE_BUY_CROSS_CHAIN_PT_MESSAGE_TYPEHASH = keccak256(
"ExecuteBuyCrossChainPtMessage("
"address validator,"
"bytes32 intentHash,"
"uint256 amountSpent,"
"uint256 feeAmount,"
"address swapExecutor,"
"address swapExtRouter,"
"bytes swapCalldata,"
"uint256 expiry"
")"
);
/// @dev creation code of OpenZeppelin's BeaconProxy
address public immutable BEACON_PROXY_CODE_CONTRACT;
address public immutable DEPOSIT_BOX_BEACON;
bytes32 public immutable DEPOSIT_BOX_CODE_HASH;
mapping(address owner => uint256 nonce) public ownerNonce;
mapping(bytes32 intentHash => bool) public isIntentExecuted;
mapping(address executor => bool) public isExecutor;
mapping(address validator => bool) public isValidator;
constructor(address beaconProxyCodeContract_, address depositBoxBeacon_) {
BEACON_PROXY_CODE_CONTRACT = beaconProxyCodeContract_;
DEPOSIT_BOX_BEACON = depositBoxBeacon_;
DEPOSIT_BOX_CODE_HASH =
keccak256(abi.encodePacked(beaconProxyCodeContract_.code, abi.encode(depositBoxBeacon_, "")));
}
modifier onlyExecutor() {
require(isExecutor[msg.sender], "SwapHub: caller is not executor");
_;
}
function setExecutor(address executor, bool isExecutor_) external onlyOwner {
isExecutor[executor] = isExecutor_;
emit SetExecutor(executor, isExecutor_);
}
function setValidator(address validator, bool isValidator_) external onlyOwner {
isValidator[validator] = isValidator_;
emit SetValidator(validator, isValidator_);
}
function computeDepositBox(address owner, uint32 boxId) public view returns (address box, bytes32 salt) {
salt = keccak256(abi.encode(owner, boxId));
box = Create2.computeAddress(salt, DEPOSIT_BOX_CODE_HASH);
}
function _checkAndDeployBox(address owner, uint32 boxId) internal returns (IPDepositBox) {
(address box, bytes32 salt) = computeDepositBox(owner, boxId);
if (box.code.length > 0) {
return IPDepositBox(box);
}
bytes memory bytecode = abi.encodePacked(BEACON_PROXY_CODE_CONTRACT.code, abi.encode(DEPOSIT_BOX_BEACON, ""));
assert(Create2.deploy(0, salt, bytecode) == box);
DepositBox(payable(box)).initialize(owner, boxId);
return IPDepositBox(box);
}
function hashTypedData(WithdrawTokenMessage memory message) public view returns (bytes32) {
return _hashTypedDataV4(
keccak256(
abi.encode(
WITHDRAW_TOKEN_MESSAGE_TYPEHASH,
message.owner,
message.boxId,
message.expiry,
message.nonce,
//
message.receiver,
message.token,
message.withdrawAmount,
message.feeAmount
)
)
);
}
function hashTypedData(BridgeTokenMessage memory message) public view returns (bytes32) {
return _hashTypedDataV4(
keccak256(
abi.encode(
BRIDGE_TOKEN_MESSAGE_TYPEHASH,
message.owner,
message.boxId,
message.expiry,
message.nonce,
//
message.token,
message.bridgeAmount,
message.feeAmount,
//
message.bridgeExtRouter,
keccak256(message.bridgeCalldata)
)
)
);
}
function hashTypedData(SwapTokenMessage memory message) public view returns (bytes32) {
return _hashTypedDataV4(
keccak256(
abi.encode(
SWAP_TOKEN_MESSAGE_TYPEHASH,
message.owner,
message.boxId,
message.expiry,
message.nonce,
//
message.tokenSpent,
message.amountSpent,
message.tokenReceived,
message.minReceived,
message.feeAmount,
//
message.swapExecutor,
message.swapExtRouter,
keccak256(message.swapCalldata)
)
)
);
}
function hashTypedData(BuyCrossChainPtIntent memory intent) public view returns (bytes32) {
return _hashTypedDataV4(
keccak256(
abi.encode(
BUY_CROSS_CHAIN_PT_INTENT_TYPEHASH,
intent.owner,
intent.boxId,
intent.salt,
intent.expiry,
//
intent.tokenSpent,
intent.maxAmountSpent,
intent.pt,
intent.ptAdapter,
intent.minPtReceived,
intent.dstLzEid,
intent.receiver
)
)
);
}
function hashTypedData(ExecuteBuyCrossChainPtMessage memory message) public view returns (bytes32) {
return _hashTypedDataV4(
keccak256(
abi.encode(
EXECUTE_BUY_CROSS_CHAIN_PT_MESSAGE_TYPEHASH,
message.validator,
message.intentHash,
message.amountSpent,
message.feeAmount,
message.swapExecutor,
message.swapExtRouter,
keccak256(message.swapCalldata),
message.expiry
)
)
);
}
function _verifyOwnerSigAndNonce(
address owner,
uint256 expiry,
uint256 nonce,
bytes32 messageHash,
bytes memory signature
) internal {
_verifyOwnerSig(owner, expiry, messageHash, signature);
_verifyAndIncreaseNonce(owner, nonce);
}
function _verifyOwnerSig(address owner, uint256 expiry, bytes32 messageHash, bytes memory signature) internal view {
require(SignatureChecker.isValidSignatureNow(owner, messageHash, signature), InvalidSignature());
require(expiry > block.timestamp, MessageExpired());
}
function _verifyAndIncreaseNonce(address owner, uint256 nonce) internal {
require(ownerNonce[owner] < nonce, InvalidNonce());
ownerNonce[owner] = nonce;
}
function _verifyValidatorSig(address validator, uint256 expiry, bytes32 messageHash, bytes memory signature)
internal
view
{
require(SignatureChecker.isValidSignatureNow(validator, messageHash, signature), InvalidSignature());
require(isValidator[validator], InvalidValidator());
require(expiry > block.timestamp, MessageExpired());
}
function _verifyIntentHashAndMarkExecuted(bytes32 expectedHash, bytes32 actualHash) internal {
require(expectedHash == actualHash, IntentHashMismatch());
require(!isIntentExecuted[actualHash], IntentExecuted());
isIntentExecuted[actualHash] = true;
}
function _balanceOf(address addr, address token) internal view returns (uint256) {
return (token == NATIVE) ? addr.balance : IERC20(token).balanceOf(addr);
}
function _swapFromBox(IPDepositBox box, address swapExecutor, SwapData memory swapData)
internal
returns (uint256 rawTokenOut)
{
box.withdrawTo(swapExecutor, swapData.tokenIn, swapData.amountIn);
uint256 preBalance = _balanceOf(address(box), swapData.tokenOut);
IPSwapExecutor(swapExecutor).swap(address(box), swapData);
rawTokenOut = _balanceOf(address(box), swapData.tokenOut) - preBalance;
}
}// 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
// 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.0) (utils/Create2.sol)
pragma solidity ^0.8.0;
/**
* @dev Helper to make usage of the `CREATE2` EVM opcode easier and safer.
* `CREATE2` can be used to compute in advance the address where a smart
* contract will be deployed, which allows for interesting new mechanisms known
* as 'counterfactual interactions'.
*
* See the https://eips.ethereum.org/EIPS/eip-1014#motivation[EIP] for more
* information.
*/
library Create2 {
/**
* @dev Deploys a contract using `CREATE2`. The address where the contract
* will be deployed can be known in advance via {computeAddress}.
*
* The bytecode for a contract can be obtained from Solidity with
* `type(contractName).creationCode`.
*
* Requirements:
*
* - `bytecode` must not be empty.
* - `salt` must have not been used for `bytecode` already.
* - the factory must have a balance of at least `amount`.
* - if `amount` is non-zero, `bytecode` must have a `payable` constructor.
*/
function deploy(uint256 amount, bytes32 salt, bytes memory bytecode) internal returns (address addr) {
require(address(this).balance >= amount, "Create2: insufficient balance");
require(bytecode.length != 0, "Create2: bytecode length is zero");
/// @solidity memory-safe-assembly
assembly {
addr := create2(amount, add(bytecode, 0x20), mload(bytecode), salt)
}
require(addr != address(0), "Create2: Failed on deploy");
}
/**
* @dev Returns the address where a contract will be stored if deployed via {deploy}. Any change in the
* `bytecodeHash` or `salt` will result in a new destination address.
*/
function computeAddress(bytes32 salt, bytes32 bytecodeHash) internal view returns (address) {
return computeAddress(salt, bytecodeHash, address(this));
}
/**
* @dev Returns the address where a contract will be stored if deployed via {deploy} from a contract located at
* `deployer`. If `deployer` is this contract's address, returns the same value as {computeAddress}.
*/
function computeAddress(bytes32 salt, bytes32 bytecodeHash, address deployer) internal pure returns (address addr) {
/// @solidity memory-safe-assembly
assembly {
let ptr := mload(0x40) // Get free memory pointer
// | | ↓ ptr ... ↓ ptr + 0x0B (start) ... ↓ ptr + 0x20 ... ↓ ptr + 0x40 ... |
// |-------------------|---------------------------------------------------------------------------|
// | bytecodeHash | CCCCCCCCCCCCC...CC |
// | salt | BBBBBBBBBBBBB...BB |
// | deployer | 000000...0000AAAAAAAAAAAAAAAAAAA...AA |
// | 0xFF | FF |
// |-------------------|---------------------------------------------------------------------------|
// | memory | 000000...00FFAAAAAAAAAAAAAAAAAAA...AABBBBBBBBBBBBB...BBCCCCCCCCCCCCC...CC |
// | keccak(start, 85) | ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ |
mstore(add(ptr, 0x40), bytecodeHash)
mstore(add(ptr, 0x20), salt)
mstore(ptr, deployer) // Right-aligned with 12 preceding garbage bytes
let start := add(ptr, 0x0b) // The hashed data starts at the final garbage byte which we will set to 0xff
mstore8(start, 0xff)
addr := keccak256(start, 85)
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/SignatureChecker.sol)
pragma solidity ^0.8.0;
import "./ECDSA.sol";
import "../../interfaces/IERC1271.sol";
/**
* @dev Signature verification helper that can be used instead of `ECDSA.recover` to seamlessly support both ECDSA
* signatures from externally owned accounts (EOAs) as well as ERC1271 signatures from smart contract wallets like
* Argent and Gnosis Safe.
*
* _Available since v4.1._
*/
library SignatureChecker {
/**
* @dev Checks if a signature is valid for a given signer and data hash. If the signer is a smart contract, the
* signature is validated against that smart contract using ERC1271, otherwise it's validated using `ECDSA.recover`.
*
* NOTE: Unlike ECDSA signatures, contract signatures are revocable, and the outcome of this function can thus
* change through time. It could return true at block N and false at block N+1 (or the opposite).
*/
function isValidSignatureNow(address signer, bytes32 hash, bytes memory signature) internal view returns (bool) {
(address recovered, ECDSA.RecoverError error) = ECDSA.tryRecover(hash, signature);
return
(error == ECDSA.RecoverError.NoError && recovered == signer) ||
isValidERC1271SignatureNow(signer, hash, signature);
}
/**
* @dev Checks if a signature is valid for a given signer and data hash. The signature is validated
* against the signer smart contract using ERC1271.
*
* NOTE: Unlike ECDSA signatures, contract signatures are revocable, and the outcome of this function can thus
* change through time. It could return true at block N and false at block N+1 (or the opposite).
*/
function isValidERC1271SignatureNow(
address signer,
bytes32 hash,
bytes memory signature
) internal view returns (bool) {
(bool success, bytes memory result) = signer.staticcall(
abi.encodeWithSelector(IERC1271.isValidSignature.selector, hash, signature)
);
return (success &&
result.length >= 32 &&
abi.decode(result, (bytes32)) == bytes32(IERC1271.isValidSignature.selector));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/EIP712.sol)
pragma solidity ^0.8.8;
import "./ECDSAUpgradeable.sol";
import "../../interfaces/IERC5267Upgradeable.sol";
import "../../proxy/utils/Initializable.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:storage-size 52
*/
abstract contract EIP712Upgradeable is Initializable, IERC5267Upgradeable {
bytes32 private constant _TYPE_HASH =
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");
/// @custom:oz-renamed-from _HASHED_NAME
bytes32 private _hashedName;
/// @custom:oz-renamed-from _HASHED_VERSION
bytes32 private _hashedVersion;
string private _name;
string private _version;
/**
* @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].
*/
function __EIP712_init(string memory name, string memory version) internal onlyInitializing {
__EIP712_init_unchained(name, version);
}
function __EIP712_init_unchained(string memory name, string memory version) internal onlyInitializing {
_name = name;
_version = version;
// Reset prior values in storage if upgrading
_hashedName = 0;
_hashedVersion = 0;
}
/**
* @dev Returns the domain separator for the current chain.
*/
function _domainSeparatorV4() internal view returns (bytes32) {
return _buildDomainSeparator();
}
function _buildDomainSeparator() private view returns (bytes32) {
return keccak256(abi.encode(_TYPE_HASH, _EIP712NameHash(), _EIP712VersionHash(), 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 ECDSAUpgradeable.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
)
{
// If the hashed name and version in storage are non-zero, the contract hasn't been properly initialized
// and the EIP712 domain is not reliable, as it will be missing name and version.
require(_hashedName == 0 && _hashedVersion == 0, "EIP712: Uninitialized");
return (
hex"0f", // 01111
_EIP712Name(),
_EIP712Version(),
block.chainid,
address(this),
bytes32(0),
new uint256[](0)
);
}
/**
* @dev The name parameter for the EIP712 domain.
*
* NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs
* are a concern.
*/
function _EIP712Name() internal virtual view returns (string memory) {
return _name;
}
/**
* @dev The version parameter for the EIP712 domain.
*
* NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs
* are a concern.
*/
function _EIP712Version() internal virtual view returns (string memory) {
return _version;
}
/**
* @dev The hash of the name parameter for the EIP712 domain.
*
* NOTE: In previous versions this function was virtual. In this version you should override `_EIP712Name` instead.
*/
function _EIP712NameHash() internal view returns (bytes32) {
string memory name = _EIP712Name();
if (bytes(name).length > 0) {
return keccak256(bytes(name));
} else {
// If the name is empty, the contract may have been upgraded without initializing the new storage.
// We return the name hash in storage if non-zero, otherwise we assume the name is empty by design.
bytes32 hashedName = _hashedName;
if (hashedName != 0) {
return hashedName;
} else {
return keccak256("");
}
}
}
/**
* @dev The hash of the version parameter for the EIP712 domain.
*
* NOTE: In previous versions this function was virtual. In this version you should override `_EIP712Version` instead.
*/
function _EIP712VersionHash() internal view returns (bytes32) {
string memory version = _EIP712Version();
if (bytes(version).length > 0) {
return keccak256(bytes(version));
} else {
// If the version is empty, the contract may have been upgraded without initializing the new storage.
// We return the version hash in storage if non-zero, otherwise we assume the version is empty by design.
bytes32 hashedVersion = _hashedVersion;
if (hashedVersion != 0) {
return hashedVersion;
} else {
return keccak256("");
}
}
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[48] private __gap;
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.0;
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
contract BoringOwnableUpgradeableData {
address public owner;
address public pendingOwner;
}
abstract contract BoringOwnableUpgradeableV2 is BoringOwnableUpgradeableData, Initializable {
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
function __BoringOwnableV2_init(address _owner) internal onlyInitializing {
owner = _owner;
}
/// @notice Transfers ownership to `newOwner`. Either directly or claimable by the new pending owner.
/// Can only be invoked by the current `owner`.
/// @param newOwner Address of the new owner.
/// @param direct True if `newOwner` should be set immediately. False if `newOwner` needs to use `claimOwnership`.
/// @param renounce Allows the `newOwner` to be `address(0)` if `direct` and `renounce` is True. Has no effect
/// otherwise.
function transferOwnership(address newOwner, bool direct, bool renounce) public onlyOwner {
if (direct) {
// Checks
require(newOwner != address(0) || renounce, "Ownable: zero address");
// Effects
emit OwnershipTransferred(owner, newOwner);
owner = newOwner;
pendingOwner = address(0);
} else {
// Effects
pendingOwner = newOwner;
}
}
/// @notice Needs to be called by `pendingOwner` to claim ownership.
function claimOwnership() public {
address _pendingOwner = pendingOwner;
// Checks
require(msg.sender == _pendingOwner, "Ownable: caller != pending owner");
// Effects
emit OwnershipTransferred(owner, _pendingOwner);
owner = _pendingOwner;
pendingOwner = address(0);
}
/// @notice Only allows the `owner` to execute the function.
modifier onlyOwner() {
require(msg.sender == owner, "Ownable: caller is not the owner");
_;
}
uint256[48] private __gap;
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.0;
import "../../interfaces/IWETH.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
abstract contract TokenHelper {
using SafeERC20 for IERC20;
address internal constant NATIVE = address(0);
uint256 internal constant LOWER_BOUND_APPROVAL = type(uint96).max / 2; // some tokens use 96 bits for approval
function _transferIn(address token, address from, uint256 amount) internal {
if (token == NATIVE) require(msg.value == amount, "eth mismatch");
else if (amount != 0) IERC20(token).safeTransferFrom(from, address(this), amount);
}
function _transferFrom(IERC20 token, address from, address to, uint256 amount) internal {
if (amount != 0) token.safeTransferFrom(from, to, amount);
}
function _transferOut(address token, address to, uint256 amount) internal {
if (amount == 0) return;
if (token == NATIVE) {
(bool success,) = to.call{value: amount}("");
require(success, "eth send failed");
} else {
IERC20(token).safeTransfer(to, amount);
}
}
function _transferOut(address[] memory tokens, address to, uint256[] memory amounts) internal {
uint256 numTokens = tokens.length;
require(numTokens == amounts.length, "length mismatch");
for (uint256 i = 0; i < numTokens;) {
_transferOut(tokens[i], to, amounts[i]);
unchecked {
i++;
}
}
}
function _selfBalance(address token) internal view returns (uint256) {
return (token == NATIVE) ? address(this).balance : IERC20(token).balanceOf(address(this));
}
function _selfBalance(IERC20 token) internal view returns (uint256) {
return token.balanceOf(address(this));
}
/// @notice Approves the stipulated contract to spend the given allowance in the given token
/// @dev PLS PAY ATTENTION to tokens that requires the approval to be set to 0 before changing it
function _safeApprove(address token, address to, uint256 value) internal {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.approve.selector, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), "Safe Approve");
}
function _safeApproveInf(address token, address to) internal {
if (token == NATIVE) return;
if (IERC20(token).allowance(address(this), to) < LOWER_BOUND_APPROVAL) {
_safeApprove(token, to, 0);
_safeApprove(token, to, type(uint256).max);
}
}
function _wrap_unwrap_ETH(address tokenIn, address tokenOut, uint256 netTokenIn) internal {
if (tokenIn == NATIVE) IWETH(tokenOut).deposit{value: netTokenIn}();
else IWETH(tokenIn).withdraw(netTokenIn);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IPCrossChainSwapHub {
error ExcessiveNativeFee();
error InsufficientTokenReceived();
error InvalidAmountIn();
error InvalidNonce();
error InvalidSignature();
error InvalidValidator();
error IntentExecuted();
error IntentHashMismatch();
error MessageExpired();
struct WithdrawTokenMessage {
address owner;
uint32 boxId;
uint256 expiry;
uint256 nonce;
//
address receiver;
address token;
uint256 withdrawAmount;
uint256 feeAmount;
}
struct BridgeTokenMessage {
address owner;
uint32 boxId;
uint256 expiry;
uint256 nonce;
//
address token;
uint256 bridgeAmount;
uint256 feeAmount;
//
address bridgeExtRouter;
bytes bridgeCalldata;
}
struct SwapTokenMessage {
address owner;
uint32 boxId;
uint256 expiry;
uint256 nonce;
//
address tokenSpent;
uint256 amountSpent;
address tokenReceived;
uint256 minReceived;
uint256 feeAmount;
//
address swapExecutor;
address swapExtRouter;
bytes swapCalldata;
}
struct BuyCrossChainPtIntent {
address owner;
uint32 boxId;
uint256 salt;
uint256 expiry;
//
address tokenSpent;
uint256 maxAmountSpent;
address pt;
address ptAdapter;
uint256 minPtReceived;
uint32 dstLzEid;
bytes32 receiver;
}
struct ExecuteBuyCrossChainPtMessage {
address validator;
bytes32 intentHash;
uint256 amountSpent;
uint256 feeAmount;
address swapExecutor;
address swapExtRouter;
bytes swapCalldata;
uint256 expiry;
}
event WithdrawToken(
address indexed owner, uint32 boxId, address receiver, address token, uint256 withdrawAmount, uint256 feeAmount
);
event BridgeToken(
address indexed owner,
uint32 boxId,
address bridgeExtRouter,
address token,
uint256 bridgeAmount,
uint256 feeAmount
);
event SwapToken(
address indexed owner,
uint32 boxId,
address tokenSpent,
uint256 amountSpent,
address tokenReceived,
uint256 netTokenReceived
);
event BuyCrossChainPt(
address indexed owner,
uint32 boxId,
bytes32 intentHash,
address tokenSpent,
uint256 amountSpent,
address pt,
address ptAdapter,
uint256 netPtReceived
);
event SetExecutor(address indexed executor, bool isExecutor);
event SetValidator(address indexed validator, bool isValidator);
function BEACON_PROXY_CODE_CONTRACT() external view returns (address);
function DEPOSIT_BOX_BEACON() external view returns (address);
function DEPOSIT_BOX_CODE_HASH() external view returns (bytes32);
function ownerNonce(address owner) external view returns (uint256);
function isIntentExecuted(bytes32 intentHash) external view returns (bool);
function isExecutor(address executor) external view returns (bool);
function isValidator(address validator) external view returns (bool);
function computeDepositBox(address owner, uint32 boxId) external view returns (address box, bytes32 salt);
function hashTypedData(WithdrawTokenMessage memory message) external view returns (bytes32);
function hashTypedData(BridgeTokenMessage memory message) external view returns (bytes32);
function hashTypedData(SwapTokenMessage memory message) external view returns (bytes32);
function hashTypedData(BuyCrossChainPtIntent memory intent) external view returns (bytes32);
function hashTypedData(ExecuteBuyCrossChainPtMessage memory message) external view returns (bytes32);
function withdrawToken(WithdrawTokenMessage memory message, bytes memory signature) external;
function bridgeToken(BridgeTokenMessage memory message, bytes memory signature) external payable;
function swapToken(SwapTokenMessage memory message, bytes memory signature) external;
function buyCrossChainPt(
BuyCrossChainPtIntent memory intent,
bytes memory intentSig,
ExecuteBuyCrossChainPtMessage memory execMsg,
bytes memory execSig
) external payable;
function setExecutor(address executor, bool isExecutor) external;
function setValidator(address validator, bool isValidator) external;
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.30;
import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {Address} from "@openzeppelin/contracts/utils/Address.sol";
import {TokenHelper} from "../../core/libraries/TokenHelper.sol";
import {ApprovedCall, IPDepositBox} from "../../interfaces/IPDepositBox.sol";
contract DepositBox is IPDepositBox, TokenHelper, Initializable {
using Address for address;
using SafeERC20 for IERC20;
address public immutable HUB;
address public immutable TREASURY;
address public OWNER;
uint32 public BOX_ID;
constructor(address hub_, address treasury_) {
_disableInitializers();
HUB = hub_;
TREASURY = treasury_;
}
modifier onlyHub() {
require(msg.sender == HUB, "DepositBox: caller is not hub");
_;
}
function initialize(address owner_, uint32 boxId_) external initializer onlyHub {
OWNER = owner_;
BOX_ID = boxId_;
}
function payTreasury(address token, uint256 amount) external onlyHub {
_transferOut(token, TREASURY, amount);
}
function withdrawTo(address to, address token, uint256 amount) external onlyHub {
_transferOut(token, to, amount);
}
function approveAndCall(ApprovedCall memory call, address nativeRefund)
external
payable
onlyHub
returns (bytes memory result)
{
uint256 nativeAmount = call.token == NATIVE ? call.amount : 0;
uint256 nativeFee = msg.value;
uint256 initialNativeBalance = _selfBalance(NATIVE) - nativeAmount - nativeFee;
_approveForExtRouter(call.token, call.spender, call.amount);
result = call.spender.functionCallWithValue(call.data, nativeAmount + nativeFee);
_approveForExtRouter(call.token, call.spender, 0);
uint256 finalNativeBalance = _selfBalance(NATIVE);
if (finalNativeBalance > initialNativeBalance) {
_transferOut(NATIVE, nativeRefund, finalNativeBalance - initialNativeBalance);
}
}
function _approveForExtRouter(address token, address extRouter, uint256 amount) internal {
if (token == NATIVE) return;
IERC20(token).forceApprove(extRouter, amount);
}
receive() external payable {}
}// 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
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;
}
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);
event DelegateSet(address sender, address delegate);
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) external view returns (bool);
function initializable(Origin calldata _origin, address _receiver) external view returns (bool);
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.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
// 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 v4.4.1 (interfaces/IERC1271.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC1271 standard signature validation method for
* contracts as defined in https://eips.ethereum.org/EIPS/eip-1271[ERC-1271].
*
* _Available since v4.1._
*/
interface IERC1271 {
/**
* @dev Should return whether the signature provided is valid for the provided data
* @param hash Hash of the data to be signed
* @param signature Signature byte array associated with _data
*/
function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/ECDSA.sol)
pragma solidity ^0.8.0;
import "../StringsUpgradeable.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 ECDSAUpgradeable {
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", StringsUpgradeable.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) (interfaces/IERC5267.sol)
pragma solidity ^0.8.0;
interface IERC5267Upgradeable {
/**
* @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) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.2;
import "../../utils/AddressUpgradeable.sol";
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Indicates that the contract has been initialized.
* @custom:oz-retyped-from bool
*/
uint8 private _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private _initializing;
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint8 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
* constructor.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
bool isTopLevelCall = !_initializing;
require(
(isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
"Initializable: contract is already initialized"
);
_initialized = 1;
if (isTopLevelCall) {
_initializing = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: setting the version to 255 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint8 version) {
require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
_initialized = version;
_initializing = true;
_;
_initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
require(_initializing, "Initializable: contract is not initializing");
_;
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
require(!_initializing, "Initializable: contract is initializing");
if (_initialized != type(uint8).max) {
_initialized = type(uint8).max;
emit Initialized(type(uint8).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint8) {
return _initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _initializing;
}
}// SPDX-License-Identifier: GPL-3.0-or-later
/*
* MIT License
* ===========
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
*/
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IWETH is IERC20 {
event Deposit(address indexed dst, uint256 wad);
event Withdrawal(address indexed src, uint256 wad);
function deposit() external payable;
function withdraw(uint256 wad) external;
}// 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.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.2;
import "../../utils/Address.sol";
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Indicates that the contract has been initialized.
* @custom:oz-retyped-from bool
*/
uint8 private _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private _initializing;
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint8 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
* constructor.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
bool isTopLevelCall = !_initializing;
require(
(isTopLevelCall && _initialized < 1) || (!Address.isContract(address(this)) && _initialized == 1),
"Initializable: contract is already initialized"
);
_initialized = 1;
if (isTopLevelCall) {
_initializing = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: setting the version to 255 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint8 version) {
require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
_initialized = version;
_initializing = true;
_;
_initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
require(_initializing, "Initializable: contract is not initializing");
_;
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
require(!_initializing, "Initializable: contract is initializing");
if (_initialized != type(uint8).max) {
_initialized = type(uint8).max;
emit Initialized(type(uint8).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint8) {
return _initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _initializing;
}
}// 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.0) (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.
*/
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].
*/
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
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 newLib);
event DefaultReceiveLibraryTimeoutSet(uint32 eid, address oldLib, uint256 expiry);
event SendLibrarySet(address sender, uint32 eid, address newLib);
event ReceiveLibrarySet(address receiver, uint32 eid, 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 _gracePeriod) 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);
function isValidReceiveLibrary(address _receiver, uint32 _eid, address _lib) 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 _expiry) 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 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 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);
function lazyInboundNonce(address _receiver, uint32 _srcEid, bytes32 _sender) external view returns (uint64);
}// 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
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
// 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/Strings.sol)
pragma solidity ^0.8.0;
import "./math/MathUpgradeable.sol";
import "./math/SignedMathUpgradeable.sol";
/**
* @dev String operations.
*/
library StringsUpgradeable {
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 = MathUpgradeable.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(SignedMathUpgradeable.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, MathUpgradeable.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/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library AddressUpgradeable {
/**
* @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 v4.4.1 (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;
}
}// 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/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: 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 MathUpgradeable {
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/SignedMath.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard signed math utilities missing in the Solidity language.
*/
library SignedMathUpgradeable {
/**
* @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);
}
}
}{
"remappings": [
"lib/pendle-core-v3/:@openzeppelin/contracts/=node_modules/@openzeppelin-v5/contracts/",
"lib/pendle-core-v3/:@openzeppelin/contracts-upgradeable/=node_modules/@openzeppelin-v5/contracts-upgradeable/",
"node_modules/@layerzerolabs/test-devtools-evm-foundry/:forge-std/=node_modules/forge-std/src/",
"node_modules/@layerzerolabs/oapp-evm/:@openzeppelin/=node_modules/@openzeppelin/",
"node_modules/@layerzerolabs/oft-evm/:@openzeppelin/=node_modules/@openzeppelin/",
"node_modules/@layerzerolabs/:@openzeppelin/=node_modules/@openzeppelin-v5/",
"@axelar-network/=node_modules/@axelar-network/",
"@chainlink/=node_modules/@chainlink/",
"@openzeppelin/contracts/=node_modules/@openzeppelin/contracts/",
"@openzeppelin/contracts-upgradeable/=node_modules/@openzeppelin/contracts-upgradeable/",
"@openzeppelin-v5/contracts/=node_modules/@openzeppelin-v5/contracts/",
"@openzeppelin-v5/contracts-upgradeable/=node_modules/@openzeppelin-v5/contracts-upgradeable/",
"@eth-optimism/=node_modules/@eth-optimism/",
"@prb/test/=node_modules/@prb/test/",
"forge-std/=node_modules/forge-std/",
"@pendle/core-v2/=lib/pendle-core-v2/",
"@pendle/core-v3/=lib/pendle-core-v3/",
"@pendle/sy/=lib/pendle-sy/",
"pendle-sy/=lib/pendle-sy/contracts/",
"hardhat-deploy/=node_modules/hardhat-deploy/",
"ds-test/=lib/surl/lib/forge-std/lib/ds-test/src/",
"solidity-bytes-utils/=node_modules/solidity-bytes-utils/",
"solidity-stringutils/=lib/surl/lib/solidity-stringutils/src/",
"surl/=lib/surl/src/",
"@layerzerolabs/=node_modules/@layerzerolabs/",
"pendle-core-v2/=lib/pendle-core-v2/contracts/",
"pendle-core-v3/=lib/pendle-core-v3/contracts/",
"hardhat/=lib/pendle-core-v2/node_modules/hardhat/"
],
"optimizer": {
"enabled": true,
"runs": 1000000
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "shanghai",
"viaIR": true
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"beaconProxyCodeContract_","type":"address"},{"internalType":"address","name":"depositBoxBeacon_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ExcessiveNativeFee","type":"error"},{"inputs":[],"name":"InsufficientTokenReceived","type":"error"},{"inputs":[],"name":"IntentExecuted","type":"error"},{"inputs":[],"name":"IntentHashMismatch","type":"error"},{"inputs":[],"name":"InvalidAmountIn","type":"error"},{"inputs":[],"name":"InvalidNonce","type":"error"},{"inputs":[],"name":"InvalidSignature","type":"error"},{"inputs":[],"name":"InvalidValidator","type":"error"},{"inputs":[],"name":"MessageExpired","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint32","name":"boxId","type":"uint32"},{"indexed":false,"internalType":"address","name":"bridgeExtRouter","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"bridgeAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"feeAmount","type":"uint256"}],"name":"BridgeToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint32","name":"boxId","type":"uint32"},{"indexed":false,"internalType":"bytes32","name":"intentHash","type":"bytes32"},{"indexed":false,"internalType":"address","name":"tokenSpent","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountSpent","type":"uint256"},{"indexed":false,"internalType":"address","name":"pt","type":"address"},{"indexed":false,"internalType":"address","name":"ptAdapter","type":"address"},{"indexed":false,"internalType":"uint256","name":"netPtReceived","type":"uint256"}],"name":"BuyCrossChainPt","type":"event"},{"anonymous":false,"inputs":[],"name":"EIP712DomainChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"executor","type":"address"},{"indexed":false,"internalType":"bool","name":"isExecutor","type":"bool"}],"name":"SetExecutor","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"validator","type":"address"},{"indexed":false,"internalType":"bool","name":"isValidator","type":"bool"}],"name":"SetValidator","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint32","name":"boxId","type":"uint32"},{"indexed":false,"internalType":"address","name":"tokenSpent","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountSpent","type":"uint256"},{"indexed":false,"internalType":"address","name":"tokenReceived","type":"address"},{"indexed":false,"internalType":"uint256","name":"netTokenReceived","type":"uint256"}],"name":"SwapToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint32","name":"boxId","type":"uint32"},{"indexed":false,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"withdrawAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"feeAmount","type":"uint256"}],"name":"WithdrawToken","type":"event"},{"inputs":[],"name":"BEACON_PROXY_CODE_CONTRACT","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEPOSIT_BOX_BEACON","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEPOSIT_BOX_CODE_HASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint32","name":"boxId","type":"uint32"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"bridgeAmount","type":"uint256"},{"internalType":"uint256","name":"feeAmount","type":"uint256"},{"internalType":"address","name":"bridgeExtRouter","type":"address"},{"internalType":"bytes","name":"bridgeCalldata","type":"bytes"}],"internalType":"struct IPCrossChainSwapHub.BridgeTokenMessage","name":"ms","type":"tuple"},{"internalType":"bytes","name":"sig","type":"bytes"}],"name":"bridgeToken","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint32","name":"boxId","type":"uint32"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"address","name":"tokenSpent","type":"address"},{"internalType":"uint256","name":"maxAmountSpent","type":"uint256"},{"internalType":"address","name":"pt","type":"address"},{"internalType":"address","name":"ptAdapter","type":"address"},{"internalType":"uint256","name":"minPtReceived","type":"uint256"},{"internalType":"uint32","name":"dstLzEid","type":"uint32"},{"internalType":"bytes32","name":"receiver","type":"bytes32"}],"internalType":"struct IPCrossChainSwapHub.BuyCrossChainPtIntent","name":"intent","type":"tuple"},{"internalType":"bytes","name":"intentSig","type":"bytes"},{"components":[{"internalType":"address","name":"validator","type":"address"},{"internalType":"bytes32","name":"intentHash","type":"bytes32"},{"internalType":"uint256","name":"amountSpent","type":"uint256"},{"internalType":"uint256","name":"feeAmount","type":"uint256"},{"internalType":"address","name":"swapExecutor","type":"address"},{"internalType":"address","name":"swapExtRouter","type":"address"},{"internalType":"bytes","name":"swapCalldata","type":"bytes"},{"internalType":"uint256","name":"expiry","type":"uint256"}],"internalType":"struct IPCrossChainSwapHub.ExecuteBuyCrossChainPtMessage","name":"execMsg","type":"tuple"},{"internalType":"bytes","name":"execSig","type":"bytes"}],"name":"buyCrossChainPt","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"claimOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint32","name":"boxId","type":"uint32"}],"name":"computeDepositBox","outputs":[{"internalType":"address","name":"box","type":"address"},{"internalType":"bytes32","name":"salt","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"eip712Domain","outputs":[{"internalType":"bytes1","name":"fields","type":"bytes1"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"version","type":"string"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"verifyingContract","type":"address"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint256[]","name":"extensions","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint32","name":"boxId","type":"uint32"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"tokenSpent","type":"address"},{"internalType":"uint256","name":"amountSpent","type":"uint256"},{"internalType":"address","name":"tokenReceived","type":"address"},{"internalType":"uint256","name":"minReceived","type":"uint256"},{"internalType":"uint256","name":"feeAmount","type":"uint256"},{"internalType":"address","name":"swapExecutor","type":"address"},{"internalType":"address","name":"swapExtRouter","type":"address"},{"internalType":"bytes","name":"swapCalldata","type":"bytes"}],"internalType":"struct IPCrossChainSwapHub.SwapTokenMessage","name":"message","type":"tuple"}],"name":"hashTypedData","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"validator","type":"address"},{"internalType":"bytes32","name":"intentHash","type":"bytes32"},{"internalType":"uint256","name":"amountSpent","type":"uint256"},{"internalType":"uint256","name":"feeAmount","type":"uint256"},{"internalType":"address","name":"swapExecutor","type":"address"},{"internalType":"address","name":"swapExtRouter","type":"address"},{"internalType":"bytes","name":"swapCalldata","type":"bytes"},{"internalType":"uint256","name":"expiry","type":"uint256"}],"internalType":"struct IPCrossChainSwapHub.ExecuteBuyCrossChainPtMessage","name":"message","type":"tuple"}],"name":"hashTypedData","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint32","name":"boxId","type":"uint32"},{"internalType":"uint256","name":"salt","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"address","name":"tokenSpent","type":"address"},{"internalType":"uint256","name":"maxAmountSpent","type":"uint256"},{"internalType":"address","name":"pt","type":"address"},{"internalType":"address","name":"ptAdapter","type":"address"},{"internalType":"uint256","name":"minPtReceived","type":"uint256"},{"internalType":"uint32","name":"dstLzEid","type":"uint32"},{"internalType":"bytes32","name":"receiver","type":"bytes32"}],"internalType":"struct IPCrossChainSwapHub.BuyCrossChainPtIntent","name":"intent","type":"tuple"}],"name":"hashTypedData","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint32","name":"boxId","type":"uint32"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"bridgeAmount","type":"uint256"},{"internalType":"uint256","name":"feeAmount","type":"uint256"},{"internalType":"address","name":"bridgeExtRouter","type":"address"},{"internalType":"bytes","name":"bridgeCalldata","type":"bytes"}],"internalType":"struct IPCrossChainSwapHub.BridgeTokenMessage","name":"message","type":"tuple"}],"name":"hashTypedData","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint32","name":"boxId","type":"uint32"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"withdrawAmount","type":"uint256"},{"internalType":"uint256","name":"feeAmount","type":"uint256"}],"internalType":"struct IPCrossChainSwapHub.WithdrawTokenMessage","name":"message","type":"tuple"}],"name":"hashTypedData","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"executor","type":"address"}],"name":"isExecutor","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"intentHash","type":"bytes32"}],"name":"isIntentExecuted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"validator","type":"address"}],"name":"isValidator","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"ownerNonce","outputs":[{"internalType":"uint256","name":"nonce","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"executor","type":"address"},{"internalType":"bool","name":"isExecutor_","type":"bool"}],"name":"setExecutor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"validator","type":"address"},{"internalType":"bool","name":"isValidator_","type":"bool"}],"name":"setValidator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint32","name":"boxId","type":"uint32"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"tokenSpent","type":"address"},{"internalType":"uint256","name":"amountSpent","type":"uint256"},{"internalType":"address","name":"tokenReceived","type":"address"},{"internalType":"uint256","name":"minReceived","type":"uint256"},{"internalType":"uint256","name":"feeAmount","type":"uint256"},{"internalType":"address","name":"swapExecutor","type":"address"},{"internalType":"address","name":"swapExtRouter","type":"address"},{"internalType":"bytes","name":"swapCalldata","type":"bytes"}],"internalType":"struct IPCrossChainSwapHub.SwapTokenMessage","name":"ms","type":"tuple"},{"internalType":"bytes","name":"sig","type":"bytes"}],"name":"swapToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"},{"internalType":"bool","name":"direct","type":"bool"},{"internalType":"bool","name":"renounce","type":"bool"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint32","name":"boxId","type":"uint32"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"withdrawAmount","type":"uint256"},{"internalType":"uint256","name":"feeAmount","type":"uint256"}],"internalType":"struct IPCrossChainSwapHub.WithdrawTokenMessage","name":"ms","type":"tuple"},{"internalType":"bytes","name":"sig","type":"bytes"}],"name":"withdrawToken","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
60e080604052346101e3576040816142d9803803809161001f82856101e7565b8339810103126101e35761003e60206100378361020a565b920161020a565b608082905260a0819052813b6001600160401b0381116101cf576100c8916100d6915f604051956100796020601f19601f86011601886101e7565b82875260208701903c6040519060018060a01b031660208201526040808201525f6060820152606081526100ae6080826101e7565b6040519283916100c260208401809761021e565b9061021e565b03601f1981018352826101e7565b51902060c05260015460ff8160a81c1661017a5760ff808260a01c1603610137575b60405161409190816102488239608051818181611a050152613417015260a0518181816124b0015261347d015260c05181818161174e01526133ad0152f35b60ff60a01b191660ff60a01b1760015560405160ff81527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249890602090a15f6100f8565b60405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b6064820152608490fd5b634e487b7160e01b5f52604160045260245ffd5b5f80fd5b601f909101601f19168101906001600160401b038211908210176101cf57604052565b51906001600160a01b03821682036101e357565b908151915f5b838110610234575050015f815290565b806020809284010151818501520161022456fe60806040526004361015610011575f80fd5b5f5f3560e01c8063078dfbe7146124d45780631122f54e146124665780631e1bff3f146123945780632212614414611a295780632d610bb0146119ba5780634623c91d146118e65780634e71e0c8146117cb5780635172e414146117715780635a3f0e6b146117185780636661b84b1461141d5780636eeee43f146113d057806384b0196e146111995780638da5cb5b14611148578063b047db00146110ee578063c0f29fa614610e01578063c4d66de814610705578063c5c6e1d6146106c1578063db50f4e014610667578063debfda30146105ff578063e30c3978146105ad578063e748fd27146102bd578063e8ad29b41461025a578063ebf65ba61461020e578063f22e9dd4146101975763facd743b1461012d575f80fd5b346101945760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101945760ff604060209273ffffffffffffffffffffffffffffffffffffffff6101806126a8565b168152606984522054166040519015158152f35b80fd5b50346101945760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610194576101cf6126a8565b6024359163ffffffff831683036101945760406101ec848461333d565b73ffffffffffffffffffffffffffffffffffffffff8351921682526020820152f35b5034610194576101007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261019457602061025261024d36612c45565b613260565b604051908152f35b50346101945760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261019457604060209173ffffffffffffffffffffffffffffffffffffffff6102ac6126a8565b168152606683522054604051908152f35b5034610194576101207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610194576102f736612c45565b6101043567ffffffffffffffff81116105a95761031b61036591369060040161295b565b338452606860205261033360ff604086205416612d86565b73ffffffffffffffffffffffffffffffffffffffff835116604084015160608501519061035f86613260565b92613854565b73ffffffffffffffffffffffffffffffffffffffff8151169073ffffffffffffffffffffffffffffffffffffffff6103a9602083019363ffffffff855116906133fe565b16906080810173ffffffffffffffffffffffffffffffffffffffff81511660a08301928673ffffffffffffffffffffffffffffffffffffffff85511660c0830193845191883b15610590576040517fc3b35a7e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff92831660048201529116602482015260448101919091528181606481838b5af1801561058557610594575b5073ffffffffffffffffffffffffffffffffffffffff8551169560e08301968751823b15610590576040517fef36298000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff92909216600483015260248201529082908290604490829084905af1801561058557610568575b505051945191519251905193516040805163ffffffff909416845273ffffffffffffffffffffffffffffffffffffffff94851660208501529184169183019190915260608201939093526080810192909252909116907f852c900c43a40fa3535c1461c76efc47e92768df6752f1b92c782415b29bd8f8908060a081015b0390a280f35b8161057591949394612799565b6105815790865f6104e4565b8680fd5b6040513d84823e3d90fd5b8380fd5b8161059e91612799565b61058157865f61045a565b8280fd5b503461019457807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261019457602073ffffffffffffffffffffffffffffffffffffffff60015416604051908152f35b50346101945760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101945760ff604060209273ffffffffffffffffffffffffffffffffffffffff6106536126a8565b168152606884522054166040519015158152f35b50346101945760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610194576004359067ffffffffffffffff82116101945760206102526106bc3660048601612b8d565b61316f565b5034610194576101607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610194576020610252610700366127eb565b613050565b50346101945760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101945761073d6126a8565b60015460ff8160a81c161590818092610df1575b8015610dd7575b15610d535781740100000000000000000000000000000000000000007fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff831617600155610d10575b5060409182516107b08482612799565b601b81527f50656e646c652043726f737320436861696e205377617020487562000000000060208201528351906107e78583612799565b600182527f3100000000000000000000000000000000000000000000000000000000000000602083015261082b60ff60015460a81c16610826816139e7565b6139e7565b80519067ffffffffffffffff8211610ce357819061084a6004546138c1565b601f8111610c38575b50602090601f8311600114610b7b578892610b70575b50507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8260011b9260031b1c1916176004555b80519067ffffffffffffffff8211610b43576108b96005546138c1565b601f8111610aa2575b50602090601f83116001146109cd5773ffffffffffffffffffffffffffffffffffffffff9392918791836109c2575b50507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8260011b9260031b1c1916176005555b846002558460035561093d60ff60015460a81c166139e7565b167fffffffffffffffffffffffff000000000000000000000000000000000000000084541617835561096d575080f35b60207f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498917fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff600154166001555160018152a180f35b015190505f806108f1565b600587527f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db091907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08416885b818110610a8a575091600193918573ffffffffffffffffffffffffffffffffffffffff97969410610a53575b505050811b01600555610924565b01517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88460031b161c191690555f8080610a45565b92936020600181928786015181550195019301610a19565b60058752601f830160051c7f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db0019060208410610b1b575b601f0160051c7f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db001905b818110610b1057506108c2565b878155600101610b03565b7f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db09150610ad9565b6024867f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b015190505f80610869565b600489527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b927fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016895b818110610c205750908460019594939210610be9575b505050811b0160045561089c565b01517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88460031b161c191690555f8080610bdb565b92936020600181928786015181550195019301610bc5565b90915060048852601f830160051c7f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b019060208410610cbb575b90601f8493920160051c7f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b01905b818110610cad5750610853565b898155849350600101610ca0565b7f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b9150610c72565b6024877f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b7fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff167501010000000000000000000000000000000000000000176001555f6107a0565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152fd5b50303b1580156107585750600160ff8260a01c1614610758565b50600160ff8260a01c1610610751565b5060407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101945760043567ffffffffffffffff81116110ea57610e4c903690600401612b8d565b60243567ffffffffffffffff81116105a957610e6f610eb391369060040161295b565b3384526068602052610e8760ff604086205416612d86565b73ffffffffffffffffffffffffffffffffffffffff835116604084015160608501519061035f8661316f565b73ffffffffffffffffffffffffffffffffffffffff81511690610ee2602082019263ffffffff845116906133fe565b608082019073ffffffffffffffffffffffffffffffffffffffff8251169260a0810190610f868773ffffffffffffffffffffffffffffffffffffffff84519560e085019682885116610100870151916040519b610f3e8d612760565b8c5260208c015260408b015260608a01521696604051809381927f704a2e9b000000000000000000000000000000000000000000000000000000008352339060048401613733565b0381348a5af180156110df576110bd575b508673ffffffffffffffffffffffffffffffffffffffff8551169560c08301968751823b15610590576040517fef36298000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff92909216600483015260248201529082908290604490829084905af18015610585576110a4575b505051945191519251905193516040805163ffffffff909416845273ffffffffffffffffffffffffffffffffffffffff94851660208501529184169183019190915260608201939093526080810192909252909116907f0e0f64c3d50163af7cbbbfccc4856d259e68800f812d791f6310603cd734e841908060a08101610562565b816110b191949394612799565b6105815790865f611022565b6110d8903d808a833e6110d08183612799565b8101906136d4565b505f610f97565b6040513d8a823e3d90fd5b5080fd5b50346101945760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610194576004359067ffffffffffffffff821161019457602061025261114336600486016129a1565b612f72565b503461019457807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101945773ffffffffffffffffffffffffffffffffffffffff6020915416604051908152f35b503461019457807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101945760025415806113c6575b1561136857604051908082600454916111ea836138c1565b808352926001811690811561132b57506001146112cd575b6112719493925090611215910383612799565b61121d613912565b90602061127f604051936112318386612799565b8385525f3681376040519687967f0f00000000000000000000000000000000000000000000000000000000000000885260e08589015260e0880190612b4a565b908682036040880152612b4a565b904660608601523060808601528260a086015284820360c08601528080855193848152019401925b8281106112b657505050500390f35b8351855286955093810193928101926001016112a7565b50600483529082907f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b5b81831061130f57505090602061121592820101611202565b60209193508060019154838589010152019101909184926112f7565b602092506112159491507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001682840152151560051b820101611202565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4549503731323a20556e696e697469616c697a656400000000000000000000006044820152fd5b50600354156111d2565b50346101945760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101945760ff60406020926004358152606784522054166040519015158152f35b50346101945760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101945760043567ffffffffffffffff81116110ea5761146d903690600401612a3a565b60243567ffffffffffffffff81116105a9576114906114d491369060040161295b565b33845260686020526114a860ff604086205416612d86565b73ffffffffffffffffffffffffffffffffffffffff835116604084015160608501519061035f86612e25565b73ffffffffffffffffffffffffffffffffffffffff81511690611503602082019263ffffffff845116906133fe565b608082019173ffffffffffffffffffffffffffffffffffffffff83511660a0820191866115b284519360c084019473ffffffffffffffffffffffffffffffffffffffff86511673ffffffffffffffffffffffffffffffffffffffff6101408701511690610160870151926040519461157a866126fb565b8552602085015260408401526060830152608082015273ffffffffffffffffffffffffffffffffffffffff6101208501511687613c80565b73ffffffffffffffffffffffffffffffffffffffff6115d8610100850192835190612deb565b96169073ffffffffffffffffffffffffffffffffffffffff8551169051823b15610590576040517fef36298000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff92909216600483015260248201529082908290604490829084905af1801561058557611703575b505060e081015184106116db579160a0939173ffffffffffffffffffffffffffffffffffffffff8063ffffffff817f96af82ad65d3deec4f3d60fccfd90dccdbaab9813fb8a008aeae79742c775e01999751169951169551169251915116916040519485526020850152604084015260608301526080820152a280f35b6004877f4af147aa000000000000000000000000000000000000000000000000000000008152fd5b8161170d91612799565b61058157865f61165e565b503461019457807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101945760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b50346101945760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610194576004359067ffffffffffffffff82116101945760206102526117c63660048601612a3a565b612e25565b503461019457807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101945760015473ffffffffffffffffffffffffffffffffffffffff811690813303611888577fffffffffffffffffffffffff0000000000000000000000000000000000000000918284548273ffffffffffffffffffffffffffffffffffffffff82167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08880a3161783551660015580f35b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602060248201527f4f776e61626c653a2063616c6c657220213d2070656e64696e67206f776e65726044820152fd5b50346101945760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101945761191e6126a8565b7ff777a2dd5104082173537070fa5bc14b35ab543cc11a90836e264f3cef55c064602073ffffffffffffffffffffffffffffffffffffffff61195e6126ec565b9361196d828754163314612d21565b1692838552606982526119ae81604087209060ff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0083541691151516179055565b6040519015158152a280f35b503461019457807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261019457602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b506101c07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261229857611a5e366127eb565b6101643567ffffffffffffffff811161229857611a7f90369060040161295b565b906101843567ffffffffffffffff811161229857611aa19036906004016129a1565b6101a43567ffffffffffffffff811161229857611ac290369060040161295b565b335f526068602052611ada60ff60405f205416612d86565b611b0c73ffffffffffffffffffffffffffffffffffffffff8451169460608501958651611b0687613050565b916133e3565b73ffffffffffffffffffffffffffffffffffffffff825116611b3c60e084015192611b3685612f72565b83613a72565b1561236c575f52606960205260ff60405f205416156123445742101561231c576040516020810173ffffffffffffffffffffffffffffffffffffffff8451168152602084019463ffffffff865116604084015260408501516060840152516080830152608084019373ffffffffffffffffffffffffffffffffffffffff85511660a084015260a08101805160c085015260c082019173ffffffffffffffffffffffffffffffffffffffff83511660e086015260e081019373ffffffffffffffffffffffffffffffffffffffff855116610100870152610100820190815161012088015261012083019063ffffffff82511661014089015261014084019788516101608201526101608152611c5261018082612799565b519020968760208a0151036122f457875f52606760205260ff60405f2054166122cc578991885f52606760205260405f2060017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055611cd68c63ffffffff73ffffffffffffffffffffffffffffffffffffffff885116915116906133fe565b60408b019687519051611d0373ffffffffffffffffffffffffffffffffffffffff80851697511687613bd1565b808210156122c45750905b1161229c576060611d7a88611d85938f8f6080908e73ffffffffffffffffffffffffffffffffffffffff808095511696519151168460a0840151169060c08401519260405198611d5d8a6126fb565b895260208901526040880152888701528286015201511690613c80565b9b019a8b5190612deb565b9973ffffffffffffffffffffffffffffffffffffffff885116905190843b15612298576040517fef36298000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff91909116600482015260248101919091525f8160448183885af1801561228d57612278575b50875173ffffffffffffffffffffffffffffffffffffffff16611f055750505034611edd575b518610611eb5579160e095939173ffffffffffffffffffffffffffffffffffffffff808063ffffffff817fd2bd82e459ebe49956443a8300f02a6dc2872bcf22e3fde66a5955d7896e4ae19c9a9851169c5116985116925193511693511693604051968752602087015260408601526060850152608084015260a083015260c0820152a280f35b6004897f4af147aa000000000000000000000000000000000000000000000000000000008152fd5b60048a7f50f6bc57000000000000000000000000000000000000000000000000000000008152fd5b5190516040519399929392909163ffffffff1660e0840167ffffffffffffffff81118582101761224b579289928f94928a9796936040528352602083019182526040830181815260608401908682526020988992604051611f668582612799565b8981526080880190815260405190611f7e8683612799565b8a825260a0890191825260405192611f968785612799565b8b845260c08a0193845260405195611fad87612744565b348752878701958d87525173ffffffffffffffffffffffffffffffffffffffff169b5173ffffffffffffffffffffffffffffffffffffffff16996040519b8c998a017fc7c7f5b300000000000000000000000000000000000000000000000000000000905260248a01608090525163ffffffff1660a48a01525160c48901525160e48801525161010487015251610124860160e09052610184860161205191612b4a565b9051908581037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5c0161014487015261208891612b4a565b9051908481037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5c016101648601526120bf91612b4a565b91516044840152516064830152336084830152037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0810184526121029084612799565b6040519361210f85612760565b8452868401526040830152606082015260405192838080937f704a2e9b00000000000000000000000000000000000000000000000000000000825233600483019161215992613733565b039134905af1908115612240578b91612226575b508051810181838201910360c081126122225760801361221e57604051916060830183811067ffffffffffffffff8211176121f15760405283810151835260408101519067ffffffffffffffff821682036121ed578360a092866121e596015260406121dc856060850161378f565b9101520161378f565b015195611e2e565b8d80fd5b60248e7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b8b80fd5b8c80fd5b61223a91503d808d833e6110d08183612799565b5f61216d565b6040513d8d823e3d90fd5b60248f7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b612285919d505f90612799565b5f9b5f611e08565b6040513d5f823e3d90fd5b5f80fd5b7fcae33fc2000000000000000000000000000000000000000000000000000000005f5260045ffd5b905090611d0e565b7f9ad9d4ae000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f7e5d179b000000000000000000000000000000000000000000000000000000005f5260045ffd5b7ff753ba40000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f682a6e7c000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f8baa579f000000000000000000000000000000000000000000000000000000005f5260045ffd5b346122985760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112612298576123cb6126a8565b7f827c394aebf0fcbf2d4f5c0107a0031a3860ec0d5e06756e03aacccfb8d2836e602073ffffffffffffffffffffffffffffffffffffffff61240b6126ec565b9361241a825f54163314612d21565b1692835f526068825261245b8160405f209060ff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0083541691151516179055565b6040519015158152a2005b34612298575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261229857602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346122985760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126122985761250b6126a8565b6125136126ec565b906044359182151583036122985761254373ffffffffffffffffffffffffffffffffffffffff5f54163314612d21565b156126635773ffffffffffffffffffffffffffffffffffffffff169081159081159161265b575b50156125fd577fffffffffffffffffffffffff00000000000000000000000000000000000000005f548273ffffffffffffffffffffffffffffffffffffffff82167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a316175f55600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055005b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4f776e61626c653a207a65726f206164647265737300000000000000000000006044820152fd5b90508261256a565b73ffffffffffffffffffffffffffffffffffffffff9150167fffffffffffffffffffffffff000000000000000000000000000000000000000060015416176001555f80f35b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361229857565b359073ffffffffffffffffffffffffffffffffffffffff8216820361229857565b60243590811515820361229857565b60a0810190811067ffffffffffffffff82111761271757604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6040810190811067ffffffffffffffff82111761271757604052565b6080810190811067ffffffffffffffff82111761271757604052565b610100810190811067ffffffffffffffff82111761271757604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761271757604052565b359063ffffffff8216820361229857565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6101609101126122985760405190610160820182811067ffffffffffffffff821117612717576040528160043573ffffffffffffffffffffffffffffffffffffffff8116810361229857815260243563ffffffff811681036122985760208201526044356040820152606435606082015260843573ffffffffffffffffffffffffffffffffffffffff8116810361229857608082015260a43560a082015260c43573ffffffffffffffffffffffffffffffffffffffff811681036122985760c082015260e43573ffffffffffffffffffffffffffffffffffffffff811681036122985760e0820152610104356101008201526101243563ffffffff811681036122985761012082015261014061014435910152565b67ffffffffffffffff811161271757601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b81601f820112156122985780359061297282612921565b926129806040519485612799565b8284526020838301011161229857815f926020809301838601378301015290565b9190916101008184031261229857604051906129bc8261277c565b81936129c7826126cb565b83526020820135602084015260408201356040840152606082013560608401526129f3608083016126cb565b6080840152612a0460a083016126cb565b60a084015260c08201359167ffffffffffffffff831161229857612a2e60e093928493830161295b565b60c08501520135910152565b9190610180838203126122985760405190610180820182811067ffffffffffffffff821117612717576040528193612a71816126cb565b8352612a7f602082016127da565b60208401526040810135604084015260608101356060840152612aa4608082016126cb565b608084015260a081013560a0840152612abf60c082016126cb565b60c084015260e081013560e0840152610100810135610100840152612ae761012082016126cb565b610120840152612afa61014082016126cb565b6101408401526101608101359167ffffffffffffffff83116122985761016092612b24920161295b565b910152565b5f5b838110612b3a5750505f910152565b8181015183820152602001612b2b565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f602093612b8681518092818752878088019101612b29565b0116010190565b9190610120838203126122985760405190610120820182811067ffffffffffffffff821117612717576040528193612bc4816126cb565b8352612bd2602082016127da565b60208401526040810135604084015260608101356060840152612bf7608082016126cb565b608084015260a081013560a084015260c081013560c0840152612c1c60e082016126cb565b60e08401526101008101359167ffffffffffffffff83116122985761010092612b24920161295b565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6101009101126122985760405190612c7d8261277c565b8160043573ffffffffffffffffffffffffffffffffffffffff8116810361229857815260243563ffffffff811681036122985760208201526044356040820152606435606082015260843573ffffffffffffffffffffffffffffffffffffffff8116810361229857608082015260a43573ffffffffffffffffffffffffffffffffffffffff811681036122985760a082015260c43560c082015260e060e435910152565b15612d2857565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b15612d8d57565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f537761704875623a2063616c6c6572206973206e6f74206578656375746f72006044820152fd5b91908203918211612df857565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b7fe07c2f14f77ceaf30254671ba25d3940e18a280d418ec04f30a421b76fec8e21612f6f9173ffffffffffffffffffffffffffffffffffffffff8151169063ffffffff602082015116906040810151606082015173ffffffffffffffffffffffffffffffffffffffff60808401511660a084015173ffffffffffffffffffffffffffffffffffffffff60c0860151169060e0860151926101008701519473ffffffffffffffffffffffffffffffffffffffff610120890151169661016073ffffffffffffffffffffffffffffffffffffffff6101408b01511699015160208151910120996040519b60208d019d8e5260408d015260608c015260808b015260a08a015260c089015260e08801526101008701526101208601526101408501526101608401526101808301526101a08201526101a08152612f676101c082612799565b5190206137b7565b90565b612f6f9073ffffffffffffffffffffffffffffffffffffffff81511690602081015190604081015190606081015173ffffffffffffffffffffffffffffffffffffffff60808301511673ffffffffffffffffffffffffffffffffffffffff60a0840151169160e060c085015160208151910120940151946040519660208801987f345607f719c1866f84a751ece95dae332cdc57f1ac7b9a3c0f57d85467f6b8558a5260408901526060880152608087015260a086015260c085015260e08401526101008301526101208201526101208152612f6761014082612799565b612f6f9073ffffffffffffffffffffffffffffffffffffffff8151169063ffffffff60208201511690604081015190606081015173ffffffffffffffffffffffffffffffffffffffff60808301511660a083015173ffffffffffffffffffffffffffffffffffffffff60c0850151169073ffffffffffffffffffffffffffffffffffffffff60e086015116926101008601519461014063ffffffff61012089015116970151976040519960208b019b7fb0495383b38434498bc2572bbcd98ce300312a41ea78569ae7c34883312098f88d5260408c015260608b015260808a015260a089015260c088015260e08701526101008601526101208501526101408401526101608301526101808201526101808152612f676101a082612799565b612f6f9073ffffffffffffffffffffffffffffffffffffffff8151169063ffffffff60208201511690604081015190606081015173ffffffffffffffffffffffffffffffffffffffff60808301511660a08301519060c08401519261010073ffffffffffffffffffffffffffffffffffffffff60e08701511695015160208151910120956040519760208901997f7ef2c3495d9c54f20199df4ec535ba2e5fdd12b43641d162c97bd6472c912ba38b5260408a01526060890152608088015260a087015260c086015260e08501526101008401526101208301526101408201526101408152612f6761016082612799565b612f6f9073ffffffffffffffffffffffffffffffffffffffff8151169063ffffffff60208201511690604081015190606081015173ffffffffffffffffffffffffffffffffffffffff60808301511673ffffffffffffffffffffffffffffffffffffffff60a0840151169160e060c0850151940151946040519660208801987fc3a5c2101c4567506dd16b560c791a943b26fb6b941c74a0a439da06a0d5fa178a5260408901526060880152608087015260a086015260c085015260e08401526101008301526101208201526101208152612f6761014082612799565b6040805173ffffffffffffffffffffffffffffffffffffffff9092166020830190815263ffffffff909316908201526133a181606081015b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282612799565b5190206055600b6040517f000000000000000000000000000000000000000000000000000000000000000060408201528360208201523081520160ff81532091565b916133f092939193613a72565b1561236c5742101561231c57565b90613409818361333d565b8193913b6136b8576134e1907f000000000000000000000000000000000000000000000000000000000000000061350f813b61344481612921565b906134526040519283612799565b8082525f6020830180953c60206040518181019073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001682526040808201525f6060820152606081526134ba608082612799565b6040519788946134d285870198899251928391612b29565b85019151809385840190612b29565b0101037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101855284612799565b82511561365a5773ffffffffffffffffffffffffffffffffffffffff9251905ff5169283156135fc5773ffffffffffffffffffffffffffffffffffffffff168093036135cf57823b15612298576040517fc5e4c9f900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff91909116600482015263ffffffff9190911660248201525f8160448183865af1801561228d576135c5575090565b5f612f6f91612799565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52600160045260245ffd5b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f437265617465323a204661696c6564206f6e206465706c6f79000000000000006044820152fd5b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602060248201527f437265617465323a2062797465636f6465206c656e677468206973207a65726f6044820152fd5b50505073ffffffffffffffffffffffffffffffffffffffff1690565b6020818303126122985780519067ffffffffffffffff8211612298570181601f8201121561229857805161370781612921565b926137156040519485612799565b8184526020828401011161229857612f6f9160208085019101612b29565b9073ffffffffffffffffffffffffffffffffffffffff61378860606020939695966040865283815116604087015284810151828701528360408201511660808701520151608060a086015260c0850190612b4a565b9416910152565b9190826040910312612298576040516137a781612744565b6020808294805184520151910152565b6042906137c2613f21565b6137ca614035565b6040519060208201927f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f8452604083015260608201524660808201523060a082015260a0815261381b60c082612799565b51902090604051917f19010000000000000000000000000000000000000000000000000000000000008352600283015260228201522090565b919373ffffffffffffffffffffffffffffffffffffffff9361387692846133e3565b16805f5260666020528160405f20541015613899575f52606660205260405f2055565b7f756688fe000000000000000000000000000000000000000000000000000000005f5260045ffd5b90600182811c92168015613908575b60208310146138db57565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b91607f16916138d0565b604051905f8260055491613925836138c1565b80835292600181169081156139aa575060011461394b575b61394992500383612799565b565b5060055f90815290917f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db05b81831061398e5750509060206139499282010161393d565b6020919350806001915483858901015201910190918492613976565b602092506139499491507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001682840152151560051b82010161393d565b156139ee57565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152fd5b90613a7d8382613e64565b6005819592951015613ba457159384613b81575b508315613a9f575b50505090565b5f935090613375613af085949360405192839160208301957f1626ba7e0000000000000000000000000000000000000000000000000000000087526024840152604060448401526064830190612b4a565b51915afa3d15613b7a573d613b0481612921565b90613b126040519283612799565b81523d5f602083013e5b81613b6c575b81613b31575b505f8080613a99565b905060208180518101031261229857602001517f1626ba7e00000000000000000000000000000000000000000000000000000000145f613b28565b905060208151101590613b22565b6060613b1c565b73ffffffffffffffffffffffffffffffffffffffff84811691161493505f613a91565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b9073ffffffffffffffffffffffffffffffffffffffff1680613bf257503190565b9073ffffffffffffffffffffffffffffffffffffffff602460209260405194859384927f70a082310000000000000000000000000000000000000000000000000000000084521660048301525afa90811561228d575f91613c51575090565b90506020813d602011613c78575b81613c6c60209383612799565b81010312612298575190565b3d9150613c5f565b8251602084018051939473ffffffffffffffffffffffffffffffffffffffff93909316935f92853b15612298576040517fc3b35a7e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff888116600483015291909116602482015260448101919091525f8160648183895af1801561228d57613e4f575b50604083019273ffffffffffffffffffffffffffffffffffffffff613d3d8186511687613bd1565b961691823b1561059057613dfe92849283608093604051968795869485937fc3a7e1ce0000000000000000000000000000000000000000000000000000000085528d60048601526040602486015273ffffffffffffffffffffffffffffffffffffffff825116604486015251606485015273ffffffffffffffffffffffffffffffffffffffff8c5116608485015273ffffffffffffffffffffffffffffffffffffffff60608201511660a4850152015160a060c484015260e4830190612b4a565b03925af1801561058557613e3a575b5050612f6f929173ffffffffffffffffffffffffffffffffffffffff613e3592511690613bd1565b612deb565b613e45828092612799565b6101945780613e0d565b613e5c9192505f90612799565b5f905f613d15565b9060418151145f14613e9057613e8c91602082015190606060408401519301515f1a90613e99565b9091565b50505f90600290565b7f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08411613f16576020935f9360ff60809460405194855216868401526040830152606082015282805260015afa1561228d575f5173ffffffffffffffffffffffffffffffffffffffff811615613f0e57905f90565b505f90600190565b505050505f90600390565b604051600454905f81613f33846138c1565b9182825260208201946001811690815f14613ffb5750600114613f9c575b613f5d92500382612799565b51908115613f69572090565b50506002548015613f775790565b507fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47090565b5060045f90815290917f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b5b818310613fdf575050906020613f5d92820101613f51565b6020919350806001915483858801015201910190918392613fc7565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016865250613f5d92151560051b82016020019050613f51565b61403d613912565b805190811561404d576020012090565b50506003548015613f77579056fea26469706673582212205ef79df11ab184849f6e8631855e459b9d9a4fe9f68ac95c6c4f0010e98f6c3464736f6c634300081e003300000000000000000000000070a8f7e851fe77058e2d9e84e4379e3b218675a2000000000000000000000000312529cc93df1cb9da2dce616a7b939182e0bf5e
Deployed Bytecode
0x60806040526004361015610011575f80fd5b5f5f3560e01c8063078dfbe7146124d45780631122f54e146124665780631e1bff3f146123945780632212614414611a295780632d610bb0146119ba5780634623c91d146118e65780634e71e0c8146117cb5780635172e414146117715780635a3f0e6b146117185780636661b84b1461141d5780636eeee43f146113d057806384b0196e146111995780638da5cb5b14611148578063b047db00146110ee578063c0f29fa614610e01578063c4d66de814610705578063c5c6e1d6146106c1578063db50f4e014610667578063debfda30146105ff578063e30c3978146105ad578063e748fd27146102bd578063e8ad29b41461025a578063ebf65ba61461020e578063f22e9dd4146101975763facd743b1461012d575f80fd5b346101945760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101945760ff604060209273ffffffffffffffffffffffffffffffffffffffff6101806126a8565b168152606984522054166040519015158152f35b80fd5b50346101945760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610194576101cf6126a8565b6024359163ffffffff831683036101945760406101ec848461333d565b73ffffffffffffffffffffffffffffffffffffffff8351921682526020820152f35b5034610194576101007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261019457602061025261024d36612c45565b613260565b604051908152f35b50346101945760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261019457604060209173ffffffffffffffffffffffffffffffffffffffff6102ac6126a8565b168152606683522054604051908152f35b5034610194576101207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610194576102f736612c45565b6101043567ffffffffffffffff81116105a95761031b61036591369060040161295b565b338452606860205261033360ff604086205416612d86565b73ffffffffffffffffffffffffffffffffffffffff835116604084015160608501519061035f86613260565b92613854565b73ffffffffffffffffffffffffffffffffffffffff8151169073ffffffffffffffffffffffffffffffffffffffff6103a9602083019363ffffffff855116906133fe565b16906080810173ffffffffffffffffffffffffffffffffffffffff81511660a08301928673ffffffffffffffffffffffffffffffffffffffff85511660c0830193845191883b15610590576040517fc3b35a7e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff92831660048201529116602482015260448101919091528181606481838b5af1801561058557610594575b5073ffffffffffffffffffffffffffffffffffffffff8551169560e08301968751823b15610590576040517fef36298000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff92909216600483015260248201529082908290604490829084905af1801561058557610568575b505051945191519251905193516040805163ffffffff909416845273ffffffffffffffffffffffffffffffffffffffff94851660208501529184169183019190915260608201939093526080810192909252909116907f852c900c43a40fa3535c1461c76efc47e92768df6752f1b92c782415b29bd8f8908060a081015b0390a280f35b8161057591949394612799565b6105815790865f6104e4565b8680fd5b6040513d84823e3d90fd5b8380fd5b8161059e91612799565b61058157865f61045a565b8280fd5b503461019457807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261019457602073ffffffffffffffffffffffffffffffffffffffff60015416604051908152f35b50346101945760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101945760ff604060209273ffffffffffffffffffffffffffffffffffffffff6106536126a8565b168152606884522054166040519015158152f35b50346101945760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610194576004359067ffffffffffffffff82116101945760206102526106bc3660048601612b8d565b61316f565b5034610194576101607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610194576020610252610700366127eb565b613050565b50346101945760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101945761073d6126a8565b60015460ff8160a81c161590818092610df1575b8015610dd7575b15610d535781740100000000000000000000000000000000000000007fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff831617600155610d10575b5060409182516107b08482612799565b601b81527f50656e646c652043726f737320436861696e205377617020487562000000000060208201528351906107e78583612799565b600182527f3100000000000000000000000000000000000000000000000000000000000000602083015261082b60ff60015460a81c16610826816139e7565b6139e7565b80519067ffffffffffffffff8211610ce357819061084a6004546138c1565b601f8111610c38575b50602090601f8311600114610b7b578892610b70575b50507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8260011b9260031b1c1916176004555b80519067ffffffffffffffff8211610b43576108b96005546138c1565b601f8111610aa2575b50602090601f83116001146109cd5773ffffffffffffffffffffffffffffffffffffffff9392918791836109c2575b50507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8260011b9260031b1c1916176005555b846002558460035561093d60ff60015460a81c166139e7565b167fffffffffffffffffffffffff000000000000000000000000000000000000000084541617835561096d575080f35b60207f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498917fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff600154166001555160018152a180f35b015190505f806108f1565b600587527f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db091907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08416885b818110610a8a575091600193918573ffffffffffffffffffffffffffffffffffffffff97969410610a53575b505050811b01600555610924565b01517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88460031b161c191690555f8080610a45565b92936020600181928786015181550195019301610a19565b60058752601f830160051c7f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db0019060208410610b1b575b601f0160051c7f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db001905b818110610b1057506108c2565b878155600101610b03565b7f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db09150610ad9565b6024867f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b015190505f80610869565b600489527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b927fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016895b818110610c205750908460019594939210610be9575b505050811b0160045561089c565b01517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88460031b161c191690555f8080610bdb565b92936020600181928786015181550195019301610bc5565b90915060048852601f830160051c7f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b019060208410610cbb575b90601f8493920160051c7f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b01905b818110610cad5750610853565b898155849350600101610ca0565b7f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b9150610c72565b6024877f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b7fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff167501010000000000000000000000000000000000000000176001555f6107a0565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152fd5b50303b1580156107585750600160ff8260a01c1614610758565b50600160ff8260a01c1610610751565b5060407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101945760043567ffffffffffffffff81116110ea57610e4c903690600401612b8d565b60243567ffffffffffffffff81116105a957610e6f610eb391369060040161295b565b3384526068602052610e8760ff604086205416612d86565b73ffffffffffffffffffffffffffffffffffffffff835116604084015160608501519061035f8661316f565b73ffffffffffffffffffffffffffffffffffffffff81511690610ee2602082019263ffffffff845116906133fe565b608082019073ffffffffffffffffffffffffffffffffffffffff8251169260a0810190610f868773ffffffffffffffffffffffffffffffffffffffff84519560e085019682885116610100870151916040519b610f3e8d612760565b8c5260208c015260408b015260608a01521696604051809381927f704a2e9b000000000000000000000000000000000000000000000000000000008352339060048401613733565b0381348a5af180156110df576110bd575b508673ffffffffffffffffffffffffffffffffffffffff8551169560c08301968751823b15610590576040517fef36298000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff92909216600483015260248201529082908290604490829084905af18015610585576110a4575b505051945191519251905193516040805163ffffffff909416845273ffffffffffffffffffffffffffffffffffffffff94851660208501529184169183019190915260608201939093526080810192909252909116907f0e0f64c3d50163af7cbbbfccc4856d259e68800f812d791f6310603cd734e841908060a08101610562565b816110b191949394612799565b6105815790865f611022565b6110d8903d808a833e6110d08183612799565b8101906136d4565b505f610f97565b6040513d8a823e3d90fd5b5080fd5b50346101945760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610194576004359067ffffffffffffffff821161019457602061025261114336600486016129a1565b612f72565b503461019457807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101945773ffffffffffffffffffffffffffffffffffffffff6020915416604051908152f35b503461019457807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101945760025415806113c6575b1561136857604051908082600454916111ea836138c1565b808352926001811690811561132b57506001146112cd575b6112719493925090611215910383612799565b61121d613912565b90602061127f604051936112318386612799565b8385525f3681376040519687967f0f00000000000000000000000000000000000000000000000000000000000000885260e08589015260e0880190612b4a565b908682036040880152612b4a565b904660608601523060808601528260a086015284820360c08601528080855193848152019401925b8281106112b657505050500390f35b8351855286955093810193928101926001016112a7565b50600483529082907f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b5b81831061130f57505090602061121592820101611202565b60209193508060019154838589010152019101909184926112f7565b602092506112159491507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001682840152151560051b820101611202565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4549503731323a20556e696e697469616c697a656400000000000000000000006044820152fd5b50600354156111d2565b50346101945760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101945760ff60406020926004358152606784522054166040519015158152f35b50346101945760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101945760043567ffffffffffffffff81116110ea5761146d903690600401612a3a565b60243567ffffffffffffffff81116105a9576114906114d491369060040161295b565b33845260686020526114a860ff604086205416612d86565b73ffffffffffffffffffffffffffffffffffffffff835116604084015160608501519061035f86612e25565b73ffffffffffffffffffffffffffffffffffffffff81511690611503602082019263ffffffff845116906133fe565b608082019173ffffffffffffffffffffffffffffffffffffffff83511660a0820191866115b284519360c084019473ffffffffffffffffffffffffffffffffffffffff86511673ffffffffffffffffffffffffffffffffffffffff6101408701511690610160870151926040519461157a866126fb565b8552602085015260408401526060830152608082015273ffffffffffffffffffffffffffffffffffffffff6101208501511687613c80565b73ffffffffffffffffffffffffffffffffffffffff6115d8610100850192835190612deb565b96169073ffffffffffffffffffffffffffffffffffffffff8551169051823b15610590576040517fef36298000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff92909216600483015260248201529082908290604490829084905af1801561058557611703575b505060e081015184106116db579160a0939173ffffffffffffffffffffffffffffffffffffffff8063ffffffff817f96af82ad65d3deec4f3d60fccfd90dccdbaab9813fb8a008aeae79742c775e01999751169951169551169251915116916040519485526020850152604084015260608301526080820152a280f35b6004877f4af147aa000000000000000000000000000000000000000000000000000000008152fd5b8161170d91612799565b61058157865f61165e565b503461019457807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101945760206040517fbfd315991f302ed14c459887f386ea0f2b23437722064e7aa51bbb1941e37c0b8152f35b50346101945760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610194576004359067ffffffffffffffff82116101945760206102526117c63660048601612a3a565b612e25565b503461019457807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101945760015473ffffffffffffffffffffffffffffffffffffffff811690813303611888577fffffffffffffffffffffffff0000000000000000000000000000000000000000918284548273ffffffffffffffffffffffffffffffffffffffff82167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08880a3161783551660015580f35b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602060248201527f4f776e61626c653a2063616c6c657220213d2070656e64696e67206f776e65726044820152fd5b50346101945760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101945761191e6126a8565b7ff777a2dd5104082173537070fa5bc14b35ab543cc11a90836e264f3cef55c064602073ffffffffffffffffffffffffffffffffffffffff61195e6126ec565b9361196d828754163314612d21565b1692838552606982526119ae81604087209060ff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0083541691151516179055565b6040519015158152a280f35b503461019457807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261019457602060405173ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000070a8f7e851fe77058e2d9e84e4379e3b218675a2168152f35b506101c07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261229857611a5e366127eb565b6101643567ffffffffffffffff811161229857611a7f90369060040161295b565b906101843567ffffffffffffffff811161229857611aa19036906004016129a1565b6101a43567ffffffffffffffff811161229857611ac290369060040161295b565b335f526068602052611ada60ff60405f205416612d86565b611b0c73ffffffffffffffffffffffffffffffffffffffff8451169460608501958651611b0687613050565b916133e3565b73ffffffffffffffffffffffffffffffffffffffff825116611b3c60e084015192611b3685612f72565b83613a72565b1561236c575f52606960205260ff60405f205416156123445742101561231c576040516020810173ffffffffffffffffffffffffffffffffffffffff8451168152602084019463ffffffff865116604084015260408501516060840152516080830152608084019373ffffffffffffffffffffffffffffffffffffffff85511660a084015260a08101805160c085015260c082019173ffffffffffffffffffffffffffffffffffffffff83511660e086015260e081019373ffffffffffffffffffffffffffffffffffffffff855116610100870152610100820190815161012088015261012083019063ffffffff82511661014089015261014084019788516101608201526101608152611c5261018082612799565b519020968760208a0151036122f457875f52606760205260ff60405f2054166122cc578991885f52606760205260405f2060017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00825416179055611cd68c63ffffffff73ffffffffffffffffffffffffffffffffffffffff885116915116906133fe565b60408b019687519051611d0373ffffffffffffffffffffffffffffffffffffffff80851697511687613bd1565b808210156122c45750905b1161229c576060611d7a88611d85938f8f6080908e73ffffffffffffffffffffffffffffffffffffffff808095511696519151168460a0840151169060c08401519260405198611d5d8a6126fb565b895260208901526040880152888701528286015201511690613c80565b9b019a8b5190612deb565b9973ffffffffffffffffffffffffffffffffffffffff885116905190843b15612298576040517fef36298000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff91909116600482015260248101919091525f8160448183885af1801561228d57612278575b50875173ffffffffffffffffffffffffffffffffffffffff16611f055750505034611edd575b518610611eb5579160e095939173ffffffffffffffffffffffffffffffffffffffff808063ffffffff817fd2bd82e459ebe49956443a8300f02a6dc2872bcf22e3fde66a5955d7896e4ae19c9a9851169c5116985116925193511693511693604051968752602087015260408601526060850152608084015260a083015260c0820152a280f35b6004897f4af147aa000000000000000000000000000000000000000000000000000000008152fd5b60048a7f50f6bc57000000000000000000000000000000000000000000000000000000008152fd5b5190516040519399929392909163ffffffff1660e0840167ffffffffffffffff81118582101761224b579289928f94928a9796936040528352602083019182526040830181815260608401908682526020988992604051611f668582612799565b8981526080880190815260405190611f7e8683612799565b8a825260a0890191825260405192611f968785612799565b8b845260c08a0193845260405195611fad87612744565b348752878701958d87525173ffffffffffffffffffffffffffffffffffffffff169b5173ffffffffffffffffffffffffffffffffffffffff16996040519b8c998a017fc7c7f5b300000000000000000000000000000000000000000000000000000000905260248a01608090525163ffffffff1660a48a01525160c48901525160e48801525161010487015251610124860160e09052610184860161205191612b4a565b9051908581037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5c0161014487015261208891612b4a565b9051908481037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5c016101648601526120bf91612b4a565b91516044840152516064830152336084830152037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0810184526121029084612799565b6040519361210f85612760565b8452868401526040830152606082015260405192838080937f704a2e9b00000000000000000000000000000000000000000000000000000000825233600483019161215992613733565b039134905af1908115612240578b91612226575b508051810181838201910360c081126122225760801361221e57604051916060830183811067ffffffffffffffff8211176121f15760405283810151835260408101519067ffffffffffffffff821682036121ed578360a092866121e596015260406121dc856060850161378f565b9101520161378f565b015195611e2e565b8d80fd5b60248e7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b8b80fd5b8c80fd5b61223a91503d808d833e6110d08183612799565b5f61216d565b6040513d8d823e3d90fd5b60248f7f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b612285919d505f90612799565b5f9b5f611e08565b6040513d5f823e3d90fd5b5f80fd5b7fcae33fc2000000000000000000000000000000000000000000000000000000005f5260045ffd5b905090611d0e565b7f9ad9d4ae000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f7e5d179b000000000000000000000000000000000000000000000000000000005f5260045ffd5b7ff753ba40000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f682a6e7c000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f8baa579f000000000000000000000000000000000000000000000000000000005f5260045ffd5b346122985760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112612298576123cb6126a8565b7f827c394aebf0fcbf2d4f5c0107a0031a3860ec0d5e06756e03aacccfb8d2836e602073ffffffffffffffffffffffffffffffffffffffff61240b6126ec565b9361241a825f54163314612d21565b1692835f526068825261245b8160405f209060ff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0083541691151516179055565b6040519015158152a2005b34612298575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261229857602060405173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000312529cc93df1cb9da2dce616a7b939182e0bf5e168152f35b346122985760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126122985761250b6126a8565b6125136126ec565b906044359182151583036122985761254373ffffffffffffffffffffffffffffffffffffffff5f54163314612d21565b156126635773ffffffffffffffffffffffffffffffffffffffff169081159081159161265b575b50156125fd577fffffffffffffffffffffffff00000000000000000000000000000000000000005f548273ffffffffffffffffffffffffffffffffffffffff82167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a316175f55600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055005b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4f776e61626c653a207a65726f206164647265737300000000000000000000006044820152fd5b90508261256a565b73ffffffffffffffffffffffffffffffffffffffff9150167fffffffffffffffffffffffff000000000000000000000000000000000000000060015416176001555f80f35b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361229857565b359073ffffffffffffffffffffffffffffffffffffffff8216820361229857565b60243590811515820361229857565b60a0810190811067ffffffffffffffff82111761271757604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6040810190811067ffffffffffffffff82111761271757604052565b6080810190811067ffffffffffffffff82111761271757604052565b610100810190811067ffffffffffffffff82111761271757604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761271757604052565b359063ffffffff8216820361229857565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6101609101126122985760405190610160820182811067ffffffffffffffff821117612717576040528160043573ffffffffffffffffffffffffffffffffffffffff8116810361229857815260243563ffffffff811681036122985760208201526044356040820152606435606082015260843573ffffffffffffffffffffffffffffffffffffffff8116810361229857608082015260a43560a082015260c43573ffffffffffffffffffffffffffffffffffffffff811681036122985760c082015260e43573ffffffffffffffffffffffffffffffffffffffff811681036122985760e0820152610104356101008201526101243563ffffffff811681036122985761012082015261014061014435910152565b67ffffffffffffffff811161271757601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b81601f820112156122985780359061297282612921565b926129806040519485612799565b8284526020838301011161229857815f926020809301838601378301015290565b9190916101008184031261229857604051906129bc8261277c565b81936129c7826126cb565b83526020820135602084015260408201356040840152606082013560608401526129f3608083016126cb565b6080840152612a0460a083016126cb565b60a084015260c08201359167ffffffffffffffff831161229857612a2e60e093928493830161295b565b60c08501520135910152565b9190610180838203126122985760405190610180820182811067ffffffffffffffff821117612717576040528193612a71816126cb565b8352612a7f602082016127da565b60208401526040810135604084015260608101356060840152612aa4608082016126cb565b608084015260a081013560a0840152612abf60c082016126cb565b60c084015260e081013560e0840152610100810135610100840152612ae761012082016126cb565b610120840152612afa61014082016126cb565b6101408401526101608101359167ffffffffffffffff83116122985761016092612b24920161295b565b910152565b5f5b838110612b3a5750505f910152565b8181015183820152602001612b2b565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f602093612b8681518092818752878088019101612b29565b0116010190565b9190610120838203126122985760405190610120820182811067ffffffffffffffff821117612717576040528193612bc4816126cb565b8352612bd2602082016127da565b60208401526040810135604084015260608101356060840152612bf7608082016126cb565b608084015260a081013560a084015260c081013560c0840152612c1c60e082016126cb565b60e08401526101008101359167ffffffffffffffff83116122985761010092612b24920161295b565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc6101009101126122985760405190612c7d8261277c565b8160043573ffffffffffffffffffffffffffffffffffffffff8116810361229857815260243563ffffffff811681036122985760208201526044356040820152606435606082015260843573ffffffffffffffffffffffffffffffffffffffff8116810361229857608082015260a43573ffffffffffffffffffffffffffffffffffffffff811681036122985760a082015260c43560c082015260e060e435910152565b15612d2857565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b15612d8d57565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f537761704875623a2063616c6c6572206973206e6f74206578656375746f72006044820152fd5b91908203918211612df857565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b7fe07c2f14f77ceaf30254671ba25d3940e18a280d418ec04f30a421b76fec8e21612f6f9173ffffffffffffffffffffffffffffffffffffffff8151169063ffffffff602082015116906040810151606082015173ffffffffffffffffffffffffffffffffffffffff60808401511660a084015173ffffffffffffffffffffffffffffffffffffffff60c0860151169060e0860151926101008701519473ffffffffffffffffffffffffffffffffffffffff610120890151169661016073ffffffffffffffffffffffffffffffffffffffff6101408b01511699015160208151910120996040519b60208d019d8e5260408d015260608c015260808b015260a08a015260c089015260e08801526101008701526101208601526101408501526101608401526101808301526101a08201526101a08152612f676101c082612799565b5190206137b7565b90565b612f6f9073ffffffffffffffffffffffffffffffffffffffff81511690602081015190604081015190606081015173ffffffffffffffffffffffffffffffffffffffff60808301511673ffffffffffffffffffffffffffffffffffffffff60a0840151169160e060c085015160208151910120940151946040519660208801987f345607f719c1866f84a751ece95dae332cdc57f1ac7b9a3c0f57d85467f6b8558a5260408901526060880152608087015260a086015260c085015260e08401526101008301526101208201526101208152612f6761014082612799565b612f6f9073ffffffffffffffffffffffffffffffffffffffff8151169063ffffffff60208201511690604081015190606081015173ffffffffffffffffffffffffffffffffffffffff60808301511660a083015173ffffffffffffffffffffffffffffffffffffffff60c0850151169073ffffffffffffffffffffffffffffffffffffffff60e086015116926101008601519461014063ffffffff61012089015116970151976040519960208b019b7fb0495383b38434498bc2572bbcd98ce300312a41ea78569ae7c34883312098f88d5260408c015260608b015260808a015260a089015260c088015260e08701526101008601526101208501526101408401526101608301526101808201526101808152612f676101a082612799565b612f6f9073ffffffffffffffffffffffffffffffffffffffff8151169063ffffffff60208201511690604081015190606081015173ffffffffffffffffffffffffffffffffffffffff60808301511660a08301519060c08401519261010073ffffffffffffffffffffffffffffffffffffffff60e08701511695015160208151910120956040519760208901997f7ef2c3495d9c54f20199df4ec535ba2e5fdd12b43641d162c97bd6472c912ba38b5260408a01526060890152608088015260a087015260c086015260e08501526101008401526101208301526101408201526101408152612f6761016082612799565b612f6f9073ffffffffffffffffffffffffffffffffffffffff8151169063ffffffff60208201511690604081015190606081015173ffffffffffffffffffffffffffffffffffffffff60808301511673ffffffffffffffffffffffffffffffffffffffff60a0840151169160e060c0850151940151946040519660208801987fc3a5c2101c4567506dd16b560c791a943b26fb6b941c74a0a439da06a0d5fa178a5260408901526060880152608087015260a086015260c085015260e08401526101008301526101208201526101208152612f6761014082612799565b6040805173ffffffffffffffffffffffffffffffffffffffff9092166020830190815263ffffffff909316908201526133a181606081015b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282612799565b5190206055600b6040517fbfd315991f302ed14c459887f386ea0f2b23437722064e7aa51bbb1941e37c0b60408201528360208201523081520160ff81532091565b916133f092939193613a72565b1561236c5742101561231c57565b90613409818361333d565b8193913b6136b8576134e1907f00000000000000000000000070a8f7e851fe77058e2d9e84e4379e3b218675a261350f813b61344481612921565b906134526040519283612799565b8082525f6020830180953c60206040518181019073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000312529cc93df1cb9da2dce616a7b939182e0bf5e1682526040808201525f6060820152606081526134ba608082612799565b6040519788946134d285870198899251928391612b29565b85019151809385840190612b29565b0101037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101855284612799565b82511561365a5773ffffffffffffffffffffffffffffffffffffffff9251905ff5169283156135fc5773ffffffffffffffffffffffffffffffffffffffff168093036135cf57823b15612298576040517fc5e4c9f900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff91909116600482015263ffffffff9190911660248201525f8160448183865af1801561228d576135c5575090565b5f612f6f91612799565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52600160045260245ffd5b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f437265617465323a204661696c6564206f6e206465706c6f79000000000000006044820152fd5b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602060248201527f437265617465323a2062797465636f6465206c656e677468206973207a65726f6044820152fd5b50505073ffffffffffffffffffffffffffffffffffffffff1690565b6020818303126122985780519067ffffffffffffffff8211612298570181601f8201121561229857805161370781612921565b926137156040519485612799565b8184526020828401011161229857612f6f9160208085019101612b29565b9073ffffffffffffffffffffffffffffffffffffffff61378860606020939695966040865283815116604087015284810151828701528360408201511660808701520151608060a086015260c0850190612b4a565b9416910152565b9190826040910312612298576040516137a781612744565b6020808294805184520151910152565b6042906137c2613f21565b6137ca614035565b6040519060208201927f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f8452604083015260608201524660808201523060a082015260a0815261381b60c082612799565b51902090604051917f19010000000000000000000000000000000000000000000000000000000000008352600283015260228201522090565b919373ffffffffffffffffffffffffffffffffffffffff9361387692846133e3565b16805f5260666020528160405f20541015613899575f52606660205260405f2055565b7f756688fe000000000000000000000000000000000000000000000000000000005f5260045ffd5b90600182811c92168015613908575b60208310146138db57565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b91607f16916138d0565b604051905f8260055491613925836138c1565b80835292600181169081156139aa575060011461394b575b61394992500383612799565b565b5060055f90815290917f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db05b81831061398e5750509060206139499282010161393d565b6020919350806001915483858901015201910190918492613976565b602092506139499491507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001682840152151560051b82010161393d565b156139ee57565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152fd5b90613a7d8382613e64565b6005819592951015613ba457159384613b81575b508315613a9f575b50505090565b5f935090613375613af085949360405192839160208301957f1626ba7e0000000000000000000000000000000000000000000000000000000087526024840152604060448401526064830190612b4a565b51915afa3d15613b7a573d613b0481612921565b90613b126040519283612799565b81523d5f602083013e5b81613b6c575b81613b31575b505f8080613a99565b905060208180518101031261229857602001517f1626ba7e00000000000000000000000000000000000000000000000000000000145f613b28565b905060208151101590613b22565b6060613b1c565b73ffffffffffffffffffffffffffffffffffffffff84811691161493505f613a91565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b9073ffffffffffffffffffffffffffffffffffffffff1680613bf257503190565b9073ffffffffffffffffffffffffffffffffffffffff602460209260405194859384927f70a082310000000000000000000000000000000000000000000000000000000084521660048301525afa90811561228d575f91613c51575090565b90506020813d602011613c78575b81613c6c60209383612799565b81010312612298575190565b3d9150613c5f565b8251602084018051939473ffffffffffffffffffffffffffffffffffffffff93909316935f92853b15612298576040517fc3b35a7e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff888116600483015291909116602482015260448101919091525f8160648183895af1801561228d57613e4f575b50604083019273ffffffffffffffffffffffffffffffffffffffff613d3d8186511687613bd1565b961691823b1561059057613dfe92849283608093604051968795869485937fc3a7e1ce0000000000000000000000000000000000000000000000000000000085528d60048601526040602486015273ffffffffffffffffffffffffffffffffffffffff825116604486015251606485015273ffffffffffffffffffffffffffffffffffffffff8c5116608485015273ffffffffffffffffffffffffffffffffffffffff60608201511660a4850152015160a060c484015260e4830190612b4a565b03925af1801561058557613e3a575b5050612f6f929173ffffffffffffffffffffffffffffffffffffffff613e3592511690613bd1565b612deb565b613e45828092612799565b6101945780613e0d565b613e5c9192505f90612799565b5f905f613d15565b9060418151145f14613e9057613e8c91602082015190606060408401519301515f1a90613e99565b9091565b50505f90600290565b7f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08411613f16576020935f9360ff60809460405194855216868401526040830152606082015282805260015afa1561228d575f5173ffffffffffffffffffffffffffffffffffffffff811615613f0e57905f90565b505f90600190565b505050505f90600390565b604051600454905f81613f33846138c1565b9182825260208201946001811690815f14613ffb5750600114613f9c575b613f5d92500382612799565b51908115613f69572090565b50506002548015613f775790565b507fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47090565b5060045f90815290917f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b5b818310613fdf575050906020613f5d92820101613f51565b6020919350806001915483858801015201910190918392613fc7565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016865250613f5d92151560051b82016020019050613f51565b61403d613912565b805190811561404d576020012090565b50506003548015613f77579056fea26469706673582212205ef79df11ab184849f6e8631855e459b9d9a4fe9f68ac95c6c4f0010e98f6c3464736f6c634300081e0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000070a8f7e851fe77058e2d9e84e4379e3b218675a2000000000000000000000000312529cc93df1cb9da2dce616a7b939182e0bf5e
-----Decoded View---------------
Arg [0] : beaconProxyCodeContract_ (address): 0x70A8f7e851FE77058e2d9E84e4379e3b218675a2
Arg [1] : depositBoxBeacon_ (address): 0x312529cc93DF1cB9da2dcE616a7B939182E0Bf5e
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 00000000000000000000000070a8f7e851fe77058e2d9e84e4379e3b218675a2
Arg [1] : 000000000000000000000000312529cc93df1cb9da2dce616a7b939182e0bf5e
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 33 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
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.