Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00Latest 12 from a total of 12 transactions
| Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Send OFT | 20959247 | 58 days ago | IN | 0.00003841 ETH | 0.00002514 | ||||
| Send OFT | 15399573 | 132 days ago | IN | 0.00004502 ETH | 0.0000237 | ||||
| Send OFT | 13983152 | 149 days ago | IN | 0.00253298 ETH | 0.00002572 | ||||
| Send OFT | 13519359 | 155 days ago | IN | 0.00003756 ETH | 0.00002692 | ||||
| Send OFT | 12732079 | 164 days ago | IN | 0.0000927 ETH | 0.00002181 | ||||
| Send OFT | 12392959 | 168 days ago | IN | 0.00003967 ETH | 0.00002152 | ||||
| Send OFT | 11990911 | 173 days ago | IN | 0.00004869 ETH | 0.00002125 | ||||
| Send OFT | 11233327 | 182 days ago | IN | 0.0002253 ETH | 0.00002174 | ||||
| Send OFT | 11133109 | 183 days ago | IN | 0.00012677 ETH | 0.00002348 | ||||
| Transfer Ownersh... | 11062268 | 184 days ago | IN | 0 ETH | 0.00000585 | ||||
| Send OFT | 10950256 | 186 days ago | IN | 0.00007555 ETH | 0.00002147 | ||||
| Send OFT | 10720686 | 188 days ago | IN | 0.0000879 ETH | 0.00002158 |
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 22064406 | 40 days ago | 0.00275969 ETH | ||||
| 20959247 | 58 days ago | 0.0000105 ETH | ||||
| 20959247 | 58 days ago | 0.00003841 ETH | ||||
| 15399573 | 132 days ago | 0.00002081 ETH | ||||
| 15399573 | 132 days ago | 0.00004502 ETH | ||||
| 13983152 | 149 days ago | 0.00019252 ETH | ||||
| 13983152 | 149 days ago | 0.00253298 ETH | ||||
| 13519359 | 155 days ago | 0.00001713 ETH | ||||
| 13519359 | 155 days ago | 0.00003756 ETH | ||||
| 12732079 | 164 days ago | 0.00007054 ETH | ||||
| 12732079 | 164 days ago | 0.0000927 ETH | ||||
| 12392959 | 168 days ago | 0.0000184 ETH | ||||
| 12392959 | 168 days ago | 0.00003967 ETH | ||||
| 11990911 | 173 days ago | 0.00002813 ETH | ||||
| 11990911 | 173 days ago | 0.00004869 ETH | ||||
| 11233327 | 182 days ago | 0.00001854 ETH | ||||
| 11233327 | 182 days ago | 0.0002253 ETH | ||||
| 11133109 | 183 days ago | 0.00009441 ETH | ||||
| 11133109 | 183 days ago | 0.00012677 ETH | ||||
| 10950256 | 186 days ago | 0.00000022 ETH | ||||
| 10950256 | 186 days ago | 0.00005265 ETH | ||||
| 10950256 | 186 days ago | 0.00007555 ETH | ||||
| 10720686 | 188 days ago | 0.00006701 ETH | ||||
| 10720686 | 188 days ago | 0.0000879 ETH | ||||
| 7955135 | 221 days ago | Contract Creation | 0 ETH |
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Source Code Verified (Exact Match)
Contract Name:
RemoteHop
Compiler Version
v0.8.23+commit.f704f362
ZkSolc Version
v1.5.12
Optimization Enabled:
Yes with Mode 3
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { Ownable2Step, Ownable } from "@openzeppelin/contracts/access/Ownable2Step.sol";
import { OptionsBuilder } from "@fraxfinance/layerzero-v2-upgradeable/oapp/contracts/oapp/libs/OptionsBuilder.sol";
import { SendParam, MessagingFee, IOFT } from "@fraxfinance/layerzero-v2-upgradeable/oapp/contracts/oft/interfaces/IOFT.sol";
import { IOFT2 } from "./interfaces/IOFT2.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import { ILayerZeroDVN } from "./interfaces/ILayerZeroDVN.sol";
import { ILayerZeroTreasury } from "./interfaces/ILayerZeroTreasury.sol";
import { IExecutor } from "./interfaces/IExecutor.sol";
// ====================================================================
// | ______ _______ |
// | / _____________ __ __ / ____(_____ ____ _____ ________ |
// | / /_ / ___/ __ `| |/_/ / /_ / / __ \/ __ `/ __ \/ ___/ _ \ |
// | / __/ / / / /_/ _> < / __/ / / / / / /_/ / / / / /__/ __/ |
// | /_/ /_/ \__,_/_/|_| /_/ /_/_/ /_/\__,_/_/ /_/\___/\___/ |
// | |
// ====================================================================
// ============================ RemoteHop =============================
// ====================================================================
/// @author Frax Finance: https://github.com/FraxFinance
contract RemoteHop is Ownable2Step {
bool public paused = false;
bytes32 public fraxtalHop;
uint256 public numDVNs = 2;
uint256 public hopFee = 1; // 10000 based so 1 = 0.01%
mapping(uint32 => bytes) public executorOptions;
mapping(address => bool) public approvedOft;
address public immutable EXECUTOR;
address public immutable DVN;
address public immutable TREASURY;
event SendOFT(address oft, address indexed sender, uint32 indexed dstEid, bytes32 indexed to, uint256 amountLD);
error InvalidOFT();
error HopPaused();
error NotEndpoint();
error InsufficientFee();
error RefundFailed();
error ZeroAmountSend();
constructor(
bytes32 _fraxtalHop,
uint256 _numDVNs,
address _EXECUTOR,
address _DVN,
address _TREASURY,
address[] memory _approvedOfts
) Ownable(msg.sender) {
fraxtalHop = _fraxtalHop;
numDVNs = _numDVNs;
EXECUTOR = _EXECUTOR;
DVN = _DVN;
TREASURY = _TREASURY;
for (uint256 i = 0; i < _approvedOfts.length; i++) {
approvedOft[_approvedOfts[i]] = true;
}
}
// Admin functions
function recoverERC20(address tokenAddress, address recipient, uint256 tokenAmount) external onlyOwner {
IERC20(tokenAddress).transfer(recipient, tokenAmount);
}
function recoverETH(address recipient, uint256 tokenAmount) external onlyOwner {
payable(recipient).call{ value: tokenAmount }("");
}
function setFraxtalHop(address _fraxtalHop) external {
setFraxtalHop(bytes32(uint256(uint160(_fraxtalHop))));
}
function setFraxtalHop(bytes32 _fraxtalHop) public onlyOwner {
fraxtalHop = _fraxtalHop;
}
function setNumDVNs(uint256 _numDVNs) external onlyOwner {
numDVNs = _numDVNs;
}
function setHopFee(uint256 _hopFee) external onlyOwner {
hopFee = _hopFee;
}
function setExecutorOptions(uint32 eid, bytes memory _options) external onlyOwner {
executorOptions[eid] = _options;
}
function pause(bool _paused) external onlyOwner {
paused = _paused;
}
function toggleOFTApproval(address _oft, bool _approved) external onlyOwner {
approvedOft[_oft] = _approved;
}
// receive ETH
receive() external payable {}
function sendOFT(address _oft, uint32 _dstEid, bytes32 _to, uint256 _amountLD) external payable {
if (paused) revert HopPaused();
if (!approvedOft[_oft]) revert InvalidOFT();
_amountLD = removeDust(_oft, _amountLD);
if (_amountLD == 0) revert ZeroAmountSend();
SafeERC20.safeTransferFrom(IERC20(IOFT(_oft).token()), msg.sender, address(this), _amountLD);
if (_dstEid == 30255) {
_sendToFraxtal(_oft, _to, _amountLD);
} else {
_sendViaFraxtal(_oft, _dstEid, _to, _amountLD);
}
emit SendOFT(_oft, msg.sender, _dstEid, _to, _amountLD);
}
function _sendToFraxtal(address _oft, bytes32 _to, uint256 _amountLD) internal {
// Send the oft
SafeERC20.forceApprove(IERC20(IOFT(_oft).token()), _oft, _amountLD);
SendParam memory sendParam = SendParam({
dstEid: 30255,
to: _to,
amountLD: _amountLD,
minAmountLD: _amountLD,
extraOptions: "",
composeMsg: "",
oftCmd: ""
});
MessagingFee memory fee = IOFT(_oft).quoteSend(sendParam, false);
IOFT(_oft).send{ value: fee.nativeFee }(sendParam, fee, address(this));
// Refund the excess
if (msg.value < fee.nativeFee) revert InsufficientFee();
if (msg.value > fee.nativeFee) {
(bool success, ) = address(msg.sender).call{ value: msg.value - fee.nativeFee }("");
if (!success) revert RefundFailed();
}
}
function _sendViaFraxtal(address _oft, uint32 _dstEid, bytes32 _to, uint256 _amountLD) internal {
// generate arguments
SendParam memory sendParam = _generateSendParam({
_dstEid: _dstEid,
_to: _to,
_amountLD: _amountLD,
_minAmountLD: _amountLD
});
MessagingFee memory fee = IOFT(_oft).quoteSend(sendParam, false);
uint256 finalFee = fee.nativeFee + quoteHop(_dstEid);
if (finalFee > msg.value) revert InsufficientFee();
// Send the oft
SafeERC20.forceApprove(IERC20(IOFT(_oft).token()), _oft, _amountLD);
IOFT(_oft).send{ value: fee.nativeFee }(sendParam, fee, address(this));
// Refund the excess
if (msg.value > finalFee) {
(bool success, ) = address(msg.sender).call{ value: msg.value - finalFee }("");
if (!success) revert RefundFailed();
}
}
function _generateSendParam(
uint32 _dstEid,
bytes32 _to,
uint256 _amountLD,
uint256 _minAmountLD
) internal view returns (SendParam memory sendParam) {
bytes memory options = OptionsBuilder.newOptions();
options = OptionsBuilder.addExecutorLzComposeOption(options, 0, 1000000, 0);
sendParam.dstEid = 30255;
sendParam.to = fraxtalHop;
sendParam.amountLD = _amountLD;
sendParam.minAmountLD = _minAmountLD;
sendParam.extraOptions = options;
sendParam.composeMsg = abi.encode(_to, _dstEid);
}
function quote(
address _oft,
uint32 _dstEid,
bytes32 _to,
uint256 _amountLD
) public view returns (MessagingFee memory fee) {
_amountLD = removeDust(_oft, _amountLD);
if (_dstEid == 30255) {
SendParam memory sendParam = SendParam({
dstEid: 30255,
to: _to,
amountLD: _amountLD,
minAmountLD: _amountLD,
extraOptions: "",
composeMsg: "",
oftCmd: ""
});
fee = IOFT(_oft).quoteSend(sendParam, false);
} else {
SendParam memory sendParam = _generateSendParam({
_dstEid: _dstEid,
_to: _to,
_amountLD: _amountLD,
_minAmountLD: _amountLD
});
fee = IOFT(_oft).quoteSend(sendParam, false);
fee.nativeFee += quoteHop(_dstEid);
}
}
function quoteHop(uint32 _dstEid) public view returns (uint256 finalFee) {
uint256 dvnFee = ILayerZeroDVN(DVN).getFee(_dstEid, 5, address(this), "");
bytes memory options = executorOptions[_dstEid];
if (options.length == 0) options = hex"01001101000000000000000000000000000493E0";
uint256 executorFee = IExecutor(EXECUTOR).getFee(_dstEid, address(this), 36, options);
uint256 totalFee = dvnFee * numDVNs + executorFee;
uint256 treasuryFee = ILayerZeroTreasury(TREASURY).getFee(address(this), _dstEid, totalFee, false);
finalFee = totalFee + treasuryFee;
finalFee = (finalFee * (10000 + hopFee)) / 10000;
}
function removeDust(address oft, uint256 _amountLD) internal view returns (uint256) {
uint256 decimalConversionRate = IOFT2(oft).decimalConversionRate();
return (_amountLD / decimalConversionRate) * decimalConversionRate;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable2Step.sol)
pragma solidity ^0.8.20;
import {Ownable} from "./Ownable.sol";
/**
* @dev Contract module which provides access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is specified at deployment time in the constructor for `Ownable`. This
* can later be changed with {transferOwnership} and {acceptOwnership}.
*
* This module is used through inheritance. It will make available all functions
* from parent (Ownable).
*/
abstract contract Ownable2Step is Ownable {
address private _pendingOwner;
event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
/**
* @dev Returns the address of the pending owner.
*/
function pendingOwner() public view virtual returns (address) {
return _pendingOwner;
}
/**
* @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual override onlyOwner {
_pendingOwner = newOwner;
emit OwnershipTransferStarted(owner(), newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual override {
delete _pendingOwner;
super._transferOwnership(newOwner);
}
/**
* @dev The new owner accepts the ownership transfer.
*/
function acceptOwnership() public virtual {
address sender = _msgSender();
if (pendingOwner() != sender) {
revert OwnableUnauthorizedAccount(sender);
}
_transferOwnership(sender);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import { BytesLib } from "solidity-bytes-utils/contracts/BytesLib.sol";
import { SafeCast } from "@openzeppelin/contracts/utils/math/SafeCast.sol";
import { ExecutorOptions } from "@layerzerolabs/lz-evm-protocol-v2/contracts/messagelib/libs/ExecutorOptions.sol";
import { DVNOptions } from "@layerzerolabs/lz-evm-messagelib-v2/contracts/uln/libs/DVNOptions.sol";
/**
* @title OptionsBuilder
* @dev Library for building and encoding various message options.
*/
library OptionsBuilder {
using SafeCast for uint256;
using BytesLib for bytes;
// Constants for options types
uint16 internal constant TYPE_1 = 1; // legacy options type 1
uint16 internal constant TYPE_2 = 2; // legacy options type 2
uint16 internal constant TYPE_3 = 3;
// Custom error message
error InvalidSize(uint256 max, uint256 actual);
error InvalidOptionType(uint16 optionType);
// Modifier to ensure only options of type 3 are used
modifier onlyType3(bytes memory _options) {
if (_options.toUint16(0) != TYPE_3) revert InvalidOptionType(_options.toUint16(0));
_;
}
/**
* @dev Creates a new options container with type 3.
* @return options The newly created options container.
*/
function newOptions() internal pure returns (bytes memory) {
return abi.encodePacked(TYPE_3);
}
/**
* @dev Adds an executor LZ receive option to the existing options.
* @param _options The existing options container.
* @param _gas The gasLimit used on the lzReceive() function in the OApp.
* @param _value The msg.value passed to the lzReceive() function in the OApp.
* @return options The updated options container.
*
* @dev When multiples of this option are added, they are summed by the executor
* eg. if (_gas: 200k, and _value: 1 ether) AND (_gas: 100k, _value: 0.5 ether) are sent in an option to the LayerZeroEndpoint,
* that becomes (300k, 1.5 ether) when the message is executed on the remote lzReceive() function.
*/
function addExecutorLzReceiveOption(
bytes memory _options,
uint128 _gas,
uint128 _value
) internal pure onlyType3(_options) returns (bytes memory) {
bytes memory option = ExecutorOptions.encodeLzReceiveOption(_gas, _value);
return addExecutorOption(_options, ExecutorOptions.OPTION_TYPE_LZRECEIVE, option);
}
/**
* @dev Adds an executor native drop option to the existing options.
* @param _options The existing options container.
* @param _amount The amount for the native value that is airdropped to the 'receiver'.
* @param _receiver The receiver address for the native drop option.
* @return options The updated options container.
*
* @dev When multiples of this option are added, they are summed by the executor on the remote chain.
*/
function addExecutorNativeDropOption(
bytes memory _options,
uint128 _amount,
bytes32 _receiver
) internal pure onlyType3(_options) returns (bytes memory) {
bytes memory option = ExecutorOptions.encodeNativeDropOption(_amount, _receiver);
return addExecutorOption(_options, ExecutorOptions.OPTION_TYPE_NATIVE_DROP, option);
}
/**
* @dev Adds an executor LZ compose option to the existing options.
* @param _options The existing options container.
* @param _index The index for the lzCompose() function call.
* @param _gas The gasLimit for the lzCompose() function call.
* @param _value The msg.value for the lzCompose() function call.
* @return options The updated options container.
*
* @dev When multiples of this option are added, they are summed PER index by the executor on the remote chain.
* @dev If the OApp sends N lzCompose calls on the remote, you must provide N incremented indexes starting with 0.
* ie. When your remote OApp composes (N = 3) messages, you must set this option for index 0,1,2
*/
function addExecutorLzComposeOption(
bytes memory _options,
uint16 _index,
uint128 _gas,
uint128 _value
) internal pure onlyType3(_options) returns (bytes memory) {
bytes memory option = ExecutorOptions.encodeLzComposeOption(_index, _gas, _value);
return addExecutorOption(_options, ExecutorOptions.OPTION_TYPE_LZCOMPOSE, option);
}
/**
* @dev Adds an executor ordered execution option to the existing options.
* @param _options The existing options container.
* @return options The updated options container.
*/
function addExecutorOrderedExecutionOption(
bytes memory _options
) internal pure onlyType3(_options) returns (bytes memory) {
return addExecutorOption(_options, ExecutorOptions.OPTION_TYPE_ORDERED_EXECUTION, bytes(""));
}
/**
* @dev Adds a DVN pre-crime option to the existing options.
* @param _options The existing options container.
* @param _dvnIdx The DVN index for the pre-crime option.
* @return options The updated options container.
*/
function addDVNPreCrimeOption(
bytes memory _options,
uint8 _dvnIdx
) internal pure onlyType3(_options) returns (bytes memory) {
return addDVNOption(_options, _dvnIdx, DVNOptions.OPTION_TYPE_PRECRIME, bytes(""));
}
/**
* @dev Adds an executor option to the existing options.
* @param _options The existing options container.
* @param _optionType The type of the executor option.
* @param _option The encoded data for the executor option.
* @return options The updated options container.
*/
function addExecutorOption(
bytes memory _options,
uint8 _optionType,
bytes memory _option
) internal pure onlyType3(_options) returns (bytes memory) {
return
abi.encodePacked(
_options,
ExecutorOptions.WORKER_ID,
_option.length.toUint16() + 1, // +1 for optionType
_optionType,
_option
);
}
/**
* @dev Adds a DVN option to the existing options.
* @param _options The existing options container.
* @param _dvnIdx The DVN index for the DVN option.
* @param _optionType The type of the DVN option.
* @param _option The encoded data for the DVN option.
* @return options The updated options container.
*/
function addDVNOption(
bytes memory _options,
uint8 _dvnIdx,
uint8 _optionType,
bytes memory _option
) internal pure onlyType3(_options) returns (bytes memory) {
return
abi.encodePacked(
_options,
DVNOptions.WORKER_ID,
_option.length.toUint16() + 2, // +2 for optionType and dvnIdx
_dvnIdx,
_optionType,
_option
);
}
/**
* @dev Encodes legacy options of type 1.
* @param _executionGas The gasLimit value passed to lzReceive().
* @return legacyOptions The encoded legacy options.
*/
function encodeLegacyOptionsType1(uint256 _executionGas) internal pure returns (bytes memory) {
if (_executionGas > type(uint128).max) revert InvalidSize(type(uint128).max, _executionGas);
return abi.encodePacked(TYPE_1, _executionGas);
}
/**
* @dev Encodes legacy options of type 2.
* @param _executionGas The gasLimit value passed to lzReceive().
* @param _nativeForDst The amount of native air dropped to the receiver.
* @param _receiver The _nativeForDst receiver address.
* @return legacyOptions The encoded legacy options of type 2.
*/
function encodeLegacyOptionsType2(
uint256 _executionGas,
uint256 _nativeForDst,
bytes memory _receiver // @dev Use bytes instead of bytes32 in legacy type 2 for _receiver.
) internal pure returns (bytes memory) {
if (_executionGas > type(uint128).max) revert InvalidSize(type(uint128).max, _executionGas);
if (_nativeForDst > type(uint128).max) revert InvalidSize(type(uint128).max, _nativeForDst);
if (_receiver.length > 32) revert InvalidSize(32, _receiver.length);
return abi.encodePacked(TYPE_2, _executionGas, _nativeForDst, _receiver);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import { MessagingReceipt, MessagingFee } from "../../oapp/OAppSenderUpgradeable.sol";
/**
* @dev Struct representing token parameters for the OFT send() operation.
*/
struct SendParam {
uint32 dstEid; // Destination endpoint ID.
bytes32 to; // Recipient address.
uint256 amountLD; // Amount to send in local decimals.
uint256 minAmountLD; // Minimum amount to send in local decimals.
bytes extraOptions; // Additional options supplied by the caller to be used in the LayerZero message.
bytes composeMsg; // The composed message for the send() operation.
bytes oftCmd; // The OFT command to be executed, unused in default OFT implementations.
}
/**
* @dev Struct representing OFT limit information.
* @dev These amounts can change dynamically and are up the the specific oft implementation.
*/
struct OFTLimit {
uint256 minAmountLD; // Minimum amount in local decimals that can be sent to the recipient.
uint256 maxAmountLD; // Maximum amount in local decimals that can be sent to the recipient.
}
/**
* @dev Struct representing OFT receipt information.
*/
struct OFTReceipt {
uint256 amountSentLD; // Amount of tokens ACTUALLY debited from the sender in local decimals.
// @dev In non-default implementations, the amountReceivedLD COULD differ from this value.
uint256 amountReceivedLD; // Amount of tokens to be received on the remote side.
}
/**
* @dev Struct representing OFT fee details.
* @dev Future proof mechanism to provide a standardized way to communicate fees to things like a UI.
*/
struct OFTFeeDetail {
int256 feeAmountLD; // Amount of the fee in local decimals.
string description; // Description of the fee.
}
/**
* @title IOFT
* @dev Interface for the OftChain (OFT) token.
* @dev Does not inherit ERC20 to accommodate usage by OFTAdapter as well.
* @dev This specific interface ID is '0x02e49c2c'.
*/
interface IOFT {
// Custom error messages
error InvalidLocalDecimals();
error SlippageExceeded(uint256 amountLD, uint256 minAmountLD);
// Events
event OFTSent(
// GUID of the OFT message.
// Destination Endpoint ID.
// Address of the sender on the src chain.
// Amount of tokens sent in local decimals.
// Amount of tokens received in local decimals.
bytes32 indexed guid,
uint32 dstEid,
address indexed fromAddress,
uint256 amountSentLD,
uint256 amountReceivedLD
);
event OFTReceived(
// GUID of the OFT message.
// Source Endpoint ID.
// Address of the recipient on the dst chain.
// Amount of tokens received in local decimals.
bytes32 indexed guid,
uint32 srcEid,
address indexed toAddress,
uint256 amountReceivedLD
);
/**
* @notice Retrieves interfaceID and the version of the OFT.
* @return interfaceId The interface ID.
* @return version The version.
*
* @dev interfaceId: This specific interface ID is '0x02e49c2c'.
* @dev version: Indicates a cross-chain compatible msg encoding with other OFTs.
* @dev If a new feature is added to the OFT cross-chain msg encoding, the version will be incremented.
* ie. localOFT version(x,1) CAN send messages to remoteOFT version(x,1)
*/
function oftVersion() external view returns (bytes4 interfaceId, uint64 version);
/**
* @notice Retrieves the address of the token associated with the OFT.
* @return token The address of the ERC20 token implementation.
*/
function token() external view returns (address);
/**
* @notice Indicates whether the OFT contract requires approval of the 'token()' to send.
* @return requiresApproval Needs approval of the underlying token implementation.
*
* @dev Allows things like wallet implementers to determine integration requirements,
* without understanding the underlying token implementation.
*/
function approvalRequired() external view returns (bool);
/**
* @notice Retrieves the shared decimals of the OFT.
* @return sharedDecimals The shared decimals of the OFT.
*/
function sharedDecimals() external view returns (uint8);
/**
* @notice Provides a quote for OFT-related operations.
* @param _sendParam The parameters for the send operation.
* @return limit The OFT limit information.
* @return oftFeeDetails The details of OFT fees.
* @return receipt The OFT receipt information.
*/
function quoteOFT(
SendParam calldata _sendParam
) external view returns (OFTLimit memory, OFTFeeDetail[] memory oftFeeDetails, OFTReceipt memory);
/**
* @notice Provides a quote for the send() operation.
* @param _sendParam The parameters for the send() operation.
* @param _payInLzToken Flag indicating whether the caller is paying in the LZ token.
* @return fee The calculated LayerZero messaging fee from the send() operation.
*
* @dev MessagingFee: LayerZero msg fee
* - nativeFee: The native fee.
* - lzTokenFee: The lzToken fee.
*/
function quoteSend(SendParam calldata _sendParam, bool _payInLzToken) external view returns (MessagingFee memory);
/**
* @notice Executes the send() operation.
* @param _sendParam The parameters for the send operation.
* @param _fee The fee information supplied by the caller.
* - nativeFee: The native fee.
* - lzTokenFee: The lzToken fee.
* @param _refundAddress The address to receive any excess funds from fees etc. on the src.
* @return receipt The LayerZero messaging receipt from the send() operation.
* @return oftReceipt The OFT receipt information.
*
* @dev MessagingReceipt: LayerZero msg receipt
* - guid: The unique identifier for the sent message.
* - nonce: The nonce of the sent message.
* - fee: The LayerZero fee incurred for the message.
*/
function send(
SendParam calldata _sendParam,
MessagingFee calldata _fee,
address _refundAddress
) external payable returns (MessagingReceipt memory, OFTReceipt memory);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IOFT2 {
function decimalConversionRate() external view returns (uint256);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC20Permit} from "../extensions/IERC20Permit.sol";
import {Address} from "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
/**
* @dev An operation with an ERC20 token failed.
*/
error SafeERC20FailedOperation(address token);
/**
* @dev Indicates a failed `decreaseAllowance` request.
*/
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
* value, non-reverting calls are assumed to be successful.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data);
if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
// and not revert is the subcall reverts.
(bool success, bytes memory returndata) = address(token).call(data);
return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface ILayerZeroDVN {
// @notice query the dvn fee for relaying block information to the destination chain
// @param _dstEid the destination endpoint identifier
// @param _confirmations - block confirmation delay before relaying blocks
// @param _sender - the source sending contract address
// @param _options - options
function getFee(
uint32 _dstEid,
uint64 _confirmations,
address _sender,
bytes calldata _options
) external view returns (uint256 fee);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface ILayerZeroTreasury {
function getFee(
address _sender,
uint32 _dstEid,
uint256 _totalNativeFee,
bool _payInLzToken
) external view returns (uint256 fee);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IExecutor {
// @notice query the executor price for relaying the payload and its proof to the destination chain
// @param _dstEid - the destination endpoint identifier
// @param _sender - the source sending contract address. executors may apply price discrimination to senders
// @param _calldataSize - dynamic data size of message + caller params
// @param _options - optional parameters for extra service plugins, e.g. sending dust tokens at the destination chain
function getFee(
uint32 _dstEid,
address _sender,
uint256 _calldataSize,
bytes calldata _options
) external view returns (uint256 price);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is set to the address provided by the deployer. This can
* later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: Unlicense /* * @title Solidity Bytes Arrays Utils * @author Gonçalo Sá <[email protected]> * * @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity. * The library lets you concatenate, slice and type cast bytes arrays both in memory and storage. */ pragma solidity >=0.8.0 <0.9.0; library BytesLib { function concat( bytes memory _preBytes, bytes memory _postBytes ) internal pure returns (bytes memory) { bytes memory tempBytes; assembly { // Get a location of some free memory and store it in tempBytes as // Solidity does for memory variables. tempBytes := mload(0x40) // Store the length of the first bytes array at the beginning of // the memory for tempBytes. let length := mload(_preBytes) mstore(tempBytes, length) // Maintain a memory counter for the current write location in the // temp bytes array by adding the 32 bytes for the array length to // the starting location. let mc := add(tempBytes, 0x20) // Stop copying when the memory counter reaches the length of the // first bytes array. let end := add(mc, length) for { // Initialize a copy counter to the start of the _preBytes data, // 32 bytes into its memory. let cc := add(_preBytes, 0x20) } lt(mc, end) { // Increase both counters by 32 bytes each iteration. mc := add(mc, 0x20) cc := add(cc, 0x20) } { // Write the _preBytes data into the tempBytes memory 32 bytes // at a time. mstore(mc, mload(cc)) } // Add the length of _postBytes to the current length of tempBytes // and store it as the new length in the first 32 bytes of the // tempBytes memory. length := mload(_postBytes) mstore(tempBytes, add(length, mload(tempBytes))) // Move the memory counter back from a multiple of 0x20 to the // actual end of the _preBytes data. mc := end // Stop copying when the memory counter reaches the new combined // length of the arrays. end := add(mc, length) for { let cc := add(_postBytes, 0x20) } lt(mc, end) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { mstore(mc, mload(cc)) } // Update the free-memory pointer by padding our last write location // to 32 bytes: add 31 bytes to the end of tempBytes to move to the // next 32 byte block, then round down to the nearest multiple of // 32. If the sum of the length of the two arrays is zero then add // one before rounding down to leave a blank 32 bytes (the length block with 0). mstore(0x40, and( add(add(end, iszero(add(length, mload(_preBytes)))), 31), not(31) // Round down to the nearest 32 bytes. )) } return tempBytes; } function concatStorage(bytes storage _preBytes, bytes memory _postBytes) internal { assembly { // Read the first 32 bytes of _preBytes storage, which is the length // of the array. (We don't need to use the offset into the slot // because arrays use the entire slot.) let fslot := sload(_preBytes.slot) // Arrays of 31 bytes or less have an even value in their slot, // while longer arrays have an odd value. The actual length is // the slot divided by two for odd values, and the lowest order // byte divided by two for even values. // If the slot is even, bitwise and the slot with 255 and divide by // two to get the length. If the slot is odd, bitwise and the slot // with -1 and divide by two. let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2) let mlength := mload(_postBytes) let newlength := add(slength, mlength) // slength can contain both the length and contents of the array // if length < 32 bytes so let's prepare for that // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage switch add(lt(slength, 32), lt(newlength, 32)) case 2 { // Since the new array still fits in the slot, we just need to // update the contents of the slot. // uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length sstore( _preBytes.slot, // all the modifications to the slot are inside this // next block add( // we can just add to the slot contents because the // bytes we want to change are the LSBs fslot, add( mul( div( // load the bytes from memory mload(add(_postBytes, 0x20)), // zero all bytes to the right exp(0x100, sub(32, mlength)) ), // and now shift left the number of bytes to // leave space for the length in the slot exp(0x100, sub(32, newlength)) ), // increase length by the double of the memory // bytes length mul(mlength, 2) ) ) ) } case 1 { // The stored value fits in the slot, but the combined value // will exceed it. // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) let sc := add(keccak256(0x0, 0x20), div(slength, 32)) // save new length sstore(_preBytes.slot, add(mul(newlength, 2), 1)) // The contents of the _postBytes array start 32 bytes into // the structure. Our first read should obtain the `submod` // bytes that can fit into the unused space in the last word // of the stored array. To get this, we read 32 bytes starting // from `submod`, so the data we read overlaps with the array // contents by `submod` bytes. Masking the lowest-order // `submod` bytes allows us to add that value directly to the // stored value. let submod := sub(32, slength) let mc := add(_postBytes, submod) let end := add(_postBytes, mlength) let mask := sub(exp(0x100, submod), 1) sstore( sc, add( and( fslot, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00 ), and(mload(mc), mask) ) ) for { mc := add(mc, 0x20) sc := add(sc, 1) } lt(mc, end) { sc := add(sc, 1) mc := add(mc, 0x20) } { sstore(sc, mload(mc)) } mask := exp(0x100, sub(mc, end)) sstore(sc, mul(div(mload(mc), mask), mask)) } default { // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) // Start copying to the last used word of the stored array. let sc := add(keccak256(0x0, 0x20), div(slength, 32)) // save new length sstore(_preBytes.slot, add(mul(newlength, 2), 1)) // Copy over the first `submod` bytes of the new data as in // case 1 above. let slengthmod := mod(slength, 32) let mlengthmod := mod(mlength, 32) let submod := sub(32, slengthmod) let mc := add(_postBytes, submod) let end := add(_postBytes, mlength) let mask := sub(exp(0x100, submod), 1) sstore(sc, add(sload(sc), and(mload(mc), mask))) for { sc := add(sc, 1) mc := add(mc, 0x20) } lt(mc, end) { sc := add(sc, 1) mc := add(mc, 0x20) } { sstore(sc, mload(mc)) } mask := exp(0x100, sub(mc, end)) sstore(sc, mul(div(mload(mc), mask), mask)) } } } function slice( bytes memory _bytes, uint256 _start, uint256 _length ) internal pure returns (bytes memory) { require(_length + 31 >= _length, "slice_overflow"); require(_bytes.length >= _start + _length, "slice_outOfBounds"); bytes memory tempBytes; assembly { switch iszero(_length) case 0 { // Get a location of some free memory and store it in tempBytes as // Solidity does for memory variables. tempBytes := mload(0x40) // The first word of the slice result is potentially a partial // word read from the original array. To read it, we calculate // the length of that partial word and start copying that many // bytes into the array. The first word we copy will start with // data we don't care about, but the last `lengthmod` bytes will // land at the beginning of the contents of the new array. When // we're done copying, we overwrite the full first word with // the actual length of the slice. let lengthmod := and(_length, 31) // The multiplication in the next line is necessary // because when slicing multiples of 32 bytes (lengthmod == 0) // the following copy loop was copying the origin's length // and then ending prematurely not copying everything it should. let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod))) let end := add(mc, _length) for { // The multiplication in the next line has the same exact purpose // as the one above. let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start) } lt(mc, end) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { mstore(mc, mload(cc)) } mstore(tempBytes, _length) //update free-memory pointer //allocating the array padded to 32 bytes like the compiler does now mstore(0x40, and(add(mc, 31), not(31))) } //if we want a zero-length slice let's just return a zero-length array default { tempBytes := mload(0x40) //zero out the 32 bytes slice we are about to return //we need to do it because Solidity does not garbage collect mstore(tempBytes, 0) mstore(0x40, add(tempBytes, 0x20)) } } return tempBytes; } function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) { require(_bytes.length >= _start + 20, "toAddress_outOfBounds"); address tempAddress; assembly { tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000) } return tempAddress; } function toUint8(bytes memory _bytes, uint256 _start) internal pure returns (uint8) { require(_bytes.length >= _start + 1 , "toUint8_outOfBounds"); uint8 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x1), _start)) } return tempUint; } function toUint16(bytes memory _bytes, uint256 _start) internal pure returns (uint16) { require(_bytes.length >= _start + 2, "toUint16_outOfBounds"); uint16 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x2), _start)) } return tempUint; } function toUint32(bytes memory _bytes, uint256 _start) internal pure returns (uint32) { require(_bytes.length >= _start + 4, "toUint32_outOfBounds"); uint32 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x4), _start)) } return tempUint; } function toUint64(bytes memory _bytes, uint256 _start) internal pure returns (uint64) { require(_bytes.length >= _start + 8, "toUint64_outOfBounds"); uint64 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x8), _start)) } return tempUint; } function toUint96(bytes memory _bytes, uint256 _start) internal pure returns (uint96) { require(_bytes.length >= _start + 12, "toUint96_outOfBounds"); uint96 tempUint; assembly { tempUint := mload(add(add(_bytes, 0xc), _start)) } return tempUint; } function toUint128(bytes memory _bytes, uint256 _start) internal pure returns (uint128) { require(_bytes.length >= _start + 16, "toUint128_outOfBounds"); uint128 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x10), _start)) } return tempUint; } function toUint256(bytes memory _bytes, uint256 _start) internal pure returns (uint256) { require(_bytes.length >= _start + 32, "toUint256_outOfBounds"); uint256 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x20), _start)) } return tempUint; } function toBytes32(bytes memory _bytes, uint256 _start) internal pure returns (bytes32) { require(_bytes.length >= _start + 32, "toBytes32_outOfBounds"); bytes32 tempBytes32; assembly { tempBytes32 := mload(add(add(_bytes, 0x20), _start)) } return tempBytes32; } function equal(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bool) { bool success = true; assembly { let length := mload(_preBytes) // if lengths don't match the arrays are not equal switch eq(length, mload(_postBytes)) case 1 { // cb is a circuit breaker in the for loop since there's // no said feature for inline assembly loops // cb = 1 - don't breaker // cb = 0 - break let cb := 1 let mc := add(_preBytes, 0x20) let end := add(mc, length) for { let cc := add(_postBytes, 0x20) // the next line is the loop condition: // while(uint256(mc < end) + cb == 2) } eq(add(lt(mc, end), cb), 2) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { // if any of these checks fails then arrays are not equal if iszero(eq(mload(mc), mload(cc))) { // unsuccess: success := 0 cb := 0 } } } default { // unsuccess: success := 0 } } return success; } function equal_nonAligned(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bool) { bool success = true; assembly { let length := mload(_preBytes) // if lengths don't match the arrays are not equal switch eq(length, mload(_postBytes)) case 1 { // cb is a circuit breaker in the for loop since there's // no said feature for inline assembly loops // cb = 1 - don't breaker // cb = 0 - break let cb := 1 let endMinusWord := add(_preBytes, length) let mc := add(_preBytes, 0x20) let cc := add(_postBytes, 0x20) for { // the next line is the loop condition: // while(uint256(mc < endWord) + cb == 2) } eq(add(lt(mc, endMinusWord), cb), 2) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { // if any of these checks fails then arrays are not equal if iszero(eq(mload(mc), mload(cc))) { // unsuccess: success := 0 cb := 0 } } // Only if still successful // For <1 word tail bytes if gt(success, 0) { // Get the remainder of length/32 // length % 32 = AND(length, 32 - 1) let numTailBytes := and(length, 0x1f) let mcRem := mload(mc) let ccRem := mload(cc) for { let i := 0 // the next line is the loop condition: // while(uint256(i < numTailBytes) + cb == 2) } eq(add(lt(i, numTailBytes), cb), 2) { i := add(i, 1) } { if iszero(eq(byte(i, mcRem), byte(i, ccRem))) { // unsuccess: success := 0 cb := 0 } } } } default { // unsuccess: success := 0 } } return success; } function equalStorage( bytes storage _preBytes, bytes memory _postBytes ) internal view returns (bool) { bool success = true; assembly { // we know _preBytes_offset is 0 let fslot := sload(_preBytes.slot) // Decode the length of the stored array like in concatStorage(). let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2) let mlength := mload(_postBytes) // if lengths don't match the arrays are not equal switch eq(slength, mlength) case 1 { // slength can contain both the length and contents of the array // if length < 32 bytes so let's prepare for that // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage if iszero(iszero(slength)) { switch lt(slength, 32) case 1 { // blank the last byte which is the length fslot := mul(div(fslot, 0x100), 0x100) if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) { // unsuccess: success := 0 } } default { // cb is a circuit breaker in the for loop since there's // no said feature for inline assembly loops // cb = 1 - don't breaker // cb = 0 - break let cb := 1 // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) let sc := keccak256(0x0, 0x20) let mc := add(_postBytes, 0x20) let end := add(mc, mlength) // the next line is the loop condition: // while(uint256(mc < end) + cb == 2) for {} eq(add(lt(mc, end), cb), 2) { sc := add(sc, 1) mc := add(mc, 0x20) } { if iszero(eq(sload(sc), mload(mc))) { // unsuccess: success := 0 cb := 0 } } } } } default { // unsuccess: success := 0 } } return success; } }
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.
pragma solidity ^0.8.20;
/**
* @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
* checks.
*
* Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
* easily result in undesired exploitation or bugs, since developers usually
* assume that overflows raise errors. `SafeCast` restores this intuition by
* reverting the transaction when such an operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeCast {
/**
* @dev Value doesn't fit in an uint of `bits` size.
*/
error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);
/**
* @dev An int value doesn't fit in an uint of `bits` size.
*/
error SafeCastOverflowedIntToUint(int256 value);
/**
* @dev Value doesn't fit in an int of `bits` size.
*/
error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);
/**
* @dev An uint value doesn't fit in an int of `bits` size.
*/
error SafeCastOverflowedUintToInt(uint256 value);
/**
* @dev Returns the downcasted uint248 from uint256, reverting on
* overflow (when the input is greater than largest uint248).
*
* Counterpart to Solidity's `uint248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*/
function toUint248(uint256 value) internal pure returns (uint248) {
if (value > type(uint248).max) {
revert SafeCastOverflowedUintDowncast(248, value);
}
return uint248(value);
}
/**
* @dev Returns the downcasted uint240 from uint256, reverting on
* overflow (when the input is greater than largest uint240).
*
* Counterpart to Solidity's `uint240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*/
function toUint240(uint256 value) internal pure returns (uint240) {
if (value > type(uint240).max) {
revert SafeCastOverflowedUintDowncast(240, value);
}
return uint240(value);
}
/**
* @dev Returns the downcasted uint232 from uint256, reverting on
* overflow (when the input is greater than largest uint232).
*
* Counterpart to Solidity's `uint232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*/
function toUint232(uint256 value) internal pure returns (uint232) {
if (value > type(uint232).max) {
revert SafeCastOverflowedUintDowncast(232, value);
}
return uint232(value);
}
/**
* @dev Returns the downcasted uint224 from uint256, reverting on
* overflow (when the input is greater than largest uint224).
*
* Counterpart to Solidity's `uint224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*/
function toUint224(uint256 value) internal pure returns (uint224) {
if (value > type(uint224).max) {
revert SafeCastOverflowedUintDowncast(224, value);
}
return uint224(value);
}
/**
* @dev Returns the downcasted uint216 from uint256, reverting on
* overflow (when the input is greater than largest uint216).
*
* Counterpart to Solidity's `uint216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*/
function toUint216(uint256 value) internal pure returns (uint216) {
if (value > type(uint216).max) {
revert SafeCastOverflowedUintDowncast(216, value);
}
return uint216(value);
}
/**
* @dev Returns the downcasted uint208 from uint256, reverting on
* overflow (when the input is greater than largest uint208).
*
* Counterpart to Solidity's `uint208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*/
function toUint208(uint256 value) internal pure returns (uint208) {
if (value > type(uint208).max) {
revert SafeCastOverflowedUintDowncast(208, value);
}
return uint208(value);
}
/**
* @dev Returns the downcasted uint200 from uint256, reverting on
* overflow (when the input is greater than largest uint200).
*
* Counterpart to Solidity's `uint200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*/
function toUint200(uint256 value) internal pure returns (uint200) {
if (value > type(uint200).max) {
revert SafeCastOverflowedUintDowncast(200, value);
}
return uint200(value);
}
/**
* @dev Returns the downcasted uint192 from uint256, reverting on
* overflow (when the input is greater than largest uint192).
*
* Counterpart to Solidity's `uint192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*/
function toUint192(uint256 value) internal pure returns (uint192) {
if (value > type(uint192).max) {
revert SafeCastOverflowedUintDowncast(192, value);
}
return uint192(value);
}
/**
* @dev Returns the downcasted uint184 from uint256, reverting on
* overflow (when the input is greater than largest uint184).
*
* Counterpart to Solidity's `uint184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*/
function toUint184(uint256 value) internal pure returns (uint184) {
if (value > type(uint184).max) {
revert SafeCastOverflowedUintDowncast(184, value);
}
return uint184(value);
}
/**
* @dev Returns the downcasted uint176 from uint256, reverting on
* overflow (when the input is greater than largest uint176).
*
* Counterpart to Solidity's `uint176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*/
function toUint176(uint256 value) internal pure returns (uint176) {
if (value > type(uint176).max) {
revert SafeCastOverflowedUintDowncast(176, value);
}
return uint176(value);
}
/**
* @dev Returns the downcasted uint168 from uint256, reverting on
* overflow (when the input is greater than largest uint168).
*
* Counterpart to Solidity's `uint168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*/
function toUint168(uint256 value) internal pure returns (uint168) {
if (value > type(uint168).max) {
revert SafeCastOverflowedUintDowncast(168, value);
}
return uint168(value);
}
/**
* @dev Returns the downcasted uint160 from uint256, reverting on
* overflow (when the input is greater than largest uint160).
*
* Counterpart to Solidity's `uint160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*/
function toUint160(uint256 value) internal pure returns (uint160) {
if (value > type(uint160).max) {
revert SafeCastOverflowedUintDowncast(160, value);
}
return uint160(value);
}
/**
* @dev Returns the downcasted uint152 from uint256, reverting on
* overflow (when the input is greater than largest uint152).
*
* Counterpart to Solidity's `uint152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*/
function toUint152(uint256 value) internal pure returns (uint152) {
if (value > type(uint152).max) {
revert SafeCastOverflowedUintDowncast(152, value);
}
return uint152(value);
}
/**
* @dev Returns the downcasted uint144 from uint256, reverting on
* overflow (when the input is greater than largest uint144).
*
* Counterpart to Solidity's `uint144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*/
function toUint144(uint256 value) internal pure returns (uint144) {
if (value > type(uint144).max) {
revert SafeCastOverflowedUintDowncast(144, value);
}
return uint144(value);
}
/**
* @dev Returns the downcasted uint136 from uint256, reverting on
* overflow (when the input is greater than largest uint136).
*
* Counterpart to Solidity's `uint136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*/
function toUint136(uint256 value) internal pure returns (uint136) {
if (value > type(uint136).max) {
revert SafeCastOverflowedUintDowncast(136, value);
}
return uint136(value);
}
/**
* @dev Returns the downcasted uint128 from uint256, reverting on
* overflow (when the input is greater than largest uint128).
*
* Counterpart to Solidity's `uint128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*/
function toUint128(uint256 value) internal pure returns (uint128) {
if (value > type(uint128).max) {
revert SafeCastOverflowedUintDowncast(128, value);
}
return uint128(value);
}
/**
* @dev Returns the downcasted uint120 from uint256, reverting on
* overflow (when the input is greater than largest uint120).
*
* Counterpart to Solidity's `uint120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*/
function toUint120(uint256 value) internal pure returns (uint120) {
if (value > type(uint120).max) {
revert SafeCastOverflowedUintDowncast(120, value);
}
return uint120(value);
}
/**
* @dev Returns the downcasted uint112 from uint256, reverting on
* overflow (when the input is greater than largest uint112).
*
* Counterpart to Solidity's `uint112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*/
function toUint112(uint256 value) internal pure returns (uint112) {
if (value > type(uint112).max) {
revert SafeCastOverflowedUintDowncast(112, value);
}
return uint112(value);
}
/**
* @dev Returns the downcasted uint104 from uint256, reverting on
* overflow (when the input is greater than largest uint104).
*
* Counterpart to Solidity's `uint104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*/
function toUint104(uint256 value) internal pure returns (uint104) {
if (value > type(uint104).max) {
revert SafeCastOverflowedUintDowncast(104, value);
}
return uint104(value);
}
/**
* @dev Returns the downcasted uint96 from uint256, reverting on
* overflow (when the input is greater than largest uint96).
*
* Counterpart to Solidity's `uint96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*/
function toUint96(uint256 value) internal pure returns (uint96) {
if (value > type(uint96).max) {
revert SafeCastOverflowedUintDowncast(96, value);
}
return uint96(value);
}
/**
* @dev Returns the downcasted uint88 from uint256, reverting on
* overflow (when the input is greater than largest uint88).
*
* Counterpart to Solidity's `uint88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*/
function toUint88(uint256 value) internal pure returns (uint88) {
if (value > type(uint88).max) {
revert SafeCastOverflowedUintDowncast(88, value);
}
return uint88(value);
}
/**
* @dev Returns the downcasted uint80 from uint256, reverting on
* overflow (when the input is greater than largest uint80).
*
* Counterpart to Solidity's `uint80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*/
function toUint80(uint256 value) internal pure returns (uint80) {
if (value > type(uint80).max) {
revert SafeCastOverflowedUintDowncast(80, value);
}
return uint80(value);
}
/**
* @dev Returns the downcasted uint72 from uint256, reverting on
* overflow (when the input is greater than largest uint72).
*
* Counterpart to Solidity's `uint72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*/
function toUint72(uint256 value) internal pure returns (uint72) {
if (value > type(uint72).max) {
revert SafeCastOverflowedUintDowncast(72, value);
}
return uint72(value);
}
/**
* @dev Returns the downcasted uint64 from uint256, reverting on
* overflow (when the input is greater than largest uint64).
*
* Counterpart to Solidity's `uint64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*/
function toUint64(uint256 value) internal pure returns (uint64) {
if (value > type(uint64).max) {
revert SafeCastOverflowedUintDowncast(64, value);
}
return uint64(value);
}
/**
* @dev Returns the downcasted uint56 from uint256, reverting on
* overflow (when the input is greater than largest uint56).
*
* Counterpart to Solidity's `uint56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*/
function toUint56(uint256 value) internal pure returns (uint56) {
if (value > type(uint56).max) {
revert SafeCastOverflowedUintDowncast(56, value);
}
return uint56(value);
}
/**
* @dev Returns the downcasted uint48 from uint256, reverting on
* overflow (when the input is greater than largest uint48).
*
* Counterpart to Solidity's `uint48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*/
function toUint48(uint256 value) internal pure returns (uint48) {
if (value > type(uint48).max) {
revert SafeCastOverflowedUintDowncast(48, value);
}
return uint48(value);
}
/**
* @dev Returns the downcasted uint40 from uint256, reverting on
* overflow (when the input is greater than largest uint40).
*
* Counterpart to Solidity's `uint40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*/
function toUint40(uint256 value) internal pure returns (uint40) {
if (value > type(uint40).max) {
revert SafeCastOverflowedUintDowncast(40, value);
}
return uint40(value);
}
/**
* @dev Returns the downcasted uint32 from uint256, reverting on
* overflow (when the input is greater than largest uint32).
*
* Counterpart to Solidity's `uint32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*/
function toUint32(uint256 value) internal pure returns (uint32) {
if (value > type(uint32).max) {
revert SafeCastOverflowedUintDowncast(32, value);
}
return uint32(value);
}
/**
* @dev Returns the downcasted uint24 from uint256, reverting on
* overflow (when the input is greater than largest uint24).
*
* Counterpart to Solidity's `uint24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*/
function toUint24(uint256 value) internal pure returns (uint24) {
if (value > type(uint24).max) {
revert SafeCastOverflowedUintDowncast(24, value);
}
return uint24(value);
}
/**
* @dev Returns the downcasted uint16 from uint256, reverting on
* overflow (when the input is greater than largest uint16).
*
* Counterpart to Solidity's `uint16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*/
function toUint16(uint256 value) internal pure returns (uint16) {
if (value > type(uint16).max) {
revert SafeCastOverflowedUintDowncast(16, value);
}
return uint16(value);
}
/**
* @dev Returns the downcasted uint8 from uint256, reverting on
* overflow (when the input is greater than largest uint8).
*
* Counterpart to Solidity's `uint8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*/
function toUint8(uint256 value) internal pure returns (uint8) {
if (value > type(uint8).max) {
revert SafeCastOverflowedUintDowncast(8, value);
}
return uint8(value);
}
/**
* @dev Converts a signed int256 into an unsigned uint256.
*
* Requirements:
*
* - input must be greater than or equal to 0.
*/
function toUint256(int256 value) internal pure returns (uint256) {
if (value < 0) {
revert SafeCastOverflowedIntToUint(value);
}
return uint256(value);
}
/**
* @dev Returns the downcasted int248 from int256, reverting on
* overflow (when the input is less than smallest int248 or
* greater than largest int248).
*
* Counterpart to Solidity's `int248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*/
function toInt248(int256 value) internal pure returns (int248 downcasted) {
downcasted = int248(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(248, value);
}
}
/**
* @dev Returns the downcasted int240 from int256, reverting on
* overflow (when the input is less than smallest int240 or
* greater than largest int240).
*
* Counterpart to Solidity's `int240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*/
function toInt240(int256 value) internal pure returns (int240 downcasted) {
downcasted = int240(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(240, value);
}
}
/**
* @dev Returns the downcasted int232 from int256, reverting on
* overflow (when the input is less than smallest int232 or
* greater than largest int232).
*
* Counterpart to Solidity's `int232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*/
function toInt232(int256 value) internal pure returns (int232 downcasted) {
downcasted = int232(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(232, value);
}
}
/**
* @dev Returns the downcasted int224 from int256, reverting on
* overflow (when the input is less than smallest int224 or
* greater than largest int224).
*
* Counterpart to Solidity's `int224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*/
function toInt224(int256 value) internal pure returns (int224 downcasted) {
downcasted = int224(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(224, value);
}
}
/**
* @dev Returns the downcasted int216 from int256, reverting on
* overflow (when the input is less than smallest int216 or
* greater than largest int216).
*
* Counterpart to Solidity's `int216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*/
function toInt216(int256 value) internal pure returns (int216 downcasted) {
downcasted = int216(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(216, value);
}
}
/**
* @dev Returns the downcasted int208 from int256, reverting on
* overflow (when the input is less than smallest int208 or
* greater than largest int208).
*
* Counterpart to Solidity's `int208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*/
function toInt208(int256 value) internal pure returns (int208 downcasted) {
downcasted = int208(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(208, value);
}
}
/**
* @dev Returns the downcasted int200 from int256, reverting on
* overflow (when the input is less than smallest int200 or
* greater than largest int200).
*
* Counterpart to Solidity's `int200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*/
function toInt200(int256 value) internal pure returns (int200 downcasted) {
downcasted = int200(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(200, value);
}
}
/**
* @dev Returns the downcasted int192 from int256, reverting on
* overflow (when the input is less than smallest int192 or
* greater than largest int192).
*
* Counterpart to Solidity's `int192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*/
function toInt192(int256 value) internal pure returns (int192 downcasted) {
downcasted = int192(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(192, value);
}
}
/**
* @dev Returns the downcasted int184 from int256, reverting on
* overflow (when the input is less than smallest int184 or
* greater than largest int184).
*
* Counterpart to Solidity's `int184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*/
function toInt184(int256 value) internal pure returns (int184 downcasted) {
downcasted = int184(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(184, value);
}
}
/**
* @dev Returns the downcasted int176 from int256, reverting on
* overflow (when the input is less than smallest int176 or
* greater than largest int176).
*
* Counterpart to Solidity's `int176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*/
function toInt176(int256 value) internal pure returns (int176 downcasted) {
downcasted = int176(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(176, value);
}
}
/**
* @dev Returns the downcasted int168 from int256, reverting on
* overflow (when the input is less than smallest int168 or
* greater than largest int168).
*
* Counterpart to Solidity's `int168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*/
function toInt168(int256 value) internal pure returns (int168 downcasted) {
downcasted = int168(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(168, value);
}
}
/**
* @dev Returns the downcasted int160 from int256, reverting on
* overflow (when the input is less than smallest int160 or
* greater than largest int160).
*
* Counterpart to Solidity's `int160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*/
function toInt160(int256 value) internal pure returns (int160 downcasted) {
downcasted = int160(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(160, value);
}
}
/**
* @dev Returns the downcasted int152 from int256, reverting on
* overflow (when the input is less than smallest int152 or
* greater than largest int152).
*
* Counterpart to Solidity's `int152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*/
function toInt152(int256 value) internal pure returns (int152 downcasted) {
downcasted = int152(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(152, value);
}
}
/**
* @dev Returns the downcasted int144 from int256, reverting on
* overflow (when the input is less than smallest int144 or
* greater than largest int144).
*
* Counterpart to Solidity's `int144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*/
function toInt144(int256 value) internal pure returns (int144 downcasted) {
downcasted = int144(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(144, value);
}
}
/**
* @dev Returns the downcasted int136 from int256, reverting on
* overflow (when the input is less than smallest int136 or
* greater than largest int136).
*
* Counterpart to Solidity's `int136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*/
function toInt136(int256 value) internal pure returns (int136 downcasted) {
downcasted = int136(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(136, value);
}
}
/**
* @dev Returns the downcasted int128 from int256, reverting on
* overflow (when the input is less than smallest int128 or
* greater than largest int128).
*
* Counterpart to Solidity's `int128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*/
function toInt128(int256 value) internal pure returns (int128 downcasted) {
downcasted = int128(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(128, value);
}
}
/**
* @dev Returns the downcasted int120 from int256, reverting on
* overflow (when the input is less than smallest int120 or
* greater than largest int120).
*
* Counterpart to Solidity's `int120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*/
function toInt120(int256 value) internal pure returns (int120 downcasted) {
downcasted = int120(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(120, value);
}
}
/**
* @dev Returns the downcasted int112 from int256, reverting on
* overflow (when the input is less than smallest int112 or
* greater than largest int112).
*
* Counterpart to Solidity's `int112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*/
function toInt112(int256 value) internal pure returns (int112 downcasted) {
downcasted = int112(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(112, value);
}
}
/**
* @dev Returns the downcasted int104 from int256, reverting on
* overflow (when the input is less than smallest int104 or
* greater than largest int104).
*
* Counterpart to Solidity's `int104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*/
function toInt104(int256 value) internal pure returns (int104 downcasted) {
downcasted = int104(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(104, value);
}
}
/**
* @dev Returns the downcasted int96 from int256, reverting on
* overflow (when the input is less than smallest int96 or
* greater than largest int96).
*
* Counterpart to Solidity's `int96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*/
function toInt96(int256 value) internal pure returns (int96 downcasted) {
downcasted = int96(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(96, value);
}
}
/**
* @dev Returns the downcasted int88 from int256, reverting on
* overflow (when the input is less than smallest int88 or
* greater than largest int88).
*
* Counterpart to Solidity's `int88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*/
function toInt88(int256 value) internal pure returns (int88 downcasted) {
downcasted = int88(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(88, value);
}
}
/**
* @dev Returns the downcasted int80 from int256, reverting on
* overflow (when the input is less than smallest int80 or
* greater than largest int80).
*
* Counterpart to Solidity's `int80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*/
function toInt80(int256 value) internal pure returns (int80 downcasted) {
downcasted = int80(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(80, value);
}
}
/**
* @dev Returns the downcasted int72 from int256, reverting on
* overflow (when the input is less than smallest int72 or
* greater than largest int72).
*
* Counterpart to Solidity's `int72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*/
function toInt72(int256 value) internal pure returns (int72 downcasted) {
downcasted = int72(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(72, value);
}
}
/**
* @dev Returns the downcasted int64 from int256, reverting on
* overflow (when the input is less than smallest int64 or
* greater than largest int64).
*
* Counterpart to Solidity's `int64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*/
function toInt64(int256 value) internal pure returns (int64 downcasted) {
downcasted = int64(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(64, value);
}
}
/**
* @dev Returns the downcasted int56 from int256, reverting on
* overflow (when the input is less than smallest int56 or
* greater than largest int56).
*
* Counterpart to Solidity's `int56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*/
function toInt56(int256 value) internal pure returns (int56 downcasted) {
downcasted = int56(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(56, value);
}
}
/**
* @dev Returns the downcasted int48 from int256, reverting on
* overflow (when the input is less than smallest int48 or
* greater than largest int48).
*
* Counterpart to Solidity's `int48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*/
function toInt48(int256 value) internal pure returns (int48 downcasted) {
downcasted = int48(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(48, value);
}
}
/**
* @dev Returns the downcasted int40 from int256, reverting on
* overflow (when the input is less than smallest int40 or
* greater than largest int40).
*
* Counterpart to Solidity's `int40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*/
function toInt40(int256 value) internal pure returns (int40 downcasted) {
downcasted = int40(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(40, value);
}
}
/**
* @dev Returns the downcasted int32 from int256, reverting on
* overflow (when the input is less than smallest int32 or
* greater than largest int32).
*
* Counterpart to Solidity's `int32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*/
function toInt32(int256 value) internal pure returns (int32 downcasted) {
downcasted = int32(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(32, value);
}
}
/**
* @dev Returns the downcasted int24 from int256, reverting on
* overflow (when the input is less than smallest int24 or
* greater than largest int24).
*
* Counterpart to Solidity's `int24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*/
function toInt24(int256 value) internal pure returns (int24 downcasted) {
downcasted = int24(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(24, value);
}
}
/**
* @dev Returns the downcasted int16 from int256, reverting on
* overflow (when the input is less than smallest int16 or
* greater than largest int16).
*
* Counterpart to Solidity's `int16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*/
function toInt16(int256 value) internal pure returns (int16 downcasted) {
downcasted = int16(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(16, value);
}
}
/**
* @dev Returns the downcasted int8 from int256, reverting on
* overflow (when the input is less than smallest int8 or
* greater than largest int8).
*
* Counterpart to Solidity's `int8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*/
function toInt8(int256 value) internal pure returns (int8 downcasted) {
downcasted = int8(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(8, value);
}
}
/**
* @dev Converts an unsigned uint256 into a signed int256.
*
* Requirements:
*
* - input must be less than or equal to maxInt256.
*/
function toInt256(uint256 value) internal pure returns (int256) {
// Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
if (value > uint256(type(int256).max)) {
revert SafeCastOverflowedUintToInt(value);
}
return int256(value);
}
}// SPDX-License-Identifier: LZBL-1.2
pragma solidity ^0.8.20;
import { CalldataBytesLib } from "../../libs/CalldataBytesLib.sol";
library ExecutorOptions {
using CalldataBytesLib for bytes;
uint8 internal constant WORKER_ID = 1;
uint8 internal constant OPTION_TYPE_LZRECEIVE = 1;
uint8 internal constant OPTION_TYPE_NATIVE_DROP = 2;
uint8 internal constant OPTION_TYPE_LZCOMPOSE = 3;
uint8 internal constant OPTION_TYPE_ORDERED_EXECUTION = 4;
error Executor_InvalidLzReceiveOption();
error Executor_InvalidNativeDropOption();
error Executor_InvalidLzComposeOption();
/// @dev decode the next executor option from the options starting from the specified cursor
/// @param _options [executor_id][executor_option][executor_id][executor_option]...
/// executor_option = [option_size][option_type][option]
/// option_size = len(option_type) + len(option)
/// executor_id: uint8, option_size: uint16, option_type: uint8, option: bytes
/// @param _cursor the cursor to start decoding from
/// @return optionType the type of the option
/// @return option the option of the executor
/// @return cursor the cursor to start decoding the next executor option
function nextExecutorOption(
bytes calldata _options,
uint256 _cursor
) internal pure returns (uint8 optionType, bytes calldata option, uint256 cursor) {
unchecked {
// skip worker id
cursor = _cursor + 1;
// read option size
uint16 size = _options.toU16(cursor);
cursor += 2;
// read option type
optionType = _options.toU8(cursor);
// startCursor and endCursor are used to slice the option from _options
uint256 startCursor = cursor + 1; // skip option type
uint256 endCursor = cursor + size;
option = _options[startCursor:endCursor];
cursor += size;
}
}
function decodeLzReceiveOption(bytes calldata _option) internal pure returns (uint128 gas, uint128 value) {
if (_option.length != 16 && _option.length != 32) revert Executor_InvalidLzReceiveOption();
gas = _option.toU128(0);
value = _option.length == 32 ? _option.toU128(16) : 0;
}
function decodeNativeDropOption(bytes calldata _option) internal pure returns (uint128 amount, bytes32 receiver) {
if (_option.length != 48) revert Executor_InvalidNativeDropOption();
amount = _option.toU128(0);
receiver = _option.toB32(16);
}
function decodeLzComposeOption(
bytes calldata _option
) internal pure returns (uint16 index, uint128 gas, uint128 value) {
if (_option.length != 18 && _option.length != 34) revert Executor_InvalidLzComposeOption();
index = _option.toU16(0);
gas = _option.toU128(2);
value = _option.length == 34 ? _option.toU128(18) : 0;
}
function encodeLzReceiveOption(uint128 _gas, uint128 _value) internal pure returns (bytes memory) {
return _value == 0 ? abi.encodePacked(_gas) : abi.encodePacked(_gas, _value);
}
function encodeNativeDropOption(uint128 _amount, bytes32 _receiver) internal pure returns (bytes memory) {
return abi.encodePacked(_amount, _receiver);
}
function encodeLzComposeOption(uint16 _index, uint128 _gas, uint128 _value) internal pure returns (bytes memory) {
return _value == 0 ? abi.encodePacked(_index, _gas) : abi.encodePacked(_index, _gas, _value);
}
}// SPDX-License-Identifier: LZBL-1.2
pragma solidity ^0.8.20;
import { BytesLib } from "solidity-bytes-utils/contracts/BytesLib.sol";
import { BitMap256 } from "@layerzerolabs/lz-evm-protocol-v2/contracts/messagelib/libs/BitMaps.sol";
import { CalldataBytesLib } from "@layerzerolabs/lz-evm-protocol-v2/contracts/libs/CalldataBytesLib.sol";
library DVNOptions {
using CalldataBytesLib for bytes;
using BytesLib for bytes;
uint8 internal constant WORKER_ID = 2;
uint8 internal constant OPTION_TYPE_PRECRIME = 1;
error DVN_InvalidDVNIdx();
error DVN_InvalidDVNOptions(uint256 cursor);
/// @dev group dvn options by its idx
/// @param _options [dvn_id][dvn_option][dvn_id][dvn_option]...
/// dvn_option = [option_size][dvn_idx][option_type][option]
/// option_size = len(dvn_idx) + len(option_type) + len(option)
/// dvn_id: uint8, dvn_idx: uint8, option_size: uint16, option_type: uint8, option: bytes
/// @return dvnOptions the grouped options, still share the same format of _options
/// @return dvnIndices the dvn indices
function groupDVNOptionsByIdx(
bytes memory _options
) internal pure returns (bytes[] memory dvnOptions, uint8[] memory dvnIndices) {
if (_options.length == 0) return (dvnOptions, dvnIndices);
uint8 numDVNs = getNumDVNs(_options);
// if there is only 1 dvn, we can just return the whole options
if (numDVNs == 1) {
dvnOptions = new bytes[](1);
dvnOptions[0] = _options;
dvnIndices = new uint8[](1);
dvnIndices[0] = _options.toUint8(3); // dvn idx
return (dvnOptions, dvnIndices);
}
// otherwise, we need to group the options by dvn_idx
dvnIndices = new uint8[](numDVNs);
dvnOptions = new bytes[](numDVNs);
unchecked {
uint256 cursor = 0;
uint256 start = 0;
uint8 lastDVNIdx = 255; // 255 is an invalid dvn_idx
while (cursor < _options.length) {
++cursor; // skip worker_id
// optionLength asserted in getNumDVNs (skip check)
uint16 optionLength = _options.toUint16(cursor);
cursor += 2;
// dvnIdx asserted in getNumDVNs (skip check)
uint8 dvnIdx = _options.toUint8(cursor);
// dvnIdx must equal to the lastDVNIdx for the first option
// so it is always skipped in the first option
// this operation slices out options whenever the scan finds a different lastDVNIdx
if (lastDVNIdx == 255) {
lastDVNIdx = dvnIdx;
} else if (dvnIdx != lastDVNIdx) {
uint256 len = cursor - start - 3; // 3 is for worker_id and option_length
bytes memory opt = _options.slice(start, len);
_insertDVNOptions(dvnOptions, dvnIndices, lastDVNIdx, opt);
// reset the start and lastDVNIdx
start += len;
lastDVNIdx = dvnIdx;
}
cursor += optionLength;
}
// skip check the cursor here because the cursor is asserted in getNumDVNs
// if we have reached the end of the options, we need to process the last dvn
uint256 size = cursor - start;
bytes memory op = _options.slice(start, size);
_insertDVNOptions(dvnOptions, dvnIndices, lastDVNIdx, op);
// revert dvnIndices to start from 0
for (uint8 i = 0; i < numDVNs; ++i) {
--dvnIndices[i];
}
}
}
function _insertDVNOptions(
bytes[] memory _dvnOptions,
uint8[] memory _dvnIndices,
uint8 _dvnIdx,
bytes memory _newOptions
) internal pure {
// dvnIdx starts from 0 but default value of dvnIndices is 0,
// so we tell if the slot is empty by adding 1 to dvnIdx
if (_dvnIdx == 255) revert DVN_InvalidDVNIdx();
uint8 dvnIdxAdj = _dvnIdx + 1;
for (uint256 j = 0; j < _dvnIndices.length; ++j) {
uint8 index = _dvnIndices[j];
if (dvnIdxAdj == index) {
_dvnOptions[j] = abi.encodePacked(_dvnOptions[j], _newOptions);
break;
} else if (index == 0) {
// empty slot, that means it is the first time we see this dvn
_dvnIndices[j] = dvnIdxAdj;
_dvnOptions[j] = _newOptions;
break;
}
}
}
/// @dev get the number of unique dvns
/// @param _options the format is the same as groupDVNOptionsByIdx
function getNumDVNs(bytes memory _options) internal pure returns (uint8 numDVNs) {
uint256 cursor = 0;
BitMap256 bitmap;
// find number of unique dvn_idx
unchecked {
while (cursor < _options.length) {
++cursor; // skip worker_id
uint16 optionLength = _options.toUint16(cursor);
cursor += 2;
if (optionLength < 2) revert DVN_InvalidDVNOptions(cursor); // at least 1 byte for dvn_idx and 1 byte for option_type
uint8 dvnIdx = _options.toUint8(cursor);
// if dvnIdx is not set, increment numDVNs
// max num of dvns is 255, 255 is an invalid dvn_idx
// The order of the dvnIdx is not required to be sequential, as enforcing the order may weaken
// the composability of the options. e.g. if we refrain from enforcing the order, an OApp that has
// already enforced certain options can append additional options to the end of the enforced
// ones without restrictions.
if (dvnIdx == 255) revert DVN_InvalidDVNIdx();
if (!bitmap.get(dvnIdx)) {
++numDVNs;
bitmap = bitmap.set(dvnIdx);
}
cursor += optionLength;
}
}
if (cursor != _options.length) revert DVN_InvalidDVNOptions(cursor);
}
/// @dev decode the next dvn option from _options starting from the specified cursor
/// @param _options the format is the same as groupDVNOptionsByIdx
/// @param _cursor the cursor to start decoding
/// @return optionType the type of the option
/// @return option the option
/// @return cursor the cursor to start decoding the next option
function nextDVNOption(
bytes calldata _options,
uint256 _cursor
) internal pure returns (uint8 optionType, bytes calldata option, uint256 cursor) {
unchecked {
// skip worker id
cursor = _cursor + 1;
// read option size
uint16 size = _options.toU16(cursor);
cursor += 2;
// read option type
optionType = _options.toU8(cursor + 1); // skip dvn_idx
// startCursor and endCursor are used to slice the option from _options
uint256 startCursor = cursor + 2; // skip option type and dvn_idx
uint256 endCursor = cursor + size;
option = _options[startCursor:endCursor];
cursor += size;
}
}
}// 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 { OAppCoreUpgradeable } from "./OAppCoreUpgradeable.sol";
/**
* @title OAppSender
* @dev Abstract contract implementing the OAppSender functionality for sending messages to a LayerZero endpoint.
*/
abstract contract OAppSenderUpgradeable is OAppCoreUpgradeable {
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;
/**
* @dev Ownable is not initialized here on purpose. It should be initialized in the child contract to
* accommodate the different version of Ownable.
*/
function __OAppSender_init() internal onlyInitializing {}
function __OAppSender_init_unchained() internal onlyInitializing {}
/**
* @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
endpoint.send{ value: messageValue }(
// solhint-disable-next-line check-send-result
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 v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*
* ==== Security Considerations
*
* There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
* expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
* considered as an intention to spend the allowance in any specific way. The second is that because permits have
* built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
* take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
* generally recommended is:
*
* ```solidity
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
* try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
* doThing(..., value);
* }
*
* function doThing(..., uint256 value) public {
* token.safeTransferFrom(msg.sender, address(this), value);
* ...
* }
* ```
*
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
* `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
* {SafeERC20-safeTransferFrom}).
*
* Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
* contracts should have entry points that don't rely on permit.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*
* CAUTION: See Security Considerations above.
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)
pragma solidity ^0.8.20;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/
error AddressInsufficientBalance(address account);
/**
* @dev There's no code at `target` (it is not a contract).
*/
error AddressEmptyCode(address target);
/**
* @dev A call to an address target failed. The target may have reverted.
*/
error FailedInnerCall();
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert AddressInsufficientBalance(address(this));
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert FailedInnerCall();
}
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason or custom error, it is bubbled
* up by this function (like regular Solidity function calls). However, if
* the call reverted with no returned reason, this function reverts with a
* {FailedInnerCall} error.
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert AddressInsufficientBalance(address(this));
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
* was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
* unsuccessful call.
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
// only check if target is a contract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
/**
* @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
* revert reason or with a default {FailedInnerCall} error.
*/
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
/**
* @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
*/
function _revert(bytes memory returndata) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert FailedInnerCall();
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: LZBL-1.2
pragma solidity ^0.8.20;
library CalldataBytesLib {
function toU8(bytes calldata _bytes, uint256 _start) internal pure returns (uint8) {
return uint8(_bytes[_start]);
}
function toU16(bytes calldata _bytes, uint256 _start) internal pure returns (uint16) {
unchecked {
uint256 end = _start + 2;
return uint16(bytes2(_bytes[_start:end]));
}
}
function toU32(bytes calldata _bytes, uint256 _start) internal pure returns (uint32) {
unchecked {
uint256 end = _start + 4;
return uint32(bytes4(_bytes[_start:end]));
}
}
function toU64(bytes calldata _bytes, uint256 _start) internal pure returns (uint64) {
unchecked {
uint256 end = _start + 8;
return uint64(bytes8(_bytes[_start:end]));
}
}
function toU128(bytes calldata _bytes, uint256 _start) internal pure returns (uint128) {
unchecked {
uint256 end = _start + 16;
return uint128(bytes16(_bytes[_start:end]));
}
}
function toU256(bytes calldata _bytes, uint256 _start) internal pure returns (uint256) {
unchecked {
uint256 end = _start + 32;
return uint256(bytes32(_bytes[_start:end]));
}
}
function toAddr(bytes calldata _bytes, uint256 _start) internal pure returns (address) {
unchecked {
uint256 end = _start + 20;
return address(bytes20(_bytes[_start:end]));
}
}
function toB32(bytes calldata _bytes, uint256 _start) internal pure returns (bytes32) {
unchecked {
uint256 end = _start + 32;
return bytes32(_bytes[_start:end]);
}
}
}// SPDX-License-Identifier: MIT
// modified from https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/structs/BitMaps.sol
pragma solidity ^0.8.20;
type BitMap256 is uint256;
using BitMaps for BitMap256 global;
library BitMaps {
/**
* @dev Returns whether the bit at `index` is set.
*/
function get(BitMap256 bitmap, uint8 index) internal pure returns (bool) {
uint256 mask = 1 << index;
return BitMap256.unwrap(bitmap) & mask != 0;
}
/**
* @dev Sets the bit at `index`.
*/
function set(BitMap256 bitmap, uint8 index) internal pure returns (BitMap256) {
uint256 mask = 1 << index;
return BitMap256.wrap(BitMap256.unwrap(bitmap) | mask);
}
}// 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 { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import { IOAppCore, ILayerZeroEndpointV2 } from "./interfaces/IOAppCore.sol";
/**
* @title OAppCore
* @dev Abstract contract implementing the IOAppCore interface with basic OApp configurations.
*/
abstract contract OAppCoreUpgradeable is IOAppCore, OwnableUpgradeable {
struct OAppCoreStorage {
mapping(uint32 => bytes32) peers;
}
// keccak256(abi.encode(uint256(keccak256("layerzerov2.storage.oappcore")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant OAppCoreStorageLocation =
0x72ab1bc1039b79dc4724ffca13de82c96834302d3c7e0d4252232d4b2dd8f900;
function _getOAppCoreStorage() internal pure returns (OAppCoreStorage storage $) {
assembly {
$.slot := OAppCoreStorageLocation
}
}
// The LayerZero endpoint associated with the given OApp
ILayerZeroEndpointV2 public immutable endpoint;
/**
* @dev Constructor to initialize the OAppCore with the provided endpoint and delegate.
* @param _endpoint The address of the LOCAL Layer Zero endpoint.
*/
constructor(address _endpoint) {
endpoint = ILayerZeroEndpointV2(_endpoint);
}
/**
* @dev Initializes the OAppCore with the provided delegate.
* @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.
* @dev Ownable is not initialized here on purpose. It should be initialized in the child contract to
* accommodate the different version of Ownable.
*/
function __OAppCore_init(address _delegate) internal onlyInitializing {
__OAppCore_init_unchained(_delegate);
}
function __OAppCore_init_unchained(address _delegate) internal onlyInitializing {
if (_delegate == address(0)) revert InvalidDelegate();
endpoint.setDelegate(_delegate);
}
/**
* @notice Returns the peer address (OApp instance) associated with a specific endpoint.
* @param _eid The endpoint ID.
* @return peer The address of the peer associated with the specified endpoint.
*/
function peers(uint32 _eid) public view override returns (bytes32) {
OAppCoreStorage storage $ = _getOAppCoreStorage();
return $.peers[_eid];
}
/**
* @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 {
OAppCoreStorage storage $ = _getOAppCoreStorage();
$.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) {
OAppCoreStorage storage $ = _getOAppCoreStorage();
bytes32 peer = $.peers[_eid];
if (peer == bytes32(0)) revert NoPeer(_eid);
return peer;
}
/**
* @notice Sets the delegate address for the OApp.
* @param _delegate The address of the delegate to be set.
*
* @dev Only the owner/admin of the OApp can call this function.
* @dev Provides the ability for a delegate to set configs, on behalf of the OApp, directly on the Endpoint contract.
*/
function setDelegate(address _delegate) public onlyOwner {
endpoint.setDelegate(_delegate);
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.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/ContextUpgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* 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 OwnableUpgradeable is Initializable, ContextUpgradeable {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
function __Ownable_init() internal onlyInitializing {
__Ownable_init_unchained();
}
function __Ownable_init_unchained() internal onlyInitializing {
_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);
}
/**
* @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[49] private __gap;
}// 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.4) (utils/Context.sol)
pragma solidity ^0.8.0;
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract ContextUpgradeable is Initializable {
function __Context_init() internal onlyInitializing {
}
function __Context_init_unchained() internal onlyInitializing {
}
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
/**
* @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[50] private __gap;
}// 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: 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);
}
}
}{
"viaIR": false,
"codegen": "yul",
"remappings": [
"frax-std/=node_modules/frax-standard-solidity/src/",
"@prb/test/=node_modules/@prb/test/",
"forge-std/=node_modules/forge-std/src/",
"ds-test/=node_modules/ds-test/src/",
"@axelar-network/=node_modules/@axelar-network/",
"@chainlink/=node_modules/@chainlink/",
"@eth-optimism/=node_modules/@eth-optimism/",
"@fraxfinance/=node_modules/@fraxfinance/",
"@layerzerolabs/=node_modules/@layerzerolabs/",
"@openzeppelin/=node_modules/@openzeppelin/",
"frax-standard-solidity/=node_modules/frax-standard-solidity/",
"hardhat-deploy/=node_modules/hardhat-deploy/",
"solidity-bytes-utils/=node_modules/solidity-bytes-utils/"
],
"evmVersion": "paris",
"outputSelection": {
"*": {
"*": [
"abi"
]
}
},
"optimizer": {
"enabled": true,
"mode": "3",
"size_fallback": false,
"disable_system_request_memoization": true
},
"metadata": {},
"libraries": {},
"enableEraVMExtensions": false,
"forceEVMLA": false
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"bytes32","name":"_fraxtalHop","type":"bytes32"},{"internalType":"uint256","name":"_numDVNs","type":"uint256"},{"internalType":"address","name":"_EXECUTOR","type":"address"},{"internalType":"address","name":"_DVN","type":"address"},{"internalType":"address","name":"_TREASURY","type":"address"},{"internalType":"address[]","name":"_approvedOfts","type":"address[]"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"HopPaused","type":"error"},{"inputs":[],"name":"InsufficientFee","type":"error"},{"inputs":[],"name":"InvalidOFT","type":"error"},{"inputs":[{"internalType":"uint16","name":"optionType","type":"uint16"}],"name":"InvalidOptionType","type":"error"},{"inputs":[],"name":"NotEndpoint","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"RefundFailed","type":"error"},{"inputs":[{"internalType":"uint8","name":"bits","type":"uint8"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"SafeCastOverflowedUintDowncast","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"ZeroAmountSend","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oft","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"uint32","name":"dstEid","type":"uint32"},{"indexed":true,"internalType":"bytes32","name":"to","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"amountLD","type":"uint256"}],"name":"SendOFT","type":"event"},{"inputs":[],"name":"DVN","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EXECUTOR","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TREASURY","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"approvedOft","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"","type":"uint32"}],"name":"executorOptions","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fraxtalHop","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"hopFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"numDVNs","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"_paused","type":"bool"}],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_oft","type":"address"},{"internalType":"uint32","name":"_dstEid","type":"uint32"},{"internalType":"bytes32","name":"_to","type":"bytes32"},{"internalType":"uint256","name":"_amountLD","type":"uint256"}],"name":"quote","outputs":[{"components":[{"internalType":"uint256","name":"nativeFee","type":"uint256"},{"internalType":"uint256","name":"lzTokenFee","type":"uint256"}],"internalType":"struct MessagingFee","name":"fee","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"_dstEid","type":"uint32"}],"name":"quoteHop","outputs":[{"internalType":"uint256","name":"finalFee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"tokenAmount","type":"uint256"}],"name":"recoverERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"tokenAmount","type":"uint256"}],"name":"recoverETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_oft","type":"address"},{"internalType":"uint32","name":"_dstEid","type":"uint32"},{"internalType":"bytes32","name":"_to","type":"bytes32"},{"internalType":"uint256","name":"_amountLD","type":"uint256"}],"name":"sendOFT","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint32","name":"eid","type":"uint32"},{"internalType":"bytes","name":"_options","type":"bytes"}],"name":"setExecutorOptions","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_fraxtalHop","type":"address"}],"name":"setFraxtalHop","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_fraxtalHop","type":"bytes32"}],"name":"setFraxtalHop","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_hopFee","type":"uint256"}],"name":"setHopFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_numDVNs","type":"uint256"}],"name":"setNumDVNs","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_oft","type":"address"},{"internalType":"bool","name":"_approved","type":"bool"}],"name":"toggleOFTApproval","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
9c4d535b0000000000000000000000000000000000000000000000000000000000000000010005cbf2f50edb352eb4a0139be0ab2a3fff5b73ef678ab195d9953dfd2d53000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000002a2019b30c157db6c1c01306b8025167dbe1803b0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000643e1471f37c4680df30cf0c540cd379a0ff58a5000000000000000000000000f4da94b4ee9d8e209e3bf9f469221ce2731a711200000000000000000000000054f1deb345306f326096a2dce26c0dd05e7b595a00000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000006000000000000000000000000ea77c590bb36c43ef7139ce649cfbcfd6163170d0000000000000000000000009f87fbb47c33cd0614e43500b9511018116f79ee000000000000000000000000c7ab797019156b543b7a3fbf5a99ecdab9eb4440000000000000000000000000fd78fd3667def2f1097ed221ec503ae477155394000000000000000000000000af01ae13fb67ad2bb2d76f29a83961069a5f245f000000000000000000000000580f2ee1476edf4b1760bd68f6aabad57dec420e
Deployed Bytecode
0x0003000000000002001a00000000000200000060031002700000055303300197000200000031035500010000000103550000000100200190000000210000c13d0000008004000039000000400040043f000000040030008c000000670000413d000000000201043b000000e002200270000005620020009c0000006b0000213d000005740020009c000000820000a13d000005750020009c000000ea0000a13d000005760020009c000001420000213d000005790020009c000001710000613d0000057a0020009c000003590000c13d0000000001000416000000000001004b000003590000c13d0000000101000039000000000101041a000005a700100198000001010000013d000000e004000039000000400040043f0000000002000416000000000002004b000003590000c13d0000001f023000390000055402200197000000e002200039000000400020043f0000001f0530018f0000055506300198000000e002600039000000330000613d000000000701034f000000007807043c0000000004840436000000000024004b0000002f0000c13d000000000005004b000000400000613d000000000161034f0000000304500210000000000502043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f0000000000120435000000c00030008c000003590000413d000001200600043d000005560060009c000003590000213d000001400700043d000005560070009c000003590000213d000001600100043d001400000001001d000005560010009c000003590000213d000001800100043d000005570010009c000003590000213d0000001f02100039000000000032004b000000000400001900000558040080410000055802200197000000000002004b00000000050000190000055805004041000005580020009c000000000504c019000000000005004b000003590000c13d001000000007001d001100000006001d000000e0021000390000000002020433000005570020009c0000033f0000a13d000005b701000041000000000010043f0000004101000039000000040010043f00000561010000410000154a00010430000000000003004b000003590000c13d0000000001000019000015490001042e000005630020009c000000d50000a13d000005640020009c000001060000a13d000005650020009c000001510000213d000005680020009c000001810000613d000005690020009c000003590000c13d000000240030008c000003590000413d0000000001000416000000000001004b000003590000c13d154813680000040f00000004010000390000000101100367000000000101043b0000000302000039000000000012041b0000000001000019000015490001042e0000057e0020009c000001110000213d000005820020009c0000022d0000613d000005830020009c000002e90000613d000005840020009c000003590000c13d000000640030008c000003590000413d0000000002000416000000000002004b000003590000c13d0000000402100370000000000202043b000005560020009c000003590000213d0000002403100370000000000303043b000005560030009c000003590000213d000000000400041a00000556054001970000000004000411000000000045004b000003900000c13d000005bd04000041000000800040043f0000004401100370000000000101043b000000840030043f000000a40010043f0000000001000414000005530010009c0000055301008041000000c001100210000005be011001c71548153e0000040f00000060031002700000055303300197000000200030008c000000200400003900000000040340190000001f0640018f000000200740019000000080057001bf000000b70000613d0000008008000039000000000901034f000000009a09043c0000000008a80436000000000058004b000000b30000c13d000000000006004b000000c40000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000000003001f00020000000103550000000100200190000003eb0000613d0000001f01400039000000600110018f00000080011001bf000000400010043f000000200030008c000003590000413d000000800100043d000000000001004b0000000002000039000000010200c039000000000021004b000000690000613d000003590000013d0000056d0020009c000001370000213d000005710020009c000002450000613d000005720020009c000002f40000613d000005730020009c000003590000c13d000000240030008c000003590000413d0000000001000416000000000001004b000003590000c13d154813680000040f00000004010000390000000101100367000000000101043b0000000202000039000000000012041b0000000001000019000015490001042e0000057b0020009c000001f80000613d0000057c0020009c000002720000613d0000057d0020009c000003590000c13d000000240030008c000003590000413d0000000002000416000000000002004b000003590000c13d0000000401100370000000000101043b000005560010009c000003590000213d000000000010043f0000000601000039000000200010043f00000040020000390000000001000019154815100000040f000000000101041a000000ff001001900000000001000039000000010100c039000000800010043f000005a501000041000015490001042e0000056a0020009c000002280000613d0000056b0020009c000002d80000613d0000056c0020009c000003590000c13d0000000001000416000000000001004b000003590000c13d0000000201000039000002550000013d0000057f0020009c000002510000613d000005800020009c0000030f0000613d000005810020009c000003590000c13d000000440030008c000003590000413d0000000002000416000000000002004b000003590000c13d0000000402100370000000000402043b000005560040009c000003590000213d000000000200041a00000556032001970000000002000411000000000023004b000003650000c13d0000002401100370000000000301043b0000000001000414000005530010009c0000055301008041000000c001100210000000000003004b0000055b0110c1c70000800902000039000000000204601900000000050000191548153e0000040f0000006002100270000005530020019d00020000000103551548114f0000040f0000000001000019000015490001042e0000056e0020009c000002590000613d0000056f0020009c000003200000613d000005700020009c000003590000c13d0000000001000416000000000001004b000003590000c13d000000000100041a0000031c0000013d000005770020009c000001870000613d000005780020009c000003590000c13d0000000001000416000000000001004b000003590000c13d0000000001000412001600000001001d001500000000003d000080050100003900000044030000390000000004000415000000160440008a000003190000013d000005660020009c000001a70000613d000005670020009c000003590000c13d000000240030008c000003590000413d0000000002000416000000000002004b000003590000c13d0000000401100370000000000601043b000005560060009c000003590000213d000000000100041a00000556011001970000000005000411000000000051004b0000035b0000c13d0000000101000039000000000201041a0000055a02200197000000000262019f000000000021041b0000000001000414000005530010009c0000055301008041000000c0011002100000055b011001c70000800d02000039000000030300003900000587040000410000030b0000013d000000240030008c000003590000413d0000000002000416000000000002004b000003590000c13d0000000401100370000000000101043b001400000001001d000005560010009c000003590000213d154813680000040f00000002010000390000001402000029000000000021041b0000000001000019000015490001042e0000000001000416000000000001004b000003590000c13d0000000101000039000000000101041a0000031c0000013d000000440030008c000003590000413d0000000002000416000000000002004b000003590000c13d0000000402100370000000000202043b001400000002001d000005560020009c000003590000213d0000002401100370000000000201043b000000000002004b0000000001000039000000010100c039001300000002001d000000000012004b000003590000c13d154813680000040f0000001401000029000000000010043f0000000601000039000000200010043f00000040020000390000000001000019154815100000040f000000000301041a000005c10230019700000013022001af000000000021041b0000000001000019000015490001042e000000840030008c000003590000413d0000000002000416000000000002004b000003590000c13d0000000402100370000000000202043b001400000002001d000005560020009c000003590000213d0000002402100370000000000202043b001300000002001d000005530020009c000003590000213d0000006402100370000000000202043b001200000002001d0000004401100370000000000101043b001100000001001d000000c001000039000000400010043f000000800000043f000000a00000043f0000058801000041000000c00010043f0000000001000414000005530010009c0000055301008041000000c00110021000000589011001c70000001402000029154815430000040f000000c00a00003900000060031002700000055303300197000000200030008c000000200400003900000000040340190000001f0640018f0000002007400190000000c0057001bf000001d80000613d000000000801034f000000008908043c000000000a9a043600000000005a004b000001d40000c13d000000000006004b000001e50000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000000003001f00020000000103550000000100200190000003800000613d0000001f01400039000000600110018f000000c002100039000000400020043f000000200030008c000003590000413d000000c00300043d000000000003004b000003f70000c13d000005b701000041000000000010043f0000001201000039000000040010043f00000561010000410000154a00010430001400000004001d000000840030008c000003590000413d0000000402100370000000000202043b001300000002001d000005560020009c000003590000213d0000002402100370000000000202043b001200000002001d000005530020009c000003590000213d0000006402100370000000000302043b0000004401100370000000000201043b0000000101000039000000000101041a000005a7001001980000038c0000c13d001100000003001d001000000002001d0000001301000029000000000010043f0000000601000039000000200010043f0000000001000414000005530010009c0000055301008041000000c0011002100000055e011001c70000801002000039154815430000040f0000000100200190000003590000613d000000400300043d000000000101043b000000000101041a000000ff00100190000004d40000c13d000005bc010000410000000000130435000005530030009c00000553030080410000004001300210000005aa011001c70000154a000104300000000001000416000000000001004b000003590000c13d0000000301000039000002550000013d000000240030008c000003590000413d0000000002000416000000000002004b000003590000c13d0000000401100370000000000201043b000000000002004b0000000001000039000000010100c039001400000002001d000000000012004b000003590000c13d154813680000040f000000140000006b0000000001000019000005bf0100c0410000000102000039000000000302041a000005c003300197000000000113019f000000000012041b0000000001000019000015490001042e000000240030008c000003590000413d0000000001000416000000000001004b000003590000c13d154813680000040f00000004010000390000000102100367000000000202043b000000000021041b0000000001000019000015490001042e0000000001000416000000000001004b000003590000c13d0000000401000039000000000101041a000000800010043f000005a501000041000015490001042e0000000001000416000000000001004b000003590000c13d0000000101000039000000000201041a00000556032001970000000006000411000000000063004b000003600000c13d0000055a02200197000000000021041b000000000100041a0000055a02100197000000000262019f000000000020041b00000000020004140000055605100197000005530020009c0000055302008041000000c0012002100000055b011001c70000800d0200003900000003030000390000055c040000410000030b0000013d000000440030008c000003590000413d0000000002000416000000000002004b000003590000c13d0000000402100370000000000202043b000005530020009c000003590000213d0000002404100370000000000504043b000005570050009c000003590000213d0000002304500039000000000034004b000003590000813d0000000406500039000000000461034f000000000404043b000005570040009c000000610000213d0000001f07400039000005c2077001970000003f07700039000005c2077001970000058d0070009c000000610000213d0000008007700039000000400070043f000000800040043f00000000054500190000002405500039000000000035004b000003590000213d0000002003600039000000000331034f000005c2054001980000001f0640018f000000a001500039000002a00000613d000000a007000039000000000803034f000000008908043c0000000007970436000000000017004b0000029c0000c13d000000000006004b000002ad0000613d000000000353034f0000000305600210000000000601043300000000065601cf000000000656022f000000000303043b0000010005500089000000000353022f00000000035301cf000000000363019f0000000000310435000000a0014000390000000000010435000000000100041a00000556031001970000000001000411000000000013004b000005460000c13d000000000020043f0000000501000039000000200010043f0000000001000414000005530010009c0000055301008041000000c0011002100000055e011001c70000801002000039154815430000040f0000000100200190000003590000613d000000000101043b001400000001001d000000800100043d001300000001001d000005570010009c000000610000213d0000001401000029000000000101041a000000010010019000000001021002700000007f0220618f001200000002001d0000001f0020008c00000000020000390000000102002039000000000121013f00000001001001900000059d0000613d000005b701000041000000000010043f0000002201000039000000040010043f00000561010000410000154a00010430000000240030008c000003590000413d0000000002000416000000000002004b000003590000c13d0000000401100370000000000101043b000005530010009c000003590000213d154811800000040f000000400200043d0000000000120435000005530020009c00000553020080410000004001200210000005a6011001c7000015490001042e0000000001000416000000000001004b000003590000c13d0000000001000412001a00000001001d001900200000003d0000800501000039000000440300003900000000040004150000001a0440008a000003190000013d0000000001000416000000000001004b000003590000c13d000000000100041a00000556021001970000000005000411000000000052004b0000035b0000c13d0000000102000039000000000302041a0000055a03300197000000000032041b0000055a01100197000000000010041b0000000001000414000005530010009c0000055301008041000000c0011002100000055b011001c70000800d0200003900000003030000390000055c0400004100000000060000191548153e0000040f0000000100200190000000690000c13d000003590000013d0000000001000416000000000001004b000003590000c13d0000000001000412001800000001001d001700400000003d000080050100003900000044030000390000000004000415000000180440008a00000005044002100000059602000041154815250000040f0000055601100197000000800010043f000005a501000041000015490001042e000000240030008c000003590000413d0000000002000416000000000002004b000003590000c13d0000000401100370000000000101043b000005530010009c000003590000213d000000000010043f0000000501000039000000200010043f00000040020000390000000001000019154815100000040f154810f00000040f0000002002000039000000400300043d001400000003001d00000000022304361548113d0000040f00000014020000290000000001210049000005530010009c00000553010080410000006001100210000005530020009c00000553020080410000004002200210000000000121019f000015490001042e00000005042002100000003f054000390000055905500197000000400600043d0000000005560019001300000006001d000000000065004b00000000060000390000000106004039000005570050009c000000610000213d0000000100600190000000610000c13d000000e006300039000001000300043d000f00000003001d000000e00300043d000e00000003001d000000400050043f00000013030000290000000003230436001200000003001d00000100011000390000000003140019000000000063004b0000036a0000a13d00000000010000190000154a000104300000058501000041000000800010043f000000840050043f00000586010000410000154a000104300000058501000041000000800010043f000000840060043f00000586010000410000154a000104300000058501000041000000800010043f000000840020043f00000586010000410000154a00010430000000000002004b000003730000613d00000012020000290000000014010434000005560040009c000003590000213d0000000002420436000000000031004b0000036d0000413d0000000006000411000000000006004b000003950000c13d000000400100043d0000056002000041000000000021043500000004021000390000000000020435000005530010009c0000055301008041000000400110021000000561011001c70000154a000104300000001f0530018f0000055506300198000000400200043d0000000004620019000005330000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000003870000c13d000005330000013d000005a801000041000000800010043f000005a9010000410000154a000104300000058501000041000000800010043f000000840040043f00000586010000410000154a00010430000000000100041a0000055a02100197000000000262019f0000000103000039000000000303041a000d00000003001d000000000020041b00000000020004140000055605100197000005530020009c0000055302008041000000c0012002100000055b011001c70000800d0200003900000003030000390000055c040000411548153e0000040f000000100400002900000011030000290000000100200190000003590000613d0000000d010000290000055d011001970000000102000039000000000012041b0000000401000039000000000021041b00000002010000390000000e02000029000000000021041b00000003010000390000000f02000029000000000021041b000000800030043f000000a00040043f0000001405000029000000c00050043f00000013010000290000000001010433000000000001004b000003de0000613d0000000002000019001400000002001d0000000501200210000000120110002900000000010104330000055601100197000000000010043f0000000601000039000000200010043f0000000001000414000005530010009c0000055301008041000000c0011002100000055e011001c70000801002000039154815430000040f0000000100200190000003590000613d000000000101043b000000000201041a000005c10220019700000001022001bf000000000021041b0000001402000029000000010220003900000013010000290000000001010433000000000012004b000003bf0000413d000000c00500043d000000a00400043d000000800300043d0000014000000443000001600030044300000020010000390000018000100443000001a0004004430000004002000039000001c000200443000001e0005004430000010000100443000000030100003900000120001004430000055f01000041000015490001042e0000001f0530018f0000055506300198000000400200043d0000000004620019000005330000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000003f20000c13d000005330000013d00000012043000f900000000093400a9000000120030006c000003fe0000213d00000000044900d9000000000034004b000006ab0000c13d000001a003100039000000400030043f000001200410003900000100051001bf000000e00610003900000013030000290000762f0030008c000005500000c13d0000762f0300003900000000003204350000001103000029000000000036043500000000009504350000000000940435000000400300043d000005a30030009c000000610000213d0000002007300039000000400070043f000000000003043500000140071000390000000000370435000000400800043d000005a30080009c000000610000213d0000002003800039000000400030043f000000000008043500000160031000390000000000830435000000400800043d000005a30080009c000000610000213d0000002009800039000000400090043f000000000008043500000180011001bf00000000008104350000059408000041000000400a00043d00000000088a0436001200000008001d0000000408a0003900000040090000390000000000980435000000000202043300000553082001970000004402a00039000000000082043500000000060604330000006408a00039000000000068043500000000050504330000008406a0003900000000005604350000000004040433000000a405a0003900000000004504350000000004070433000000c405a00039000000e00600003900000000006504350000012405a000390000000064040434000000000045043500130000000a001d0000014405a00039000000000004004b0000044b0000613d000000000700001900000000085700190000000009760019000000000909043300000000009804350000002007700039000000000047004b000004440000413d000000000654001900000000000604350000001f06400039000000200400008a000000000646016f0000000007560019000000000527004900000000030304330000001306000029000000e406600039000000000056043500000000650304340000000003570436000000000005004b000004620000613d000000000700001900000000083700190000000009760019000000000909043300000000009804350000002007700039000000000057004b0000045b0000413d000000000635001900000000000604350000001f05500039000000000545016f00000000053500190000000002250049000000000101043300000013030000290000010403300039000000000023043500000000320104340000000001250436000000000002004b000004780000613d000000000500001900000000061500190000000007530019000000000707043300000000007604350000002005500039000000000025004b000004710000413d000000000312001900000000000304350000001305000029000000240350003900000000000304350000001f02200039000000000242016f00000000015100490000000001210019000005530010009c00000553010080410000006001100210000005530050009c000005530200004100000000020540190000004002200210000000000121019f0000000002000414000005530020009c0000055302008041000000c002200210000000000112019f0000001402000029154815430000040f00000060031002700000055303300197000000400030008c000000400400003900000000040340190000001f0640018f000000600740019000000013057000290000049f0000613d000000000801034f0000001309000029000000008a08043c0000000009a90436000000000059004b0000049b0000c13d000000000006004b000004ac0000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000000003001f00020000000103550000000100200190000005d00000613d0000001f01400039000000e00210018f0000001301200029000000000021004b00000000020000390000000102004039000005570010009c000000610000213d0000000100200190000000610000c13d000000400010043f000000400030008c000003590000413d0000058b0010009c000000610000213d0000004002100039000000400020043f00000013020000290000000002020433000000000321043600000012010000290000000001010433001100000003001d001000000003001d00000011030000290000000000130435000000400100043d0000000002210436000000100300002900000000030304330000000000320435000005530010009c00000553010080410000004001100210000005a4011001c7000015490001042e00000588010000410000000000130435000005530030009c0000055301000041000000000103401900000040011002100000000002000414000005530020009c0000055302008041000000c002200210000000000112019f000005aa011001c70000001302000029000f00000003001d154815430000040f0000000f0b00002900000060031002700000055303300197000000200030008c000000200400003900000000040340190000001f0640018f000000200740019000000000057b0019000004f30000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b000004ef0000c13d000000000006004b000005000000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000000003001f00020000000103550000000100200190000005280000613d0000001f01400039000000600110018f0000000002b10019000000000012004b00000000010000390000000101004039000e00000002001d000005570020009c000000610000213d0000000100100190000000610000c13d0000000e01000029000000400010043f000000200030008c000003590000413d0000000f010000290000000001010433000000000001004b000001f20000613d00000011021000f9000f0000001200ad000000110010006c0000051e0000213d0000000f022000f9000000000012004b000006ab0000c13d0000000f0000006b000005dc0000c13d000005bb010000410000000e020000290000000000120435000005530020009c00000553020080410000004001200210000005aa011001c70000154a000104300000001f0530018f0000055506300198000000400200043d0000000004620019000005330000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b0000052f0000c13d000000000005004b000005400000613d000000000161034f0000000305500210000000000604043300000000065601cf000000000656022f000000000101043b0000010005500089000000000151022f00000000015101cf000000000161019f00000000001404350000006001300210000005530020009c00000553020080410000004002200210000000000112019f0000154a00010430000000400200043d0000058503000041000000000032043500000004032000390000000000130435000005530020009c0000055302008041000000400120021000000561011001c70000154a00010430000000000002043500000000000604350000000000050435000000000004043500000180031001bf000000600a000039001200000003001d0000000000a3043500000160071000390000000000a7043500000140081000390000000000a804350000000203000039000000400100043d000000000e3104360000058a0b0000410000000000be04350000058b0010009c000000610000213d000000400c1000390000004000c0043f000000000b0104330000000100b0008c000005780000213d000005a00200004100000000002c04350000008402100039000005a10300004100000000003204350000006402100039000000140300003900000000003204350000004401100039000000200200003900000000002104350000055300c0009c000005530c0080410000004001c00210000005a2011001c70000154a00010430000000020b100039000000000d0b04330000ffff0dd0018f0000000300d0008c00000ab00000c13d000000600d10003900000000000d0435000000620f1000390000058c0a0000410000000000af0435000000120a0000390000000000ac04350000058d0010009c000000610000213d0000008003100039001000000003001d000000400030043f000000000f0104330000000100f0008c000006660000213d000005a00200004100000010040000290000000000240435000000c402100039000005a1030000410000000000320435000000a40210003900000014030000390000000000320435000000840110003900000020020000390000000000210435000005530040009c00000553040080410000004001400210000005a2011001c70000154a000104300000001201000029000000200010008c000005bc0000413d0000001401000029000000000010043f0000000001000414000005530010009c0000055301008041000000c00110021000000599011001c70000801002000039154815430000040f0000000100200190000003590000613d00000013030000290000001f023000390000000502200270000000200030008c0000000002004019000000000301043b00000012010000290000001f01100039000000050110027000000000011300190000000002230019000000000012004b000005bc0000813d000000000002041b0000000102200039000000000012004b000005b80000413d0000001301000029000000200010008c0000065b0000413d0000001401000029000000000010043f0000000001000414000005530010009c0000055301008041000000c00110021000000599011001c70000801002000039154815430000040f0000000100200190000003590000613d000000200200008a0000001302200180000000000101043b000006880000c13d000000a003000039000006960000013d0000001f0530018f0000055506300198000000400200043d0000000004620019000005330000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000005d70000c13d000005330000013d000005ab010000410000000e020000290000000000120435000005530020009c0000055301000041000000000102401900000040011002100000000002000414000005530020009c0000055302008041000000c002200210000000000112019f000005aa011001c70000001302000029154815430000040f00000060031002700000055303300197000000200030008c000000200400003900000000040340190000001f0640018f00000020074001900000000e05700029000005fa0000613d000000000801034f0000000e09000029000000008a08043c0000000009a90436000000000059004b000005f60000c13d000000000006004b000006070000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000000003001f000200000001035500000001002001900000067c0000613d0000001f01400039000000600110018f0000000e01100029000005570010009c000000610000213d000000400010043f000000200030008c000003590000413d0000000e020000290000000002020433001100000002001d000005560020009c000003590000213d00000064021000390000000f0300002900000000003204350000002002100039000005ac030000410000000000320435000000000300041100000556033001970000002404100039000000000034043500000064030000390000000000310435000000000300041000000556043001970000004403100039000d00000004001d0000000000430435000005ad0010009c000000610000213d000000a003100039000000400030043f000005530020009c000005530200804100000040022002100000000001010433000005530010009c00000553010080410000006001100210000000000121019f0000000002000414000005530020009c0000055302008041000000c002200210000000000121019f00000011020000291548153e0000040f00020000000103550000006003100270000005530030019d0000055303300198000008380000c13d000e00600000003d0000000e0100002900000000010104330000000100200190000008620000613d000000000001004b000008850000c13d000005b0010000410000000000100443000000110100002900000004001004430000000001000414000005530010009c0000055301008041000000c001100210000005b1011001c70000800202000039154815430000040f000000010020019000000f220000613d000000000101043b000000000001004b000008810000c13d000000400100043d000005ba02000041000008940000013d000000130000006b0000000001000019000006a40000613d00000013030000290000000301300210000005c30110027f000005c301100167000000a00200043d000000000212016f0000000101300210000006a30000013d000000000a0b04330000ffff0aa0018f0000000300a0008c00000ab00000c13d00000000030c0433000f00000003001d0000058f0030009c000006a80000413d0000059e0200004100000010030000290000000000230435000000a4021000390000000f040000290000000000420435000000840110003900000010020000390000000000210435000005530030009c000005530300804100000040013002100000059f011001c70000154a000104300000001f0530018f0000055506300198000000400200043d0000000004620019000005330000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000006830000c13d000005330000013d000000010320008a0000000503300270000000000331001900000020040000390000000103300039000000000504001900000080044000390000000004040433000000000041041b00000020045000390000000101100039000000000031004b0000068d0000c13d000000a003500039000000130020006c000006a00000813d00000013020000290000000302200210000000f80220018f000005c30220027f000005c3022001670000000003030433000000000223016f000000000021041b000000010100003900000013020000290000000102200210000000000112019f0000001402000029000000000012041b0000000001000019000015490001042e0000000f030000290000ffff0030008c000006b10000c13d000005b701000041000000000010043f0000001101000039000000040010043f00000561010000410000154a00010430000000a001100039000000000b000019000000000a1b00190000000003eb0019000000000303043300000000003a0435000000200bb000390000000000fb004b000006b30000413d00000000011f0019000005900300004100000000003104350000000f03000029000000f003300210000005910330009a000000010a10003900000000003a04350000000303100039000005920a0000410000000000a304350000000401100039000000000b0c043300000000000b004b000006d10000613d000000000c00001900000000031c0019000000000adc0019000000000a0a04330000000000a30435000000200cc000390000000000bc004b000006ca0000413d00000000011b00190000000000010435000000100a0000290000000001a10049000000200310008a00000000003a04350000001f01100039000005c2031001970000000001a30019000000000031004b000000000b000039000000010b004039000005570010009c000000610000213d0000000100b00190000000610000c13d000000400010043f0000762f0100003900000000001204350000000201000039000000000101041a00000000001604350000000000950435000000000094043500000010010000290000000000180435000000400100043d00000040031000390000001309000029000000000093043500000020031000390000001109000029000000000093043500000040030000390000000000310435000005930010009c000000610000213d0000006003100039000000400030043f00000000001704350000059401000041000000400900043d0000000001190436000f00000001001d00000004019000390000004003000039000000000031043500000000010204330000055302100197000000440190003900000000002104350000000002060433000000640390003900000000002304350000000002050433000000840390003900000000002304350000000002040433000000a40390003900000000002304350000000002080433000000c403900039000000e0040000390000000000430435000001240390003900000000520204340000000000230435001000000009001d0000014404900039000000000002004b000007200000613d000000000600001900000000034600190000000008650019000000000808043300000000008304350000002006600039000000000026004b000007190000413d000000000342001900000000000304350000001f02200039000005c2022001970000000002420019000000000312004900000000040704330000001005000029000000e405500039000000000035043500000000540404340000000002420436000000000004004b000007360000613d000000000600001900000000032600190000000007650019000000000707043300000000007304350000002006600039000000000046004b0000072f0000413d000000000324001900000000000304350000001f03400039000005c203300197000000000423001900000000011400490000001202000029000000000202043300000010030000290000010403300039000000000013043500000000320204340000000001240436000000000002004b0000074d0000613d000000000400001900000000051400190000000006430019000000000606043300000000006504350000002004400039000000000024004b000007460000413d000000000312001900000000000304350000001004000029000000240340003900000000000304350000001f02200039000005c20220019700000000014100490000000001210019000005530010009c00000553010080410000006001100210000005530040009c000005530200004100000000020440190000004002200210000000000121019f0000000002000414000005530020009c0000055302008041000000c002200210000000000112019f0000001402000029154815430000040f00000060031002700000055303300197000000400030008c000000400400003900000000040340190000001f0640018f00000060074001900000001005700029000007740000613d000000000801034f0000001009000029000000008a08043c0000000009a90436000000000059004b000007700000c13d000000000006004b000007810000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000000003001f000200000001035500000001002001900000086c0000613d0000001f01400039000000e00110018f0000001002100029000000000012004b00000000010000390000000101004039001100000002001d000005570020009c000000610000213d0000000100100190000000610000c13d0000001101000029000000400010043f000000400030008c000003590000413d00000011010000290000058b0010009c000000610000213d00000011020000290000004001200039000000400010043f0000001001000029000000000101043300000000021204360000000f010000290000000001010433001000000002001d0000000000120435000000400300043d00000064013000390000008002000039000000000021043500000005020000390000002401300039000000000021043500000595010000410000000000130435000000040130003900000013020000290000000000210435000000000100041000000556021001970000004401300039000f00000002001d0000000000210435001400000003001d000000840130003900000000000104350000059601000041000000000010044300000000010004120000000400100443000000200100003900000024001004430000000001000414000005530010009c0000055301008041000000c00110021000000597011001c70000800502000039154815430000040f000000010020019000000f220000613d000000000201043b0000001401000029000005530010009c000005530100804100000040011002100000000003000414000005530030009c0000055303008041000000c003300210000000000113019f00000598011001c70000055602200197154815430000040f00000060031002700000055303300197000000200030008c000000200400003900000000040340190000001f0640018f00000020074001900000001405700029000007e00000613d000000000801034f0000001409000029000000008a08043c0000000009a90436000000000059004b000007dc0000c13d000000000006004b000007ed0000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000000003001f0002000000010355000000010020019000000a750000613d0000001f01400039000000600210018f0000001401200029000000000021004b00000000020000390000000102004039000005570010009c000000610000213d0000000100200190000000610000c13d000000400010043f000000200030008c000003590000413d00000014010000290000000001010433000e00000001001d0000001301000029000000000010043f0000000501000039000000200010043f0000000001000414000005530010009c0000055301008041000000c0011002100000055e011001c70000801002000039154815430000040f0000000100200190000003590000613d000000000101043b000000000201041a000000010320019000000001042002700000007f0440618f001200000004001d0000001f0040008c00000000040000390000000104002039000000000442013f0000000100400190000002d20000c13d000000400400043d000d00000004001d00000012050000290000000004540436001400000004001d000000000003004b00000abc0000613d000000000010043f0000000001000414000005530010009c0000055301008041000000c00110021000000599011001c70000801002000039154815430000040f0000000100200190000003590000613d000000120000006b000000000200001900000ac20000613d000000000101043b00000000020000190000001403200029000000000401041a000000000043043500000001011000390000002002200039000000120020006c000008300000413d00000ac20000013d0000001f0430003900000554044001970000003f04400039000005ae04400197000000400500043d0000000004450019000e00000005001d000000000054004b00000000050000390000000105004039000005570040009c000000610000213d0000000100500190000000610000c13d000000400040043f0000001f0430018f0000000e0500002900000000063504360000055505300198001400000006001d0000000003560019000008540000613d000000000601034f0000001407000029000000006806043c0000000007870436000000000037004b000008500000c13d000000000004004b000006420000613d000000000151034f0000000304400210000000000503043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f0000000000130435000006420000013d000000000001004b000008780000c13d000000400100043d000005af020000410000000000210435000005530010009c00000553010080410000004001100210000005aa011001c70000154a000104300000001f0530018f0000055506300198000000400200043d0000000004620019000005330000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000008730000c13d000005330000013d0000001402000029000005530020009c00000553020080410000004002200210000005530010009c00000553010080410000006001100210000000000121019f0000154a000104300000000e010000290000000001010433000000000001004b000008990000613d000005b20010009c000003590000213d000000200010008c000003590000413d00000014010000290000000001010433000000000001004b0000000002000039000000010200c039000000000021004b000003590000c13d000000000001004b000008990000c13d000000400100043d000005b30200004100000000002104350000000402100039000000110300002900000000003204350000037b0000013d000000400100043d001400000001001d00000012010000290000762f0010008c00000a3a0000c13d000005ab0100004100000014020000290000000000120435000005530020009c0000055301000041000000000102401900000040011002100000000002000414000005530020009c0000055302008041000000c002200210000000000112019f000005aa011001c70000001302000029154815430000040f00000060031002700000055303300197000000200030008c000000200400003900000000040340190000001f0640018f00000020074001900000001405700029000008bc0000613d000000000801034f0000001409000029000000008a08043c0000000009a90436000000000059004b000008b80000c13d000000000006004b000008c90000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000000003001f0002000000010355000000010020019000000a690000613d0000001f01400039000000600210018f0000001401200029000000000021004b00000000020000390000000102004039000005570010009c000000610000213d0000000100200190000000610000c13d000000400010043f000000200030008c000003590000413d00000014010000290000000001010433000005560010009c000003590000213d00000013020000290000000f03000029154813780000040f000000400100043d001400000001001d000005b40010009c000000610000213d0000001403000029000000e001300039000000400010043f00000060023000390000000f01000029001100000002001d00000000001204350000004002300039000e00000002001d00000000001204350000762f0100003900000000021304360000001001000029000c00000002001d0000000000120435000000400100043d000005a30010009c000000610000213d0000002002100039000000400020043f000000000001043500000014020000290000008002200039000a00000002001d0000000000120435000000400100043d000005a30010009c000000610000213d0000002002100039000000400020043f00000000000104350000001402000029000000a002200039000900000002001d0000000000120435000000400100043d000005a30010009c000000610000213d0000002002100039000000400020043f00000000000104350000001403000029000000c002300039000800000002001d00000000001204350000059401000041000000400600043d0000000001160436000700000001001d00000004016000390000004002000039000000000021043500000000010304330000055302100197000000440160003900000000002104350000000c020000290000000002020433000000640360003900000000002304350000000e0200002900000000020204330000008403600039000000000023043500000011020000290000000002020433000000a40360003900000000002304350000000a020000290000000002020433000000c403600039000000e0040000390000000000430435000001240560003900000000430204340000000000350435000b00000006001d0000014402600039000000000003004b0000093d0000613d000000000500001900000000062500190000000007540019000000000707043300000000007604350000002005500039000000000035004b000009360000413d000000000423001900000000000404350000001f03300039000005c20330019700000000022300190000000003120049000000090400002900000000040404330000000b05000029000000e405500039000000000035043500000000430404340000000002320436000000000003004b000009540000613d000000000500001900000000062500190000000007540019000000000707043300000000007604350000002005500039000000000035004b0000094d0000413d000000000423001900000000000404350000001f03300039000005c20330019700000000042300190000000001140049000000080200002900000000020204330000000b030000290000010403300039000000000013043500000000320204340000000001240436000000000002004b0000096b0000613d000000000400001900000000051400190000000006430019000000000606043300000000006504350000002004400039000000000024004b000009640000413d000000000312001900000000000304350000000b04000029000000240340003900000000000304350000001f02200039000005c20220019700000000014100490000000001210019000005530010009c00000553010080410000006001100210000005530040009c000005530200004100000000020440190000004002200210000000000121019f0000000002000414000005530020009c0000055302008041000000c002200210000000000112019f0000001302000029154815430000040f00000060031002700000055303300197000000400030008c000000400400003900000000040340190000001f0640018f00000060074001900000000b05700029000009920000613d000000000801034f0000000b09000029000000008a08043c0000000009a90436000000000059004b0000098e0000c13d000000000006004b0000099f0000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000000003001f0002000000010355000000010020019000000d5b0000613d0000001f01400039000000e00110018f0000000b02100029000000000012004b00000000010000390000000101004039000600000002001d000005570020009c000000610000213d0000000100100190000000610000c13d0000000601000029000000400010043f000000400030008c000003590000413d00000006010000290000058b0010009c000000610000213d00000006020000290000004001200039000000400010043f0000000b0100002900000000030104330000000001320436000000070200002900000000020204330000000000210435000005b502000041000000400700043d0000000002270436000b00000002001d000000800200003900000004047000390000000000240435000000140200002900000000020204330000055304200197000000840270003900000000004204350000000c040000290000000004040433000000a40570003900000000004504350000000e040000290000000004040433000000c405700039000000000045043500000011040000290000000004040433000000e40570003900000000004504350000000a0400002900000000040404330000010405700039000000e0060000390000000000650435000001640570003900000000640404340000000000450435001400000007001d0000018405700039000000000004004b000009ea0000613d000000000700001900000000085700190000000009760019000000000909043300000000009804350000002007700039000000000047004b000009e30000413d000000000654001900000000000604350000001f04400039000005c204400197000000000454001900000000052400490000000906000029000000000606043300000014070000290000012407700039000000000057043500000000650604340000000004540436000000000005004b00000a010000613d000000000700001900000000084700190000000009760019000000000909043300000000009804350000002007700039000000000057004b000009fa0000413d000000000645001900000000000604350000001f05500039000005c205500197000000000645001900000000022600490000000804000029000000000404043300000014050000290000014405500039000000000025043500000000540404340000000002460436000000000004004b00000a180000613d000000000600001900000000072600190000000008650019000000000808043300000000008704350000002006600039000000000046004b00000a110000413d0000000005240019000000000005043500000006050000290000000005050433000000140700002900000024067000390000000000560435000000000101043300000064057000390000000d060000290000000000650435000000440570003900000000001504350000001f01400039000005c20110019700000000027200490000000001120019000005530010009c00000553010080410000006001100210000005530070009c000005530200004100000000020740190000004002200210000000000121019f0000000002000414000005530020009c0000055302008041000000c002200210000000000112019f000000000003004b00000d7f0000c13d000000130200002900000d830000013d0000001401000029000005b40010009c000000610000213d0000001402000029000000e001200039000000400010043f000000c0032000390000006001000039000900000003001d0000000000130435000000a003200039000a00000003001d00000000001304350000008003200039001100000003001d00000000001304350000006001200039000e00000001001d00000000000104350000004001200039000c00000001001d00000000000104350000000001020436000b00000001001d00000000000104350000000202000039000000400100043d00000000062104360000058a0300004100000000003604350000058b0010009c000000610000213d0000004004100039000000400040043f0000000003010433000000010030008c00000a810000213d000005a00200004100000000002404350000008402100039000005a10300004100000000003204350000006402100039000000140300003900000000003204350000004401100039000005960000013d0000001f0530018f0000055506300198000000400200043d0000000004620019000005330000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b00000a700000c13d000005330000013d0000001f0530018f0000055506300198000000400200043d0000000004620019000005330000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b00000a7c0000c13d000005330000013d000000020810003900000000030804330000ffff0330018f000000030030008c00000ab00000c13d0000006005100039000000000005043500000062031000390000058c070000410000000000730435000000120300003900000000003404350000058d0010009c000000610000213d0000008003100039000000400030043f0000000007010433000000010070008c00000aa40000213d000005a0020000410000000000230435000000c402100039000005a1040000410000000000420435000000a40210003900000014040000390000000000420435000000840110003900000020020000390000000000210435000005530030009c00000553030080410000004001300210000005a2011001c70000154a0001043000000000080804330000ffff0880018f000000030080008c00000ab00000c13d00000000080404330000058f0080009c00000bcb0000413d0000059e020000410000000000230435000000a4021000390000000000820435000006740000013d154814f80000040f0000058e02000041000000400300043d00000000002304350000ffff0110018f00000004023000390000000000120435000005530030009c0000055303008041000000400130021000000561011001c70000154a00010430000005c10120019700000014020000290000000000120435000000120000006b000000200200003900000000020060390000003f01200039000005c2011001970000000d02100029000000000012004b00000000010000390000000101004039000c00000002001d000005570020009c000000610000213d0000000100100190000000610000c13d0000000c01000029000000400010043f0000000d010000290000000001010433000000000001004b00000ae20000c13d0000000c010000290000058b0010009c000000610000213d0000000c020000290000004001200039000000400010043f00000020032000390000059a01000041001400000003001d000000000013043500000014010000390000000000120435000000400100043d000d00000002001d000c00000001001d0000000c0300002900000064013000390000008002000039000000000021043500000044013000390000002402000039000000000021043500000024013000390000000f0200002900000000002104350000059b0100004100000000001304350000000401300039000000130200002900000000002104350000000d01000029000000000201043300000084013000390000000000210435000000a401300039001200000002001d000000000002004b00000b010000613d000000000200001900000000031200190000001404200029000000000404043300000000004304350000002002200039000000120020006c00000afa0000413d00000012011000290000000000010435000005960100004100000000001004430000000001000412000000040010044300000024000004430000000001000414000005530010009c0000055301008041000000c00110021000000597011001c70000800502000039154815430000040f000000010020019000000f220000613d00000012020000290000001f02200039000005c202200197000000a402200039000005530020009c000005530200804100000060022002100000000c03000029000c00000003001d000005530030009c00000553030080410000004003300210000000000232019f000000000301043b0000000001000414000005530010009c0000055301008041000000c001100210000000000121019f0000055602300197154815430000040f00000060031002700000055303300197000000200030008c000000200400003900000000040340190000001f0640018f00000020074001900000000c0570002900000b350000613d000000000801034f0000000c09000029000000008a08043c0000000009a90436000000000059004b00000b310000c13d000000000006004b00000b420000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000000003001f0002000000010355000000010020019000000d670000613d0000001f01400039000000600110018f0000000c02100029000000000012004b00000000010000390000000101004039001400000002001d000005570020009c000000610000213d0000000100100190000000610000c13d0000001401000029000000400010043f000000200030008c000003590000413d0000000c0100002900000000010104330000000302000039000000000302041a0000000e023000b90000000e0000006b00000b5f0000613d0000000e042000fa000000000034004b000006ab0000c13d000000000012001a000006ab0000413d000000000212001900000014030000290000004401300039001200000002001d00000000002104350000002401300039000000130200002900000000002104350000059c01000041000000000013043500000004013000390000000f020000290000000000210435000000640130003900000000000104350000059601000041000000000010044300000000010004120000000400100443000000400100003900000024001004430000000001000414000005530010009c0000055301008041000000c00110021000000597011001c70000800502000039154815430000040f000000010020019000000f220000613d000000000201043b0000001401000029000005530010009c000005530100804100000040011002100000000003000414000005530030009c0000055303008041000000c003300210000000000113019f0000059d011001c70000055602200197154815430000040f00000060031002700000055303300197000000200030008c000000200400003900000000040340190000001f0640018f0000002007400190000000140570002900000b9b0000613d000000000801034f0000001409000029000000008a08043c0000000009a90436000000000059004b00000b970000c13d000000000006004b00000ba80000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000000003001f0002000000010355000000010020019000000df70000613d0000001f01400039000000600110018f0000001401100029000005570010009c000000610000213d000000400010043f000000200030008c000003590000413d00000014010000290000000001010433000000120010002a000006ab0000413d0000000402000039000000000202041a000005c40020009c000006ab0000213d000000120310002a000027100220003900000000013200a900000bc30000613d00000000033100d9000000000023004b000006ab0000c13d000027100110011a00000011020000290000000002020433000000000012001a000006ab0000413d00000000011200190000000002010019000004c80000013d0000ffff0080008c000006ab0000613d000000a0011000390000000009000019000000000a190019000000000b690019000000000b0b04330000000000ba04350000002009900039000000000079004b00000bcf0000413d000000000117001900000590060000410000000000610435000000f006800210000005910660009a0000000107100039000000000067043500000003061000390000059207000041000000000076043500000004011000390000000004040433000000000004004b00000bec0000613d000000000600001900000000071600190000000008560019000000000808043300000000008704350000002006600039000000000046004b00000be50000413d000000000114001900000000000104350000000001310049000000200410008a00000000004304350000001f01100039000005c2041001970000000001340019000000000041004b00000000040000390000000104004039000005570010009c000000610000213d0000000100400190000000610000c13d000000400010043f0000762f0100003900000014040000290000000000140435000000000102041a0000000b0200002900000000001204350000000f010000290000000c0200002900000000001204350000000e02000029000000000012043500000011010000290000000000310435000000400100043d00000040021000390000001203000029000000000032043500000020021000390000001003000029000000000032043500000040020000390000000000210435000005930010009c000000610000213d0000006002100039000000400020043f0000000a0200002900000000001204350000059401000041000000400500043d0000000001150436000700000001001d000000040150003900000040020000390000000000210435000000140100002900000000010104330000055302100197000000440150003900000000002104350000000b020000290000000002020433000000640350003900000000002304350000000c020000290000000002020433000000840350003900000000002304350000000e020000290000000002020433000000a403500039000000000023043500000011020000290000000002020433000000c403500039000000e0040000390000000000430435000001240350003900000000420204340000000000230435000800000005001d0000014403500039000000000002004b00000c440000613d000000000500001900000000063500190000000007540019000000000707043300000000007604350000002005500039000000000025004b00000c3d0000413d000000000432001900000000000404350000001f02200039000005c202200197000000000232001900000000031200490000000a0400002900000000040404330000000805000029000000e405500039000000000035043500000000430404340000000002320436000000000003004b00000c5b0000613d000000000500001900000000062500190000000007540019000000000707043300000000007604350000002005500039000000000035004b00000c540000413d000000000423001900000000000404350000001f03300039000005c203300197000000000423001900000000011400490000000902000029000000000202043300000008030000290000010403300039000000000013043500000000320204340000000001240436000000000002004b00000c720000613d000000000400001900000000051400190000000006430019000000000606043300000000006504350000002004400039000000000024004b00000c6b0000413d000000000312001900000000000304350000000804000029000000240340003900000000000304350000001f02200039000005c20220019700000000014100490000000001210019000005530010009c00000553010080410000006001100210000005530040009c000005530200004100000000020440190000004002200210000000000121019f0000000002000414000005530020009c0000055302008041000000c002200210000000000112019f0000001302000029154815430000040f00000060031002700000055303300197000000400030008c000000400400003900000000040340190000001f0640018f0000006007400190000000080570002900000c990000613d000000000801034f0000000809000029000000008a08043c0000000009a90436000000000059004b00000c950000c13d000000000006004b00000ca60000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000000003001f0002000000010355000000010020019000000d730000613d0000001f01400039000000e00110018f0000000802100029000000000012004b00000000010000390000000101004039000600000002001d000005570020009c000000610000213d0000000100100190000000610000c13d0000000601000029000000400010043f000000400030008c000003590000413d00000006010000290000058b0010009c000000610000213d00000006020000290000004001200039000000400010043f00000008010000290000000001010433000500000001001d000000000212043600000007010000290000000001010433000400000002001d00000000001204350000008002000039000000400300043d0000006401300039000000000021043500000044013000390000000d02000029000000000021043500000005020000390000002401300039000000000021043500000595010000410000000000130435000000040130003900000012020000290000000000210435000800000003001d000000840130003900000000000104350000059601000041000000000010044300000000010004120000000400100443000000200100003900000024001004430000000001000414000005530010009c0000055301008041000000c00110021000000597011001c70000800502000039154815430000040f000000010020019000000f220000613d000000000201043b0000000801000029000005530010009c000005530100804100000040011002100000000003000414000005530030009c0000055303008041000000c003300210000000000113019f00000598011001c70000055602200197154815430000040f00000060031002700000055303300197000000200030008c000000200400003900000000040340190000001f0640018f0000002007400190000000080570002900000d040000613d000000000801034f0000000809000029000000008a08043c0000000009a90436000000000059004b00000d000000c13d000000000006004b00000d110000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000000003001f0002000000010355000000010020019000000e030000613d0000001f01400039000000600210018f0000000801200029000000000021004b00000000020000390000000102004039000005570010009c000000610000213d0000000100200190000000610000c13d000000400010043f000000200030008c000003590000413d00000008010000290000000001010433000100000001001d0000001201000029000000000010043f0000000501000039000000200010043f0000000001000414000005530010009c0000055301008041000000c0011002100000055e011001c70000801002000039154815430000040f0000000100200190000003590000613d000000000101043b000000000201041a000000010320019000000001042002700000007f0440618f000700000004001d0000001f0040008c00000000040000390000000104002039000000000043004b000002d20000c13d000000400400043d000200000004001d00000007050000290000000004540436000800000004001d000000000003004b00000e0f0000613d000000000010043f0000000001000414000005530010009c0000055301008041000000c00110021000000599011001c70000801002000039154815430000040f0000000100200190000003590000613d000000070000006b000000000200001900000e150000613d000000000101043b00000000020000190000000803200029000000000401041a000000000043043500000001011000390000002002200039000000070020006c00000d530000413d00000e150000013d0000001f0530018f0000055506300198000000400200043d0000000004620019000005330000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b00000d620000c13d000005330000013d0000001f0530018f0000055506300198000000400200043d0000000004620019000005330000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b00000d6e0000c13d000005330000013d0000001f0530018f0000055506300198000000400200043d0000000004620019000005330000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b00000d7a0000c13d000005330000013d0000055b011001c70000800902000039000000130400002900000000050000191548153e0000040f00000060031002700000055303300197000000c00030008c000000c00400003900000000040340190000001f0640018f000000e007400190000000140570002900000d930000613d000000000801034f0000001409000029000000008a08043c0000000009a90436000000000059004b00000d8f0000c13d000000000006004b00000da00000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000000003001f0002000000010355000000010020019000000deb0000613d0000001f01400039000001e00210018f0000001401200029000000000021004b00000000020000390000000102004039000005570010009c000000610000213d0000000100200190000000610000c13d000000400010043f000000c00030008c000003590000413d000005930010009c000000610000213d0000006002100039000000400020043f0000001402000029000000000202043300000000032104360000000b020000290000000005020433000005570050009c000003590000213d00000014060000290000000002640019000000000053043500000040036000390000000004320049000005b20040009c000003590000213d000000400040008c000003590000413d000000400400043d0000058b0040009c000000610000213d0000004005400039000000400050043f0000000003030433000000000334043600000014060000290000006005600039000000000505043300000000005304350000004001100039000000000041043500000080016000390000000002120049000005b20020009c000003590000213d000000400020008c000003590000413d000000400200043d0000058b0020009c000000610000213d0000004003200039000000400030043f000000000101043300000000011204360000001402000029000000a00220003900000000020204330000000000210435000000060100002900000000010104330000000002000416000000000312004b00000f230000813d000000400100043d000005b602000041000008660000013d0000001f0530018f0000055506300198000000400200043d0000000004620019000005330000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b00000df20000c13d000005330000013d0000001f0530018f0000055506300198000000400200043d0000000004620019000005330000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b00000dfe0000c13d000005330000013d0000001f0530018f0000055506300198000000400200043d0000000004620019000005330000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b00000e0a0000c13d000005330000013d000005c10120019700000008020000290000000000120435000000070000006b000000200200003900000000020060390000003f01200039000005c2011001970000000202100029000000000012004b00000000010000390000000101004039000300000002001d000005570020009c000000610000213d0000000100100190000000610000c13d0000000301000029000000400010043f00000002010000290000000001010433000000000001004b00000e350000c13d00000003010000290000058b0010009c000000610000213d00000003020000290000004001200039000000400010043f00000020032000390000059a01000041000800000003001d000000000013043500000014010000390000000000120435000000400100043d000200000002001d000300000001001d000000030300002900000064013000390000008002000039000000000021043500000044013000390000002402000039000000000021043500000024013000390000000d0200002900000000002104350000059b0100004100000000001304350000000401300039000000120200002900000000002104350000000201000029000000000201043300000084013000390000000000210435000000a401300039000700000002001d000000000002004b00000e540000613d000000000200001900000000031200190000000804200029000000000404043300000000004304350000002002200039000000070020006c00000e4d0000413d00000007011000290000000000010435000005960100004100000000001004430000000001000412000000040010044300000024000004430000000001000414000005530010009c0000055301008041000000c00110021000000597011001c70000800502000039154815430000040f000000010020019000000f220000613d00000007020000290000001f02200039000005c202200197000000a402200039000005530020009c000005530200804100000060022002100000000303000029000300000003001d000005530030009c00000553030080410000004003300210000000000232019f000000000301043b0000000001000414000005530010009c0000055301008041000000c001100210000000000121019f0000055602300197154815430000040f00000060031002700000055303300197000000200030008c000000200400003900000000040340190000001f0640018f0000002007400190000000030570002900000e880000613d000000000801034f0000000309000029000000008a08043c0000000009a90436000000000059004b00000e840000c13d000000000006004b00000e950000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000000003001f0002000000010355000000010020019000000f4b0000613d0000001f01400039000000600110018f0000000302100029000000000012004b00000000010000390000000101004039000800000002001d000005570020009c000000610000213d0000000100100190000000610000c13d0000000801000029000000400010043f000000200030008c000003590000413d000000030100002900000000010104330000000302000039000000000302041a00000001023000b9000000010000006b00000eb20000613d00000001042000fa000000000034004b000006ab0000c13d000000000012001a000006ab0000413d000000000212001900000008030000290000004401300039000300000002001d00000000002104350000002401300039000000120200002900000000002104350000059c01000041000000000013043500000004013000390000000d020000290000000000210435000000640130003900000000000104350000059601000041000000000010044300000000010004120000000400100443000000400100003900000024001004430000000001000414000005530010009c0000055301008041000000c00110021000000597011001c70000800502000039154815430000040f000000010020019000000f220000613d000000000201043b0000000801000029000005530010009c000005530100804100000040011002100000000003000414000005530030009c0000055303008041000000c003300210000000000113019f0000059d011001c70000055602200197154815430000040f00000060031002700000055303300197000000200030008c000000200400003900000000040340190000001f0640018f0000002007400190000000080570002900000eee0000613d000000000801034f0000000809000029000000008a08043c0000000009a90436000000000059004b00000eea0000c13d000000000006004b00000efb0000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000000003001f0002000000010355000000010020019000000f570000613d0000001f01400039000000600110018f0000000801100029000700000001001d000005570010009c000000610000213d0000000701000029000000400010043f000000200030008c000003590000413d00000008010000290000000001010433000000030010002a000006ab0000413d0000000402000039000000000202041a000005c40020009c000006ab0000213d000000030310002a000027100220003900000000013200a900000f180000613d00000000033100d9000000000023004b000006ab0000c13d000027100110011a000000050010002a000006ab0000413d000800050010002d0000000002000416000000080020006c00000f630000813d000005b6010000410000000702000029000005220000013d000000000001042f000010c80000a13d0000000001000414000005530010009c0000055301008041000000c0011002100000055b011001c70000800902000039000000000400041100000000050000191548153e0000040f00020000000103550000006003100270000005530030019d0000055303300198000010c60000613d0000001f0430003900000554044001970000003f04400039000005ae04400197000000400500043d0000000004450019000000000054004b00000000060000390000000106004039000005570040009c000000610000213d0000000100600190000000610000c13d000000400040043f0000001f0430018f000000000635043600000555053001980000000003560019000010b90000613d000000000701034f000000007807043c0000000006860436000000000036004b00000f460000c13d000010b90000013d0000001f0530018f0000055506300198000000400200043d0000000004620019000005330000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b00000f520000c13d000005330000013d0000001f0530018f0000055506300198000000400200043d0000000004620019000005330000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b00000f5e0000c13d000005330000013d000005ab0100004100000007020000290000000000120435000005530020009c0000055301000041000000000102401900000040011002100000000002000414000005530020009c0000055302008041000000c002200210000000000112019f000005aa011001c70000001302000029154815430000040f00000060031002700000055303300197000000200030008c000000200400003900000000040340190000001f0640018f0000002007400190000000070570002900000f810000613d000000000801034f0000000709000029000000008a08043c0000000009a90436000000000059004b00000f7d0000c13d000000000006004b00000f8e0000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000000003001f00020000000103550000000100200190000010200000613d0000001f01400039000000600110018f0000000701100029000005570010009c000000610000213d000000400010043f000000200030008c000003590000413d00000007010000290000000001010433000005560010009c000003590000213d00000013020000290000000f03000029154813780000040f00000006010000290000000003010433000000400600043d000005b5010000410000000001160436000700000001001d000000040160003900000080020000390000000000210435000000140100002900000000010104330000055302100197000000840160003900000000002104350000000b020000290000000002020433000000a40460003900000000002404350000000c020000290000000002020433000000c40460003900000000002404350000000e020000290000000002020433000000e4046000390000000000240435000000110200002900000000020204330000010404600039000000e0050000390000000000540435000001640460003900000000520204340000000000240435001400000006001d0000018404600039000000000002004b00000fcf0000613d000000000600001900000000074600190000000008650019000000000808043300000000008704350000002006600039000000000026004b00000fc80000413d000000000542001900000000000504350000001f02200039000005c202200197000000000242001900000000041200490000000a05000029000000000505043300000014060000290000012406600039000000000046043500000000540504340000000002420436000000000004004b00000fe60000613d000000000600001900000000072600190000000008650019000000000808043300000000008704350000002006600039000000000046004b00000fdf0000413d000000000524001900000000000504350000001f04400039000005c204400197000000000524001900000000011500490000000902000029000000000202043300000014040000290000014404400039000000000014043500000000420204340000000001250436000000000002004b00000ffd0000613d000000000500001900000000061500190000000007540019000000000707043300000000007604350000002005500039000000000025004b00000ff60000413d00000000041200190000000000040435000000060400002900000000040404330000001407000029000000240570003900000000004504350000000404000029000000000404043300000064057000390000000d060000290000000000650435000000440570003900000000004504350000001f02200039000005c20220019700000000017100490000000001210019000005530010009c00000553010080410000006001100210000005530070009c000005530200004100000000020740190000004002200210000000000121019f0000000002000414000005530020009c0000055302008041000000c002200210000000000112019f000000000003004b0000102c0000c13d0000001302000029000010300000013d0000001f0530018f0000055506300198000000400200043d0000000004620019000005330000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000010270000c13d000005330000013d0000055b011001c70000800902000039000000130400002900000000050000191548153e0000040f00000060031002700000055303300197000000c00030008c000000c00400003900000000040340190000001f0640018f000000e0074001900000001405700029000010400000613d000000000801034f0000001409000029000000008a08043c0000000009a90436000000000059004b0000103c0000c13d000000000006004b0000104d0000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000000003001f00020000000103550000000100200190000010e10000613d0000001f01400039000001e00210018f0000001401200029000000000021004b00000000020000390000000102004039000005570010009c000000610000213d0000000100200190000000610000c13d000000400010043f000000c00030008c000003590000413d000005930010009c000000610000213d0000006002100039000000400020043f00000014020000290000000002020433000000000321043600000007020000290000000005020433000005570050009c000003590000213d00000014060000290000000002640019000000000053043500000040036000390000000004320049000005b20040009c000003590000213d000000400040008c000003590000413d000000400400043d0000058b0040009c000000610000213d0000004005400039000000400050043f0000000003030433000000000334043600000014060000290000006005600039000000000505043300000000005304350000004001100039000000000041043500000080016000390000000002120049000005b20020009c000003590000213d000000400020008c000003590000413d000000400200043d0000058b0020009c000000610000213d0000004003200039000000400030043f000000000101043300000000011204360000001402000029000000a002200039000000000202043300000000002104350000000002000416000000080320006c000010c80000a13d0000000001000414000005530010009c0000055301008041000000c0011002100000055b011001c70000800902000039000000000400041100000000050000191548153e0000040f00020000000103550000006003100270000005530030019d0000055303300198000010c60000613d0000001f0430003900000554044001970000003f04400039000005ae04400197000000400500043d0000000004450019000000000054004b00000000060000390000000106004039000005570040009c000000610000213d0000000100600190000000610000c13d000000400040043f0000001f0430018f000000000635043600000555053001980000000003560019000010b90000613d000000000701034f000000007807043c0000000006860436000000000036004b000010b50000c13d000000000004004b000010c60000613d000000000151034f0000000304400210000000000503043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f00000000001304350000000100200190000010ed0000613d000000400100043d00000020021000390000000f03000029000000000032043500000013020000290000000000210435000005530010009c000005530100804100000040011002100000000002000414000005530020009c0000055302008041000000c002200210000000000112019f0000055e011001c70000800d020000390000000403000039000005b9040000410000000005000411000000120600002900000010070000291548153e0000040f0000000100200190000000690000c13d000003590000013d0000001f0530018f0000055506300198000000400200043d0000000004620019000005330000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000010e80000c13d000005330000013d000000400100043d000005b802000041000008660000013d0003000000000002000000000201041a000000010320019000000001062002700000007f0660618f0000001f0060008c00000000040000390000000104002039000000000043004b0000112f0000c13d000000400500043d0000000004650436000000000003004b0000111a0000613d000100000004001d000300000006001d000200000005001d000000000010043f0000000001000414000005530010009c0000055301008041000000c00110021000000599011001c70000801002000039154815430000040f00000001002001900000113b0000613d0000000306000029000000000006004b000011200000613d000000000201043b0000000001000019000000020500002900000001070000290000000003170019000000000402041a000000000043043500000001022000390000002001100039000000000061004b000011120000413d000011220000013d000005c1012001970000000000140435000000000006004b00000020010000390000000001006039000011220000013d000000000100001900000002050000290000003f01100039000005c2021001970000000001520019000000000021004b00000000020000390000000102004039000005570010009c000011350000213d0000000100200190000011350000c13d000000400010043f0000000001050019000000000001042d000005b701000041000000000010043f0000002201000039000000040010043f00000561010000410000154a00010430000005b701000041000000000010043f0000004101000039000000040010043f00000561010000410000154a0001043000000000010000190000154a0001043000000000430104340000000001320436000000000003004b000011490000613d000000000200001900000000051200190000000006240019000000000606043300000000006504350000002002200039000000000032004b000011420000413d000000000213001900000000000204350000001f02300039000005c2022001970000000001210019000000000001042d0000000001000032000011790000613d000005c50010009c0000117a0000813d0000001f03100039000005c2033001970000003f03300039000005c204300197000000400300043d0000000004430019000000000034004b00000000050000390000000105004039000005570040009c0000117a0000213d00000001005001900000117a0000c13d000000400040043f0000000005130436000005c2021001980000001f0310018f000000000125001900000002040003670000116c0000613d000000000604034f000000006706043c0000000005750436000000000015004b000011680000c13d000000000003004b000011790000613d000000000224034f0000000303300210000000000401043300000000043401cf000000000434022f000000000202043b0000010003300089000000000232022f00000000023201cf000000000242019f0000000000210435000000000001042d000005b701000041000000000010043f0000004101000039000000040010043f00000561010000410000154a000104300006000000000002000000400400043d00000064024000390000008003000039000000000032043500000024024000390000000503000039000000000032043500000595020000410000000000240435000000000200041000000556032001970000004402400039000400000003001d000000000032043500000553021001970000000401400039000600000002001d0000000000210435000500000004001d000000840140003900000000000104350000059601000041000000000010044300000000010004120000000400100443000000200100003900000024001004430000000001000414000005530010009c0000055301008041000000c00110021000000597011001c70000800502000039154815430000040f0000000100200190000013250000613d000000000201043b0000000501000029000005530010009c000005530100804100000040011002100000000003000414000005530030009c0000055303008041000000c003300210000000000113019f00000598011001c70000055602200197154815430000040f00000060031002700000055303300197000000200030008c000000200400003900000000040340190000001f0640018f0000002007400190000000050b00002900000000057b0019000011c20000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b000011be0000c13d000000000006004b000011cf0000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000000003001f000200000001035500000001002001900000132c0000613d0000001f01400039000000600210018f0000000001b20019000000000021004b00000000020000390000000102004039000005570010009c0000131f0000213d00000001002001900000131f0000c13d000000400010043f0000001f0030008c0000131d0000a13d00000000010b0433000200000001001d0000000601000029000000000010043f0000000501000039000000200010043f0000000001000414000005530010009c0000055301008041000000c0011002100000055e011001c70000801002000039154815430000040f00000001002001900000131d0000613d000000000101043b000000000201041a000000010320019000000001072002700000007f0770618f0000001f0070008c00000000040000390000000104002039000000000043004b000013380000c13d000000400600043d0000000005760436000000000003004b000012190000613d000500000007001d000100000006001d000300000005001d000000000010043f0000000001000414000005530010009c0000055301008041000000c00110021000000599011001c70000801002000039154815430000040f00000001002001900000131d0000613d0000000507000029000000000007004b0000121f0000613d000000000201043b0000000001000019000000030500002900000001060000290000000003150019000000000402041a000000000043043500000001022000390000002001100039000000000071004b000012110000413d000012220000013d000005c1012001970000000000150435000000000007004b00000020010000390000000001006039000012220000013d0000000001000019000000030500002900000001060000290000003f01100039000005c2011001970000000003610019000000000013004b00000000010000390000000101004039000005570030009c0000131f0000213d00000001001001900000131f0000c13d000000400030043f0000000001060433000000000001004b0000123c0000c13d0000058b0030009c0000131f0000213d0000004001300039000000400010043f00000020053000390000059a01000041000000000015043500000014010000390000000000130435000000400100043d000000000603001900000000030100190000006401300039000000800200003900000000002104350000004401300039000000240200003900000000002104350000002401300039000000040200002900000000002104350000059b010000410000000000130435000000040130003900000006020000290000000000210435000000000606043300000084013000390000000000610435000500000003001d000000a401300039000000000006004b000012590000613d000000000200001900000000031200190000000004250019000000000404043300000000004304350000002002200039000000000062004b000012520000413d00000000011600190000000000010435000005960100004100000000001004430000000001000412000000040010044300000024000004430000000001000414000005530010009c0000055301008041000000c00110021000000597011001c70000800502000039000300000006001d154815430000040f0000000100200190000013250000613d00000003020000290000001f02200039000005c202200197000000a402200039000005530020009c000005530200804100000060022002100000000503000029000005530030009c00000553030080410000004003300210000000000232019f000000000301043b0000000001000414000005530010009c0000055301008041000000c001100210000000000121019f0000055602300197154815430000040f000000050b00002900000060031002700000055303300197000000200030008c000000200400003900000000040340190000001f0640018f000000200740019000000000057b00190000128e0000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b0000128a0000c13d000000000006004b0000129b0000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000000003001f000200000001035500000001002001900000133e0000613d0000001f01400039000000600110018f0000000005b10019000000000015004b00000000010000390000000101004039000005570050009c0000131f0000213d00000001001001900000131f0000c13d000000400050043f000000200030008c0000131d0000413d00000000010b04330000000302000039000000000302041a000000020400002900000000023400a9000000000004004b000012b60000613d00000000044200d9000000000034004b000013260000c13d000000000012001a000013260000413d00000000021200190000004401500039000500000002001d00000000002104350000002401500039000000060200002900000000002104350000059c010000410000000000150435000000040150003900000004020000290000000000210435000000640150003900000000000104350000059601000041000000000010044300000000010004120000000400100443000000400100003900000024001004430000000001000414000005530010009c0000055301008041000000c00110021000000597011001c70000800502000039000300000005001d154815430000040f0000000100200190000013250000613d000000000201043b0000000301000029000005530010009c000005530100804100000040011002100000000003000414000005530030009c0000055303008041000000c003300210000000000113019f0000059d011001c70000055602200197154815430000040f00000060031002700000055303300197000000200030008c000000200400003900000000040340190000001f0640018f0000002007400190000000030b00002900000000057b0019000012f30000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b000012ef0000c13d000000000006004b000013000000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000000003001f000200000001035500000001002001900000134a0000613d0000001f01400039000000600110018f0000000001b10019000005570010009c0000131f0000213d000000400010043f000000200030008c0000131d0000413d00000000010b04330000000504000029000000000041001a000013260000413d0000000402000039000000000202041a000005c40020009c000013260000213d000000000341001a000027100220003900000000013200a90000131b0000613d00000000033100d9000000000023004b000013260000c13d000027100110011a000000000001042d00000000010000190000154a00010430000005b701000041000000000010043f0000004101000039000000040010043f00000561010000410000154a00010430000000000001042f000005b701000041000000000010043f0000001101000039000000040010043f00000561010000410000154a000104300000001f0530018f0000055506300198000000400200043d0000000004620019000013550000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000013330000c13d000013550000013d000005b701000041000000000010043f0000002201000039000000040010043f00000561010000410000154a000104300000001f0530018f0000055506300198000000400200043d0000000004620019000013550000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000013450000c13d000013550000013d0000001f0530018f0000055506300198000000400200043d0000000004620019000013550000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000013510000c13d000000000005004b000013620000613d000000000161034f0000000305500210000000000604043300000000065601cf000000000656022f000000000101043b0000010005500089000000000151022f00000000015101cf000000000161019f00000000001404350000006001300210000005530020009c00000553020080410000004002200210000000000112019f0000154a00010430000000000100041a00000556021001970000000001000411000000000012004b0000136e0000c13d000000000001042d000000400200043d0000058503000041000000000032043500000004032000390000000000130435000005530020009c0000055302008041000000400120021000000561011001c70000154a000104300007000000000002000000400500043d000000440450003900000000003404350000002003500039000005c60400004100000000004304350000004404000039000000000045043500000556042001970000002402500039000300000004001d0000000000420435000400000005001d000005c70050009c000014cf0000813d00000004040000290000008002400039000000400020043f0000000002040433000005530020009c000005530200804100000060022002100000000004000414000005530040009c0000055304008041000000c004400210000000000424019f0000055602100197000005530030009c0000055303008041000200400030021800000002014001af000500000002001d1548153e0000040f00020000000103550000006003100270000005530030019d0000055305300198000013c90000613d0000001f0350003900000554033001970000003f03300039000005ae04300197000000400300043d0000000004430019000000000034004b00000000060000390000000106004039000005570040009c000014cf0000213d0000000100600190000014cf0000c13d000000400040043f0000001f0650018f000000000453043600000555075001980000000005740019000013b90000613d000000000801034f0000000009040019000000008a08043c0000000009a90436000000000059004b000013b50000c13d000000000006004b000013c60000613d000000000171034f0000000306600210000000000705043300000000076701cf000000000767022f000000000101043b0000010006600089000000000161022f00000000016101cf000000000171019f00000000001504350000000100200190000013cd0000c13d000013f70000013d000000600300003900000080040000390000000100200190000013f70000613d0000000002000415000000070220008a00000005022002100000000001030433000000000001004b000013e20000613d000005b20010009c000014d50000213d0000001f0010008c000014d50000a13d0000000001040433000000000001004b0000000002000039000000010200c039000000000021004b000014d50000c13d0000000002000415000000060220008a0000000502200210000000000001004b000013f70000613d000100000002001d000005b0010000410000000000100443000000050100002900000004001004430000000001000414000005530010009c0000055301008041000000c001100210000005b1011001c70000800202000039154815430000040f0000000100200190000014e40000613d000000000101043b000000000001004b00000001010000290000000501100270000000000100003f000000010100c03f000014ce0000c13d000000400100043d0000002002100039000005c603000041000000000032043500000024031000390000000304000029000000000043043500000044030000390000000000310435000000440310003900000000000304350000058d0010009c000014cf0000213d0000008003100039000000400030043f000005530020009c000005530200804100000040022002100000000001010433000005530010009c00000553010080410000006001100210000000000121019f0000000002000414000005530020009c0000055302008041000000c002200210000000000121019f00000005020000291548153e0000040f00020000000103550000006003100270000005530030019d0000055303300198000014410000613d0000001f0430003900000554044001970000003f04400039000005ae04400197000000400a00043d00000000044a00190000000000a4004b00000000050000390000000105004039000005570040009c000014cf0000213d0000000100500190000014cf0000c13d000000400040043f0000001f0430018f00000000093a043600000555053001980000000003590019000014330000613d000000000601034f0000000007090019000000006806043c0000000007870436000000000037004b0000142f0000c13d000000000004004b000014430000613d000000000151034f0000000304400210000000000503043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f0000000000130435000014430000013d000000600a000039000000800900003900000000010a04330000000100200190000014d70000613d000000000001004b0000145f0000c13d00030000000a001d000100000009001d000005b0010000410000000000100443000000050100002900000004001004430000000001000414000005530010009c0000055301008041000000c001100210000005b1011001c70000800202000039154815430000040f0000000100200190000014e40000613d000000000101043b000000000001004b0000000301000029000014ed0000613d0000000001010433000000000001004b00000001090000290000146b0000613d000005b20010009c000014d50000213d000000200010008c000014d50000413d0000000001090433000000000001004b0000000002000039000000010200c039000000000021004b000014d50000c13d000000000001004b000014e10000613d00000004010000290000000001010433000005530010009c000005530100804100000060011002100000000002000414000005530020009c0000055302008041000000c002200210000000000112019f00000002011001af00000005020000291548153e0000040f00020000000103550000006003100270000005530030019d0000055303300198000014a40000613d0000001f0430003900000554044001970000003f04400039000005ae04400197000000400a00043d00000000044a00190000000000a4004b00000000050000390000000105004039000005570040009c000014cf0000213d0000000100500190000014cf0000c13d000000400040043f0000001f0430018f00000000093a043600000555053001980000000003590019000014960000613d000000000601034f0000000007090019000000006806043c0000000007870436000000000037004b000014920000c13d000000000004004b000014a60000613d000000000151034f0000000304400210000000000503043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f0000000000130435000014a60000013d000000600a000039000000800900003900000000010a04330000000100200190000014d70000613d000000000001004b000014c20000c13d00040000000a001d000300000009001d000005b0010000410000000000100443000000050100002900000004001004430000000001000414000005530010009c0000055301008041000000c001100210000005b1011001c70000800202000039154815430000040f0000000100200190000014e40000613d000000000101043b000000000001004b0000000401000029000014ed0000613d0000000001010433000000000001004b0000000309000029000014ce0000613d000005b20010009c000014d50000213d000000200010008c000014d50000413d0000000001090433000000000001004b0000000002000039000000010200c039000000000021004b000014d50000c13d000000000001004b000014e10000613d000000000001042d000005b701000041000000000010043f0000004101000039000000040010043f00000561010000410000154a0001043000000000010000190000154a00010430000000000001004b000014e50000c13d000000400100043d000005af020000410000000000210435000005530010009c00000553010080410000004001100210000005aa011001c70000154a00010430000000400100043d000005b302000041000014ef0000013d000000000001042f000005530090009c00000553090080410000004002900210000005530010009c00000553010080410000006001100210000000000121019f0000154a00010430000000400100043d000005ba020000410000000000210435000000040210003900000005030000290000000000320435000005530010009c0000055301008041000000400110021000000561011001c70000154a000104300000000002010433000000010020008c000014fe0000a13d00000002011000390000000001010433000000000001042d000000400100043d0000004402100039000005a1030000410000000000320435000000240210003900000014030000390000000000320435000005a0020000410000000000210435000000040210003900000020030000390000000000320435000005530010009c00000553010080410000004001100210000005a2011001c70000154a00010430000000000001042f000005530010009c00000553010080410000004001100210000005530020009c00000553020080410000006002200210000000000112019f0000000002000414000005530020009c0000055302008041000000c002200210000000000112019f0000055b011001c70000801002000039154815430000040f0000000100200190000015230000613d000000000101043b000000000001042d00000000010000190000154a0001043000000000050100190000000000200443000000040100003900000005024002700000000002020031000000000121043a0000002004400039000000000031004b000015280000413d000005530030009c000005530300804100000060013002100000000002000414000005530020009c0000055302008041000000c002200210000000000112019f000005c8011001c70000000002050019154815430000040f00000001002001900000153d0000613d000000000101043b000000000001042d000000000001042f00001541002104210000000102000039000000000001042d0000000002000019000000000001042d00001546002104230000000102000039000000000001042d0000000002000019000000000001042d0000154800000432000015490001042e0000154a00010430000000000000000000000000000000000000000000000000000000000000000000000000ffffffff00000000000000000000000000000000000000000000000000000001ffffffe000000000000000000000000000000000000000000000000000000000ffffffe0000000000000000000000000ffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000000000000000ffffffffffffffff80000000000000000000000000000000000000000000000000000000000000007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0ffffffffffffffffffffffff000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000008be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0ffffffffffffffffffffff000000000000000000000000000000000000000000020000000000000000000000000000000000004000000000000000000000000000000002000000000000000000000000000001000000010000000000000000001e4fbdf70000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000000000000000000000067fb473700000000000000000000000000000000000000000000000000000000b218b19700000000000000000000000000000000000000000000000000000000e30c397700000000000000000000000000000000000000000000000000000000efb7998400000000000000000000000000000000000000000000000000000000efb7998500000000000000000000000000000000000000000000000000000000f2fde38b00000000000000000000000000000000000000000000000000000000e30c397800000000000000000000000000000000000000000000000000000000ec1278d600000000000000000000000000000000000000000000000000000000b218b19800000000000000000000000000000000000000000000000000000000c616f37600000000000000000000000000000000000000000000000000000000d393f0720000000000000000000000000000000000000000000000000000000079ba50960000000000000000000000000000000000000000000000000000000079ba5097000000000000000000000000000000000000000000000000000000008153924b000000000000000000000000000000000000000000000000000000008da5cb5b0000000000000000000000000000000000000000000000000000000067fb473800000000000000000000000000000000000000000000000000000000715018a60000000000000000000000000000000000000000000000000000000077958f87000000000000000000000000000000000000000000000000000000003e832c8f000000000000000000000000000000000000000000000000000000005b461c82000000000000000000000000000000000000000000000000000000005e8c18d9000000000000000000000000000000000000000000000000000000005e8c18da00000000000000000000000000000000000000000000000000000000630dc7cb000000000000000000000000000000000000000000000000000000005b461c83000000000000000000000000000000000000000000000000000000005c975abb000000000000000000000000000000000000000000000000000000003e832c90000000000000000000000000000000000000000000000000000000005135db460000000000000000000000000000000000000000000000000000000059c7c5160000000000000000000000000000000000000000000000000000000024df604a0000000000000000000000000000000000000000000000000000000024df604b000000000000000000000000000000000000000000000000000000002d2c5565000000000000000000000000000000000000000000000000000000003e0c06290000000000000000000000000000000000000000000000000000000002329a2900000000000000000000000000000000000000000000000000000000104db380000000000000000000000000000000000000000000000000000000001171bda9118cdaa700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002400000080000000000000000038d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e22700963efcaa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000c000000000000000000003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffbf000000000000000000000000000f424000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffff7f3a51740d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000100000000000000000000000000000000000000000000000000000000000000ffff0000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffff9f3b6f743b0000000000000000000000000000000000000000000000000000000030bb3aac00000000000000000000000000000000000000000000000000000000310ab089e4439a4c15d089f94afb7896ff553aecb10793d0ab882de59d99a32e020000020000000000000000000000000000004400000000000000000000000000000000000000000000000000000000000000a4000000000000000000000000020000000000000000000000000000000000002000000000000000000000000001001101000000000000000000000000000493e0000000000000000000000000709eb66400000000000000000000000000000000000000000000000000000000d42442210000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000840000000000000000000000006dfcc65000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004400000000000000000000000008c379a000000000000000000000000000000000000000000000000000000000746f55696e7431365f6f75744f66426f756e64730000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffdf0000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002000000080000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000ff0000000000000000000000000000000000000000819f99390000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000008000000000000000000000000000000000000000000000000000000004000000000000000000000000fc0c546a0000000000000000000000000000000000000000000000000000000023b872dd00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffff5f00000000000000000000000000000000000000000000000000000003ffffffe01425ea42000000000000000000000000000000000000000000000000000000001806aa1896bbf26568e884a7374b41e002500962caba6a15023a8d90e8508b8302000002000000000000000000000000000000240000000000000000000000007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5274afe700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffff1fc7c7f5b300000000000000000000000000000000000000000000000000000000025dbdd4000000000000000000000000000000000000000000000000000000004e487b7100000000000000000000000000000000000000000000000000000000f0c49d4400000000000000000000000000000000000000000000000000000000bc9ee36b6ca0bdd5b3840e6d329dd19a2490d880c7ce24d9818aa593adfb35be9996b315000000000000000000000000000000000000000000000000000000004fdf5da6000000000000000000000000000000000000000000000000000000007413e48600000000000000000000000000000000000000000000000000000000a9059cbb0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000440000008000000000000000000000000000000000000000010000000000000000000000000000000000000000ffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd8ef0000000000000000000000000000000000000000000000010000000000000000095ea7b300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffff80020000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005b8cd0493e773cf72497e0d50c4c36c6b0e67433c30ef703e982b021a406dd1c
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000002a2019b30c157db6c1c01306b8025167dbe1803b0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000643e1471f37c4680df30cf0c540cd379a0ff58a5000000000000000000000000f4da94b4ee9d8e209e3bf9f469221ce2731a711200000000000000000000000054f1deb345306f326096a2dce26c0dd05e7b595a00000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000006000000000000000000000000ea77c590bb36c43ef7139ce649cfbcfd6163170d0000000000000000000000009f87fbb47c33cd0614e43500b9511018116f79ee000000000000000000000000c7ab797019156b543b7a3fbf5a99ecdab9eb4440000000000000000000000000fd78fd3667def2f1097ed221ec503ae477155394000000000000000000000000af01ae13fb67ad2bb2d76f29a83961069a5f245f000000000000000000000000580f2ee1476edf4b1760bd68f6aabad57dec420e
-----Decoded View---------------
Arg [0] : _fraxtalHop (bytes32): 0x0000000000000000000000002a2019b30c157db6c1c01306b8025167dbe1803b
Arg [1] : _numDVNs (uint256): 2
Arg [2] : _EXECUTOR (address): 0x643E1471f37c4680Df30cF0C540Cd379a0fF58A5
Arg [3] : _DVN (address): 0xF4DA94b4EE9D8e209e3bf9f469221CE2731A7112
Arg [4] : _TREASURY (address): 0x54f1DEB345306F326096a2dce26c0DD05e7B595A
Arg [5] : _approvedOfts (address[]): 0xEa77c590Bb36c43ef7139cE649cFBCFD6163170d,0x9F87fbb47C33Cd0614E43500b9511018116F79eE,0xc7Ab797019156b543B7a3fBF5A99ECDab9eb4440,0xFD78FD3667DeF2F1097Ed221ec503AE477155394,0xAf01aE13Fb67AD2bb2D76f29A83961069a5F245F,0x580F2ee1476eDF4B1760bd68f6AaBaD57dec420E
-----Encoded View---------------
13 Constructor Arguments found :
Arg [0] : 0000000000000000000000002a2019b30c157db6c1c01306b8025167dbe1803b
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000002
Arg [2] : 000000000000000000000000643e1471f37c4680df30cf0c540cd379a0ff58a5
Arg [3] : 000000000000000000000000f4da94b4ee9d8e209e3bf9f469221ce2731a7112
Arg [4] : 00000000000000000000000054f1deb345306f326096a2dce26c0dd05e7b595a
Arg [5] : 00000000000000000000000000000000000000000000000000000000000000c0
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000006
Arg [7] : 000000000000000000000000ea77c590bb36c43ef7139ce649cfbcfd6163170d
Arg [8] : 0000000000000000000000009f87fbb47c33cd0614e43500b9511018116f79ee
Arg [9] : 000000000000000000000000c7ab797019156b543b7a3fbf5a99ecdab9eb4440
Arg [10] : 000000000000000000000000fd78fd3667def2f1097ed221ec503ae477155394
Arg [11] : 000000000000000000000000af01ae13fb67ad2bb2d76f29a83961069a5f245f
Arg [12] : 000000000000000000000000580f2ee1476edf4b1760bd68f6aabad57dec420e
Loading...
Loading
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|---|---|---|---|---|
| ZKSYNC | 100.00% | $2,943.49 | 0.00041866 | $1.23 |
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.