Source Code
Latest 25 from a total of 41 transactions
| Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Deposit | 28812185 | 5 mins ago | IN | 0 ETH | 0.00000003 | ||||
| Deposit | 28812134 | 6 mins ago | IN | 0 ETH | 0.00000003 | ||||
| Transfer Ownersh... | 28616133 | 3 days ago | IN | 0 ETH | 0.00000019 | ||||
| Deposit | 28552296 | 4 days ago | IN | 0 ETH | 0.00000003 | ||||
| Deposit | 28329980 | 7 days ago | IN | 0 ETH | 0.00000002 | ||||
| Deposit | 28305634 | 7 days ago | IN | 0 ETH | 0.00000059 | ||||
| Deposit | 28147191 | 10 days ago | IN | 0 ETH | 0.00000003 | ||||
| Deposit | 28115247 | 10 days ago | IN | 0 ETH | 0.00000011 | ||||
| Deposit | 27758681 | 18 days ago | IN | 0 ETH | 0.00000003 | ||||
| Deposit | 27754642 | 18 days ago | IN | 0 ETH | 0.00000062 | ||||
| Deposit | 27739055 | 19 days ago | IN | 0 ETH | 0.00000062 | ||||
| Deposit | 27734445 | 19 days ago | IN | 0 ETH | 0.00000056 | ||||
| Deposit | 27732797 | 19 days ago | IN | 0 ETH | 0.0000007 | ||||
| Deposit | 27708852 | 20 days ago | IN | 0 ETH | 0.00000003 | ||||
| Deposit | 27532719 | 23 days ago | IN | 0 ETH | 0.00000005 | ||||
| Deposit | 27249851 | 29 days ago | IN | 0 ETH | 0.00000002 | ||||
| Deposit | 26919112 | 36 days ago | IN | 0 ETH | 0.00000002 | ||||
| Deposit | 26752662 | 39 days ago | IN | 0 ETH | 0.00000002 | ||||
| Deposit | 26736902 | 39 days ago | IN | 0 ETH | 0.00000005 | ||||
| Deposit | 26736851 | 39 days ago | IN | 0 ETH | 0.00000003 | ||||
| Deposit | 26736748 | 39 days ago | IN | 0 ETH | 0.00000059 | ||||
| Deposit | 26736644 | 39 days ago | IN | 0 ETH | 0.00000003 | ||||
| Deposit | 26735954 | 39 days ago | IN | 0 ETH | 0.0000006 | ||||
| Deposit | 26735890 | 39 days ago | IN | 0 ETH | 0.00000004 | ||||
| Deposit | 26735843 | 39 days ago | IN | 0 ETH | 0.00000059 |
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 28806658 | 2 hrs ago | 0.00019933 ETH | ||||
| 28806658 | 2 hrs ago | 0.00019933 ETH | ||||
| 28785053 | 11 hrs ago | 0.00030331 ETH | ||||
| 28785053 | 11 hrs ago | 0.00030331 ETH | ||||
| 28783309 | 12 hrs ago | 0.00025018 ETH | ||||
| 28783309 | 12 hrs ago | 0.00025018 ETH | ||||
| 28768433 | 18 hrs ago | 0.00019883 ETH | ||||
| 28768433 | 18 hrs ago | 0.00019883 ETH | ||||
| 28764667 | 19 hrs ago | 0.00019521 ETH | ||||
| 28764667 | 19 hrs ago | 0.00019521 ETH | ||||
| 28748956 | 25 hrs ago | 0.00019773 ETH | ||||
| 28748956 | 25 hrs ago | 0.00019773 ETH | ||||
| 28748182 | 25 hrs ago | 0.00019605 ETH | ||||
| 28748182 | 25 hrs ago | 0.00019605 ETH | ||||
| 28680275 | 2 days ago | 0.00020556 ETH | ||||
| 28680275 | 2 days ago | 0.00020556 ETH | ||||
| 28650645 | 2 days ago | 0.00028034 ETH | ||||
| 28650645 | 2 days ago | 0.00028034 ETH | ||||
| 28619370 | 3 days ago | 0.00020242 ETH | ||||
| 28619370 | 3 days ago | 0.00020242 ETH | ||||
| 28602282 | 3 days ago | 0.00023687 ETH | ||||
| 28602282 | 3 days ago | 0.00023687 ETH | ||||
| 28593664 | 3 days ago | 0.00027305 ETH | ||||
| 28593664 | 3 days ago | 0.00027305 ETH | ||||
| 28588225 | 3 days ago | 0.00029278 ETH |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
LayerZeroTellerWithRateLimiting
Compiler Version
v0.8.21+commit.d9974bed
Optimization Enabled:
Yes with 200 runs
Other Settings:
shanghai EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.21;
import {
CrossChainTellerWithGenericBridge, ERC20
} from "src/base/Roles/CrossChain/CrossChainTellerWithGenericBridge.sol";
import {SafeTransferLib} from "@solmate/utils/SafeTransferLib.sol";
import {OAppAuth, Origin, MessagingFee, MessagingReceipt} from "@oapp-auth/OAppAuth.sol";
import {AddressToBytes32Lib} from "src/helper/AddressToBytes32Lib.sol";
import {OptionsBuilder} from "@oapp-auth/OptionsBuilder.sol";
import {PairwiseRateLimiter} from "src/base/Roles/CrossChain/PairwiseRateLimiter.sol";
import {MessageLib} from "src/base/Roles/CrossChain/MessageLib.sol";
contract LayerZeroTellerWithRateLimiting is CrossChainTellerWithGenericBridge, OAppAuth, PairwiseRateLimiter {
using SafeTransferLib for ERC20;
using AddressToBytes32Lib for address;
using AddressToBytes32Lib for bytes32;
using OptionsBuilder for bytes;
using MessageLib for uint256;
// ========================================= STRUCTS =========================================
/**
* @notice Stores information about a chain.
* @dev Sender is stored in OAppAuthCore `peers` mapping.
* @param allowMessagesFrom Whether to allow messages from this chain.
* @param allowMessagesTo Whether to allow messages to this chain.
* @param messageGasLimit The gas limit for messages to this chain.
*/
struct Chain {
bool allowMessagesFrom;
bool allowMessagesTo;
uint128 messageGasLimit;
}
// ========================================= STATE =========================================
/**
* @notice Maps chain selector to chain information.
*/
mapping(uint32 => Chain) public idToChains;
//============================== ERRORS ===============================
error LayerZeroTeller__MessagesNotAllowedFrom(uint256 chainSelector);
error LayerZeroTeller__MessagesNotAllowedFromSender(uint256 chainSelector, address sender);
error LayerZeroTeller__MessagesNotAllowedTo(uint256 chainSelector);
error LayerZeroTeller__FeeExceedsMax(uint256 chainSelector, uint256 fee, uint256 maxFee);
error LayerZeroTeller__BadFeeToken();
error LayerZeroTeller__ZeroMessageGasLimit();
//============================== EVENTS ===============================
event ChainAdded(uint256 chainId, bool allowMessagesFrom, bool allowMessagesTo, address targetTeller);
event ChainRemoved(uint256 chainId);
event ChainAllowMessagesFrom(uint256 chainId, address targetTeller);
event ChainAllowMessagesTo(uint256 chainId, address targetTeller);
event ChainStopMessagesFrom(uint256 chainId);
event ChainStopMessagesTo(uint256 chainId);
event ChainSetGasLimit(uint256 chainId, uint128 messageGasLimit);
//============================== IMMUTABLES ===============================
/**
* @notice The LayerZero token.
*/
address internal immutable lzToken;
constructor(
address _owner,
address _vault,
address _accountant,
address _weth,
address _lzEndPoint,
address _delegate,
address _lzToken
) CrossChainTellerWithGenericBridge(_owner, _vault, _accountant, _weth) OAppAuth(_lzEndPoint, _delegate) {
lzToken = _lzToken;
}
// ========================================= ADMIN FUNCTIONS =========================================
/**
* @notice Add a chain to the teller.
* @dev Callable by OWNER_ROLE.
* @param chainId The LayerZero chain id to add.
* @param allowMessagesFrom Whether to allow messages from this chain.
* @param allowMessagesTo Whether to allow messages to this chain.
* @param targetTeller The address of the target teller on the other chain.
* @param messageGasLimit The gas limit for messages to this chain.
*/
function addChain(
uint32 chainId,
bool allowMessagesFrom,
bool allowMessagesTo,
address targetTeller,
uint128 messageGasLimit
) external requiresAuth {
if (allowMessagesTo && messageGasLimit == 0) {
revert LayerZeroTeller__ZeroMessageGasLimit();
}
idToChains[chainId] = Chain(allowMessagesFrom, allowMessagesTo, messageGasLimit);
_setPeer(chainId, targetTeller.toBytes32());
emit ChainAdded(chainId, allowMessagesFrom, allowMessagesTo, targetTeller);
}
/**
* @notice Remove a chain from the teller.
* @dev Callable by MULTISIG_ROLE.
*/
function removeChain(uint32 chainId) external requiresAuth {
delete idToChains[chainId];
_setPeer(chainId, bytes32(0));
emit ChainRemoved(chainId);
}
/**
* @notice Allow messages from a chain.
* @dev Callable by OWNER_ROLE.
*/
function allowMessagesFromChain(uint32 chainId, address targetTeller) external requiresAuth {
Chain storage chain = idToChains[chainId];
chain.allowMessagesFrom = true;
_setPeer(chainId, targetTeller.toBytes32());
emit ChainAllowMessagesFrom(chainId, targetTeller);
}
/**
* @notice Allow messages to a chain.
* @dev Callable by OWNER_ROLE.
*/
function allowMessagesToChain(uint32 chainId, address targetTeller, uint128 messageGasLimit)
external
requiresAuth
{
if (messageGasLimit == 0) {
revert LayerZeroTeller__ZeroMessageGasLimit();
}
Chain storage chain = idToChains[chainId];
chain.allowMessagesTo = true;
chain.messageGasLimit = messageGasLimit;
_setPeer(chainId, targetTeller.toBytes32());
emit ChainAllowMessagesTo(chainId, targetTeller);
}
/**
* @notice Stop messages from a chain.
* @dev Callable by MULTISIG_ROLE.
*/
function stopMessagesFromChain(uint32 chainId) external requiresAuth {
Chain storage chain = idToChains[chainId];
chain.allowMessagesFrom = false;
emit ChainStopMessagesFrom(chainId);
}
/**
* @notice Stop messages to a chain.
* @dev Callable by MULTISIG_ROLE.
*/
function stopMessagesToChain(uint32 chainId) external requiresAuth {
Chain storage chain = idToChains[chainId];
chain.allowMessagesTo = false;
emit ChainStopMessagesTo(chainId);
}
/**
* @notice Set outbound rate limit configurations.
* @dev Callable by MULTISIG_ROLE.
*/
function setOutboundRateLimits(RateLimitConfig[] calldata _rateLimitConfigs) external requiresAuth {
_setOutboundRateLimits(_rateLimitConfigs);
}
/**
* @notice Set inbound rate limit configurations.
* @dev Callable by MULTISIG_ROLE.
*/
function setInboundRateLimits(RateLimitConfig[] calldata _rateLimitConfigs) external requiresAuth {
_setInboundRateLimits(_rateLimitConfigs);
}
/**
* @notice Set the gas limit for messages to a chain.
* @dev Callable by OWNER_ROLE.
*/
function setChainGasLimit(uint32 chainId, uint128 messageGasLimit) external requiresAuth {
if (messageGasLimit == 0) {
revert LayerZeroTeller__ZeroMessageGasLimit();
}
Chain storage chain = idToChains[chainId];
chain.messageGasLimit = messageGasLimit;
emit ChainSetGasLimit(chainId, messageGasLimit);
}
// ========================================= OAppAuthReceiver =========================================
/**
* @notice Receive messages from the LayerZero endpoint.
* @dev `lzReceive` only sanitizes the message sender, but we also need to make sure we are allowing messages
* from the source chain.
*/
function _lzReceive(
Origin calldata _origin,
bytes32 _guid,
bytes calldata _message,
address, /*_executor*/
bytes calldata /*_extraData*/
) internal override {
Chain memory source = idToChains[_origin.srcEid];
if (!source.allowMessagesFrom) revert LayerZeroTeller__MessagesNotAllowedFrom(_origin.srcEid);
uint256 message = abi.decode(_message, (uint256));
_checkAndUpdateInboundRateLimit(_origin.srcEid, message.uint256ToMessage().shareAmount);
_completeMessageReceive(_guid, message);
}
// ========================================= INTERNAL BRIDGE FUNCTIONS =========================================
/**
* @notice Sends messages using Layer Zero end point.
* @dev This function does NOT revert if the `feeToken` is invalid,
* rather the Layer Zero end point will revert.
* @dev This function will revert if maxFee is exceeded.
* @dev This function will revert if destination chain does not allow messages.
* @param message The message to send.
* @param bridgeWildCard An abi encoded uint32 containing the destination chain id.
* @param feeToken The token to pay the bridge fee in.
* @param maxFee The maximum fee to pay the bridge.
*/
function _sendMessage(uint256 message, bytes calldata bridgeWildCard, ERC20 feeToken, uint256 maxFee)
internal
override
returns (bytes32 messageId)
{
uint32 destinationId = abi.decode(bridgeWildCard, (uint32));
_checkAndUpdateOutboundRateLimit(destinationId, message.uint256ToMessage().shareAmount);
Chain memory chain = idToChains[destinationId];
if (!chain.allowMessagesTo) {
revert LayerZeroTeller__MessagesNotAllowedTo(destinationId);
}
bytes memory m = abi.encode(message);
bytes memory options = OptionsBuilder.newOptions().addExecutorLzReceiveOption(chain.messageGasLimit, 0);
MessagingFee memory fee = _quote(destinationId, m, options, address(feeToken) != NATIVE);
if (address(feeToken) == NATIVE) {
if (fee.nativeFee > maxFee) {
revert LayerZeroTeller__FeeExceedsMax(destinationId, fee.nativeFee, maxFee);
}
} else if (address(feeToken) == lzToken) {
if (fee.lzTokenFee > maxFee) {
revert LayerZeroTeller__FeeExceedsMax(destinationId, fee.lzTokenFee, maxFee);
}
} else {
revert LayerZeroTeller__BadFeeToken();
}
MessagingReceipt memory receipt = _lzSend(destinationId, m, options, fee, msg.sender);
messageId = receipt.guid;
}
/**
* @notice Preview fee required to bridge shares in a given feeToken.
* @param message The message to send.
* @param bridgeWildCard An abi encoded uint32 containing the destination chain id.
* @param feeToken The token to pay the bridge fee in.
*/
function _previewFee(uint256 message, bytes calldata bridgeWildCard, ERC20 feeToken)
internal
view
override
returns (uint256 fee)
{
// Make sure feeToken is either NATIVE or lzToken.
if (address(feeToken) != NATIVE && address(feeToken) != lzToken) {
revert LayerZeroTeller__BadFeeToken();
}
uint32 destinationId = abi.decode(bridgeWildCard, (uint32));
Chain memory chain = idToChains[destinationId];
if (!chain.allowMessagesTo) {
revert LayerZeroTeller__MessagesNotAllowedTo(destinationId);
}
bytes memory m = abi.encode(message);
bytes memory options = OptionsBuilder.newOptions().addExecutorLzReceiveOption(chain.messageGasLimit, 0);
MessagingFee memory messageFee = _quote(destinationId, m, options, address(feeToken) != NATIVE);
fee = address(feeToken) == NATIVE ? messageFee.nativeFee : messageFee.lzTokenFee;
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.21;
import {TellerWithMultiAssetSupport, ERC20} from "src/base/Roles/TellerWithMultiAssetSupport.sol";
import {MessageLib} from "src/base/Roles/CrossChain/MessageLib.sol";
abstract contract CrossChainTellerWithGenericBridge is TellerWithMultiAssetSupport {
using MessageLib for uint256;
using MessageLib for MessageLib.Message;
//============================== ERRORS ===============================
error CrossChainTellerWithGenericBridge__UnsafeCastToUint96();
//============================== EVENTS ===============================
event MessageSent(bytes32 indexed messageId, uint256 shareAmount, address indexed to);
event MessageReceived(bytes32 indexed messageId, uint256 shareAmount, address indexed to);
//============================== IMMUTABLES ===============================
constructor(address _owner, address _vault, address _accountant, address _weth)
TellerWithMultiAssetSupport(_owner, _vault, _accountant, _weth)
{}
// ========================================= PUBLIC FUNCTIONS =========================================
/**
* @notice Deposit an asset and bridge the shares to another chain.
* @dev This function will REVERT if `beforeTransfer` hook reverts from:
* - shares being locked
* - allow list
* @dev Since call to `bridge` is public, msg.sig is not updated which means any role capabilities regarding this function
* are also granted to the `bridge` function.
*/
function depositAndBridge(
ERC20 depositAsset,
uint256 depositAmount,
uint256 minimumMint,
address to,
bytes calldata bridgeWildCard,
ERC20 feeToken,
uint256 maxFee
)
external
payable
requiresAuth
nonReentrant
revertOnNativeDeposit(address(depositAsset))
returns (uint256 sharesBridged)
{
// Deposit
Asset memory asset = _beforeDeposit(depositAsset);
sharesBridged = _erc20Deposit(depositAsset, depositAmount, minimumMint, msg.sender, msg.sender, asset);
_afterPublicDeposit(msg.sender, depositAsset, depositAmount, sharesBridged, shareLockPeriod);
// Bridge shares
if (sharesBridged > type(uint96).max) revert CrossChainTellerWithGenericBridge__UnsafeCastToUint96();
_bridge(uint96(sharesBridged), to, bridgeWildCard, feeToken, maxFee);
}
/**
* @notice Deposit an asset and bridge the shares to another chain using a permit.
* @dev This function will REVERT if `beforeTransfer` hook reverts from:
* - shares being locked
* - allow list
* @dev Since calls to `depositWithPermit` and `bridge` are public, msg.sig is not updated which means any role capabilities regarding this function
* are also granted to the `depositWithPermit` and `bridge` function.
*/
function depositAndBridgeWithPermit(
ERC20 depositAsset,
uint256 depositAmount,
uint256 minimumMint,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s,
address to,
bytes calldata bridgeWildCard,
ERC20 feeToken,
uint256 maxFee
)
external
payable
requiresAuth
nonReentrant
revertOnNativeDeposit(address(depositAsset))
returns (uint256 sharesBridged)
{
// Permit deposit
{
Asset memory asset = _beforeDeposit(depositAsset);
_handlePermit(depositAsset, depositAmount, deadline, v, r, s);
sharesBridged = _erc20Deposit(depositAsset, depositAmount, minimumMint, msg.sender, msg.sender, asset);
}
_afterPublicDeposit(msg.sender, depositAsset, depositAmount, sharesBridged, shareLockPeriod);
// Bridge shares
if (sharesBridged > type(uint96).max) revert CrossChainTellerWithGenericBridge__UnsafeCastToUint96();
_bridge(uint96(sharesBridged), to, bridgeWildCard, feeToken, maxFee);
}
/**
* @notice Bridge shares to another chain.
* @param shareAmount The amount of shares to bridge.
* @param to The address to send the shares to on the other chain.
* @param bridgeWildCard The bridge specific data to configure message.
* @param feeToken The token to pay the bridge fee in.
* @param maxFee The maximum fee to pay the bridge.
*/
function bridge(uint96 shareAmount, address to, bytes calldata bridgeWildCard, ERC20 feeToken, uint256 maxFee)
external
payable
requiresAuth
nonReentrant
{
if (isPaused) revert TellerWithMultiAssetSupport__Paused();
_bridge(shareAmount, to, bridgeWildCard, feeToken, maxFee);
}
/**
* @notice Preview fee required to bridge shares in a given feeToken.
*/
function previewFee(uint96 shareAmount, address to, bytes calldata bridgeWildCard, ERC20 feeToken)
external
view
returns (uint256 fee)
{
MessageLib.Message memory m = MessageLib.Message(shareAmount, to);
uint256 message = m.messageToUint256();
return _previewFee(message, bridgeWildCard, feeToken);
}
// ========================================= INTERNAL BRIDGE FUNCTIONS =========================================
/**
* @notice Implement the bridge logic.
*/
function _bridge(uint96 shareAmount, address to, bytes calldata bridgeWildCard, ERC20 feeToken, uint256 maxFee)
internal
{
// Since shares are directly burned, call `beforeTransfer` to enforce before transfer hooks.
beforeTransfer(msg.sender, address(0), msg.sender);
// Burn shares from sender
vault.exit(address(0), ERC20(address(0)), 0, msg.sender, shareAmount);
// Send the message.
MessageLib.Message memory m = MessageLib.Message(shareAmount, to);
// `messageToUnit256` reverts on overflow, eventhough it is not possible to overflow.
// This was done for future proofing.
uint256 message = m.messageToUint256();
bytes32 messageId = _sendMessage(message, bridgeWildCard, feeToken, maxFee);
emit MessageSent(messageId, shareAmount, to);
}
/**
* @notice Complete the message receive process, should be called in child contract once
* message has been confirmed as legit.`
*/
function _completeMessageReceive(bytes32 messageId, uint256 message) internal {
MessageLib.Message memory m = message.uint256ToMessage();
// Mint shares to message.to
vault.enter(address(0), ERC20(address(0)), 0, m.to, m.shareAmount);
emit MessageReceived(messageId, m.shareAmount, m.to);
}
/**
* @notice Send the message to the bridge implementation.
* @dev This function should handle reverting if maxFee exceeds the fee required to send the message.
* @dev This function should handle collecting the fee.
* @param message The message to send.
* @param bridgeWildCard The bridge specific data to configure message.
* @param feeToken The token to pay the bridge fee in.
* @param maxFee The maximum fee to pay the bridge.
*/
function _sendMessage(uint256 message, bytes calldata bridgeWildCard, ERC20 feeToken, uint256 maxFee)
internal
virtual
returns (bytes32 messageId);
/**
* @notice Preview fee required to bridge shares in a given token.
*/
function _previewFee(uint256 message, bytes calldata bridgeWildCard, ERC20 feeToken)
internal
view
virtual
returns (uint256 fee);
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
import {ERC20} from "../tokens/ERC20.sol";
/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)
/// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer.
/// @dev Note that none of the functions in this library check that a token has code at all! That responsibility is delegated to the caller.
library SafeTransferLib {
/*//////////////////////////////////////////////////////////////
ETH OPERATIONS
//////////////////////////////////////////////////////////////*/
function safeTransferETH(address to, uint256 amount) internal {
bool success;
/// @solidity memory-safe-assembly
assembly {
// Transfer the ETH and store if it succeeded or not.
success := call(gas(), to, amount, 0, 0, 0, 0)
}
require(success, "ETH_TRANSFER_FAILED");
}
/*//////////////////////////////////////////////////////////////
ERC20 OPERATIONS
//////////////////////////////////////////////////////////////*/
function safeTransferFrom(
ERC20 token,
address from,
address to,
uint256 amount
) internal {
bool success;
/// @solidity memory-safe-assembly
assembly {
// Get a pointer to some free memory.
let freeMemoryPointer := mload(0x40)
// Write the abi-encoded calldata into memory, beginning with the function selector.
mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
mstore(add(freeMemoryPointer, 4), and(from, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "from" argument.
mstore(add(freeMemoryPointer, 36), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.
mstore(add(freeMemoryPointer, 68), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.
success := and(
// Set success to whether the call reverted, if not we check it either
// returned exactly 1 (can't just be non-zero data), or had no return data.
or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
// We use 100 because the length of our calldata totals up like so: 4 + 32 * 3.
// We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
// Counterintuitively, this call must be positioned second to the or() call in the
// surrounding and() call or else returndatasize() will be zero during the computation.
call(gas(), token, 0, freeMemoryPointer, 100, 0, 32)
)
}
require(success, "TRANSFER_FROM_FAILED");
}
function safeTransfer(
ERC20 token,
address to,
uint256 amount
) internal {
bool success;
/// @solidity memory-safe-assembly
assembly {
// Get a pointer to some free memory.
let freeMemoryPointer := mload(0x40)
// Write the abi-encoded calldata into memory, beginning with the function selector.
mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)
mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.
mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.
success := and(
// Set success to whether the call reverted, if not we check it either
// returned exactly 1 (can't just be non-zero data), or had no return data.
or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
// We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
// We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
// Counterintuitively, this call must be positioned second to the or() call in the
// surrounding and() call or else returndatasize() will be zero during the computation.
call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
)
}
require(success, "TRANSFER_FAILED");
}
function safeApprove(
ERC20 token,
address to,
uint256 amount
) internal {
bool success;
/// @solidity memory-safe-assembly
assembly {
// Get a pointer to some free memory.
let freeMemoryPointer := mload(0x40)
// Write the abi-encoded calldata into memory, beginning with the function selector.
mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000)
mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.
mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.
success := and(
// Set success to whether the call reverted, if not we check it either
// returned exactly 1 (can't just be non-zero data), or had no return data.
or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
// We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
// We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
// Counterintuitively, this call must be positioned second to the or() call in the
// surrounding and() call or else returndatasize() will be zero during the computation.
call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
)
}
require(success, "APPROVE_FAILED");
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
// @dev Import the 'MessagingFee' and 'MessagingReceipt' so it's exposed to OApp implementers
// solhint-disable-next-line no-unused-import
import {OAppAuthSender, MessagingFee, MessagingReceipt} from "./OAppAuthSender.sol";
// @dev Import the 'Origin' so it's exposed to OApp implementers
// solhint-disable-next-line no-unused-import
import {OAppAuthReceiver, Origin} from "./OAppAuthReceiver.sol";
import {OAppAuthCore} from "./OAppAuthCore.sol";
/**
* @title OApp
* @dev Abstract contract serving as the base for OApp implementation, combining OAppSender and OAppReceiver functionality.
*/
abstract contract OAppAuth is OAppAuthSender, OAppAuthReceiver {
/**
* @dev Constructor to initialize the OApp with the provided endpoint and owner.
* @param _endpoint The address of the LOCAL LayerZero endpoint.
* @param _delegate The delegate capable of making OApp configurations inside of the endpoint.
*/
constructor(address _endpoint, address _delegate) OAppAuthCore(_endpoint, _delegate) {}
/**
* @notice Retrieves the OApp version information.
* @return senderVersion The version of the OAppSender.sol implementation.
* @return receiverVersion The version of the OAppReceiver.sol implementation.
*/
function oAppVersion()
public
pure
virtual
override(OAppAuthSender, OAppAuthReceiver)
returns (uint64 senderVersion, uint64 receiverVersion)
{
return (SENDER_VERSION, RECEIVER_VERSION);
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.0;
library AddressToBytes32Lib {
function toBytes32(address addressValue) internal pure returns (bytes32) {
return bytes32(uint256(uint160(addressValue)));
}
function toAddress(bytes32 bytes32Value) internal pure returns (address) {
return address(bytes20(bytes32Value << 96));
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.20;
import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
import {BytesLib} from "@sbu/contracts/BytesLib.sol";
library OptionsBuilder {
using SafeCast for uint256;
using BytesLib for bytes;
// Constants for options types
uint16 internal constant TYPE_3 = 3;
uint8 internal constant OPTION_TYPE_LZRECEIVE = 1;
uint8 internal constant WORKER_ID = 1;
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 = encodeLzReceiveOption(_gas, _value);
return addExecutorOption(_options, OPTION_TYPE_LZRECEIVE, option);
}
/**
* @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,
WORKER_ID,
_option.length.toUint16() + 1, // +1 for optionType
_optionType,
_option
);
}
function encodeLzReceiveOption(uint128 _gas, uint128 _value) internal pure returns (bytes memory) {
return _value == 0 ? abi.encodePacked(_gas) : abi.encodePacked(_gas, _value);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @title Rate Limiter
* @dev Extends LayerZero's evm-oapp v2 RateLimiter contract. The original contract only supports rate limiting for outbound messages.
* This contract adds support for rate limiting inbound messages.
*/
abstract contract PairwiseRateLimiter {
/**
* @notice Rate Limit struct.
* @param amountInFlight The amount in the current window.
* @param lastUpdated Timestamp representing the last time the rate limit was checked or updated.
* @param limit This represents the maximum allowed amount within a given window.
* @param window Defines the duration of the rate limiting window.
*/
struct RateLimit {
uint256 amountInFlight;
uint256 lastUpdated;
uint256 limit;
uint256 window;
}
/**
* @notice Rate Limit Configuration struct.
* @param dstEid The peer endpoint id.
* @param limit This represents the maximum allowed amount within a given window.
* @param window Defines the duration of the rate limiting window.
*/
struct RateLimitConfig {
uint32 peerEid;
uint256 limit;
uint256 window;
}
/**
* @dev Mapping from peer endpoint id to RateLimit Configurations.
*/
mapping(uint32 dstEid => RateLimit limit) public outboundRateLimits;
mapping(uint32 srcEid => RateLimit limit) public inboundRateLimits;
/**
* @notice Emitted when _setRateLimits occurs.
* @param rateLimitConfigs An array of `RateLimitConfig` structs representing the rate limit configurations set.
* - `peerEid`: The peer endpoint id.
* - `limit`: This represents the maximum allowed amount within a given window.
* - `window`: Defines the duration of the rate limiting window.
*/
event OutboundRateLimitsChanged(RateLimitConfig[] rateLimitConfigs);
event InboundRateLimitsChanged(RateLimitConfig[] rateLimitConfigs);
/**
* @notice Error that is thrown when an amount exceeds the rate_limit.
*/
error OutboundRateLimitExceeded();
error InboundRateLimitExceeded();
/**
* @notice Get the current amount that can be sent to this peer endpoint id for the given rate limit window.
* @param _dstEid The destination endpoint id.
* @return outboundAmountInFlight The current amount that was sent.
* @return amountCanBeSent The amount that can be sent.
*/
function getAmountCanBeSent(uint32 _dstEid)
external
view
virtual
returns (uint256 outboundAmountInFlight, uint256 amountCanBeSent)
{
RateLimit memory rl = outboundRateLimits[_dstEid];
return _amountCanBeSent(rl.amountInFlight, rl.lastUpdated, rl.limit, rl.window);
}
/**
* @notice Get the current amount that can received from this peer endpoint for the given rate limit window.
* @param _srcEid The source endpoint id.
* @return inboundAmountInFlight The current amount has been received.
* @return amountCanBeReceived The amount that be received.
*/
function getAmountCanBeReceived(uint32 _srcEid)
external
view
virtual
returns (uint256 inboundAmountInFlight, uint256 amountCanBeReceived)
{
RateLimit memory rl = inboundRateLimits[_srcEid];
return _amountCanBeSent(rl.amountInFlight, rl.lastUpdated, rl.limit, rl.window);
}
/**
* @notice Sets the Rate Limit.
* @param _rateLimitConfigs A `RateLimitConfig` struct representing the rate limit configuration.
* - `dstEid`: The destination endpoint id.
* - `limit`: This represents the maximum allowed amount within a given window.
* - `window`: Defines the duration of the rate limiting window.
*/
function _setOutboundRateLimits(RateLimitConfig[] memory _rateLimitConfigs) internal virtual {
unchecked {
for (uint256 i = 0; i < _rateLimitConfigs.length; i++) {
RateLimit storage rl = outboundRateLimits[_rateLimitConfigs[i].peerEid];
// @dev Ensure we checkpoint the existing rate limit as to not retroactively apply the new decay rate.
_checkAndUpdateOutboundRateLimit(_rateLimitConfigs[i].peerEid, 0);
// @dev Does NOT reset the amountInFlight/lastUpdated of an existing rate limit.
rl.limit = _rateLimitConfigs[i].limit;
rl.window = _rateLimitConfigs[i].window;
}
}
emit OutboundRateLimitsChanged(_rateLimitConfigs);
}
/**
* @notice Sets the Rate Limit.
* @param _rateLimitConfigs A `RateLimitConfig` struct representing the rate limit configuration.
* - `srcEid`: The source endpoint id.
* - `limit`: This represents the maximum allowed amount within a given window.
* - `window`: Defines the duration of the rate limiting window.
*/
function _setInboundRateLimits(RateLimitConfig[] memory _rateLimitConfigs) internal virtual {
unchecked {
for (uint256 i = 0; i < _rateLimitConfigs.length; i++) {
RateLimit storage rl = inboundRateLimits[_rateLimitConfigs[i].peerEid];
// @dev Ensure we checkpoint the existing rate limit as to not retroactively apply the new decay rate.
_checkAndUpdateInboundRateLimit(_rateLimitConfigs[i].peerEid, 0);
// @dev Does NOT reset the amountInFlight/lastUpdated of an existing rate limit.
rl.limit = _rateLimitConfigs[i].limit;
rl.window = _rateLimitConfigs[i].window;
}
}
emit InboundRateLimitsChanged(_rateLimitConfigs);
}
/**
* @notice Checks current amount in flight and amount that can be sent for a given rate limit window.
* @param _amountInFlight The amount in the current window.
* @param _lastUpdated Timestamp representing the last time the rate limit was checked or updated.
* @param _limit This represents the maximum allowed amount within a given window.
* @param _window Defines the duration of the rate limiting window.
* @return currentAmountInFlight The amount in the current window.
* @return amountCanBeSent The amount that can be sent.
*/
function _amountCanBeSent(uint256 _amountInFlight, uint256 _lastUpdated, uint256 _limit, uint256 _window)
internal
view
virtual
returns (uint256 currentAmountInFlight, uint256 amountCanBeSent)
{
uint256 timeSinceLastDeposit = block.timestamp - _lastUpdated;
if (timeSinceLastDeposit >= _window) {
currentAmountInFlight = 0;
amountCanBeSent = _limit;
} else {
// @dev Presumes linear decay.
uint256 decay = (_limit * timeSinceLastDeposit) / _window;
currentAmountInFlight = _amountInFlight <= decay ? 0 : _amountInFlight - decay;
// @dev In the event the _limit is lowered, and the 'in-flight' amount is higher than the _limit, set to 0.
amountCanBeSent = _limit <= currentAmountInFlight ? 0 : _limit - currentAmountInFlight;
}
}
/**
* @notice Verifies whether the specified amount falls within the rate limit constraints for the targeted
* endpoint ID. On successful verification, it updates amountInFlight and lastUpdated. If the amount exceeds
* the rate limit, the operation reverts.
* @param _dstEid The destination endpoint id.
* @param _amount The amount to check for rate limit constraints.
*/
function _checkAndUpdateOutboundRateLimit(uint32 _dstEid, uint256 _amount) internal virtual {
// @dev By default dstEid that have not been explicitly set will return amountCanBeSent == 0.
RateLimit storage rl = outboundRateLimits[_dstEid];
(uint256 currentAmountInFlight, uint256 amountCanBeSent) =
_amountCanBeSent(rl.amountInFlight, rl.lastUpdated, rl.limit, rl.window);
if (_amount > amountCanBeSent) revert OutboundRateLimitExceeded();
// @dev Update the storage to contain the new amount and current timestamp.
rl.amountInFlight = currentAmountInFlight + _amount;
rl.lastUpdated = block.timestamp;
}
/**
* @notice Verifies whether the specified amount falls within the rate limit constraints for the targeted
* endpoint ID. On successful verification, it updates amountInFlight and lastUpdated. If the amount exceeds
* the rate limit, the operation reverts.
* @param _srcEid The source endpoint id.
* @param _amount The amount to check for rate limit constraints.
*/
function _checkAndUpdateInboundRateLimit(uint32 _srcEid, uint256 _amount) internal virtual {
// @dev By default dstEid that have not been explicitly set will return amountCanBeSent == 0.
RateLimit storage rl = inboundRateLimits[_srcEid];
(uint256 currentAmountInFlight, uint256 amountCanBeSent) =
_amountCanBeSent(rl.amountInFlight, rl.lastUpdated, rl.limit, rl.window);
if (_amount > amountCanBeSent) revert InboundRateLimitExceeded();
// @dev Update the storage to contain the new amount and current timestamp.
rl.amountInFlight = currentAmountInFlight + _amount;
rl.lastUpdated = block.timestamp;
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.0;
library MessageLib {
error MessageLib__ShareAmountOverflow();
uint256 internal constant MAX_SHARE_AMOUNT = type(uint96).max;
/**
* @notice Messages are transferred between chains as uint256
* The first 96 bits are the share amount.
* The remaining 160 bits are the address to send the shares to.
* @dev Using a uint256 was chosen because most bridging protocols charge based off the number of
* bytes sent, and packing a uint256 in this way caps it at 32 bytes.
*/
struct Message {
uint256 shareAmount; // The amount of shares to bridge.
address to;
}
/**
* @notice Extracts a Message from a uint256.
*/
function uint256ToMessage(uint256 b) internal pure returns (Message memory m) {
m.shareAmount = uint96(b >> 160);
m.to = address(uint160(b));
}
/**
* @notice Packs a Message into a uint256.
*/
function messageToUint256(Message memory m) internal pure returns (uint256 b) {
if (m.shareAmount > MAX_SHARE_AMOUNT) revert MessageLib__ShareAmountOverflow();
b |= m.shareAmount << 160;
b |= uint160(m.to);
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.21;
import {ERC20} from "@solmate/tokens/ERC20.sol";
import {WETH} from "@solmate/tokens/WETH.sol";
import {BoringVault} from "src/base/BoringVault.sol";
import {AccountantWithRateProviders} from "src/base/Roles/AccountantWithRateProviders.sol";
import {FixedPointMathLib} from "@solmate/utils/FixedPointMathLib.sol";
import {SafeTransferLib} from "@solmate/utils/SafeTransferLib.sol";
import {BeforeTransferHook} from "src/interfaces/BeforeTransferHook.sol";
import {Auth, Authority} from "@solmate/auth/Auth.sol";
import {ReentrancyGuard} from "@solmate/utils/ReentrancyGuard.sol";
import {IPausable} from "src/interfaces/IPausable.sol";
contract TellerWithMultiAssetSupport is Auth, BeforeTransferHook, ReentrancyGuard, IPausable {
using FixedPointMathLib for uint256;
using SafeTransferLib for ERC20;
using SafeTransferLib for WETH;
// ========================================= STRUCTS =========================================
/**
* @param allowDeposits bool indicating whether or not deposits are allowed for this asset.
* @param allowWithdraws bool indicating whether or not withdraws are allowed for this asset.
* @param sharePremium uint16 indicating the premium to apply to the shares minted.
* where 40 represents a 40bps reduction in shares minted using this asset.
*/
struct Asset {
bool allowDeposits;
bool allowWithdraws;
uint16 sharePremium;
}
// ========================================= CONSTANTS =========================================
/**
* @notice Native address used to tell the contract to handle native asset deposits.
*/
address internal constant NATIVE = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
/**
* @notice The maximum possible share lock period.
*/
uint256 internal constant MAX_SHARE_LOCK_PERIOD = 3 days;
/**
* @notice The maximum possible share premium that can be set using `updateAssetData`.
* @dev 1,000 or 10%
*/
uint16 internal constant MAX_SHARE_PREMIUM = 1_000;
// ========================================= STATE =========================================
/**
* @notice Mapping ERC20s to their assetData.
*/
mapping(ERC20 => Asset) public assetData;
/**
* @notice The deposit nonce used to map to a deposit hash.
*/
uint96 public depositNonce;
/**
* @notice After deposits, shares are locked to the msg.sender's address
* for `shareLockPeriod`.
* @dev During this time all trasnfers from msg.sender will revert, and
* deposits are refundable.
*/
uint64 public shareLockPeriod;
/**
* @notice Used to pause calls to `deposit` and `depositWithPermit`.
*/
bool public isPaused;
/**
* @dev Maps deposit nonce to keccak256(address receiver, address depositAsset, uint256 depositAmount, uint256 shareAmount, uint256 timestamp, uint256 shareLockPeriod).
*/
mapping(uint256 => bytes32) public publicDepositHistory;
/**
* @notice Maps user address to the time their shares will be unlocked.
*/
mapping(address => uint256) public shareUnlockTime;
/**
* @notice Mapping `from` address to a bool to deny them from transferring shares.
*/
mapping(address => bool) public fromDenyList;
/**
* @notice Mapping `to` address to a bool to deny them from receiving shares.
*/
mapping(address => bool) public toDenyList;
/**
* @notice Mapping `opeartor` address to a bool to deny them from calling `transfer` or `transferFrom`.
*/
mapping(address => bool) public operatorDenyList;
//============================== ERRORS ===============================
error TellerWithMultiAssetSupport__ShareLockPeriodTooLong();
error TellerWithMultiAssetSupport__SharesAreLocked();
error TellerWithMultiAssetSupport__SharesAreUnLocked();
error TellerWithMultiAssetSupport__BadDepositHash();
error TellerWithMultiAssetSupport__AssetNotSupported();
error TellerWithMultiAssetSupport__ZeroAssets();
error TellerWithMultiAssetSupport__MinimumMintNotMet();
error TellerWithMultiAssetSupport__MinimumAssetsNotMet();
error TellerWithMultiAssetSupport__PermitFailedAndAllowanceTooLow();
error TellerWithMultiAssetSupport__ZeroShares();
error TellerWithMultiAssetSupport__DualDeposit();
error TellerWithMultiAssetSupport__Paused();
error TellerWithMultiAssetSupport__TransferDenied(address from, address to, address operator);
error TellerWithMultiAssetSupport__SharePremiumTooLarge();
error TellerWithMultiAssetSupport__CannotDepositNative();
//============================== EVENTS ===============================
event Paused();
event Unpaused();
event AssetDataUpdated(address indexed asset, bool allowDeposits, bool allowWithdraws, uint16 sharePremium);
event Deposit(
uint256 indexed nonce,
address indexed receiver,
address indexed depositAsset,
uint256 depositAmount,
uint256 shareAmount,
uint256 depositTimestamp,
uint256 shareLockPeriodAtTimeOfDeposit
);
event BulkDeposit(address indexed asset, uint256 depositAmount);
event BulkWithdraw(address indexed asset, uint256 shareAmount);
event DepositRefunded(uint256 indexed nonce, bytes32 depositHash, address indexed user);
event DenyFrom(address indexed user);
event DenyTo(address indexed user);
event DenyOperator(address indexed user);
event AllowFrom(address indexed user);
event AllowTo(address indexed user);
event AllowOperator(address indexed user);
// =============================== MODIFIERS ===============================
/**
* @notice Reverts if the deposit asset is the native asset.
*/
modifier revertOnNativeDeposit(address depositAsset) {
if (depositAsset == NATIVE) revert TellerWithMultiAssetSupport__CannotDepositNative();
_;
}
//============================== IMMUTABLES ===============================
/**
* @notice The BoringVault this contract is working with.
*/
BoringVault public immutable vault;
/**
* @notice The AccountantWithRateProviders this contract is working with.
*/
AccountantWithRateProviders public immutable accountant;
/**
* @notice One share of the BoringVault.
*/
uint256 internal immutable ONE_SHARE;
/**
* @notice The native wrapper contract.
*/
WETH public immutable nativeWrapper;
constructor(address _owner, address _vault, address _accountant, address _weth)
Auth(_owner, Authority(address(0)))
{
vault = BoringVault(payable(_vault));
ONE_SHARE = 10 ** vault.decimals();
accountant = AccountantWithRateProviders(_accountant);
nativeWrapper = WETH(payable(_weth));
}
// ========================================= ADMIN FUNCTIONS =========================================
/**
* @notice Pause this contract, which prevents future calls to `deposit` and `depositWithPermit`.
* @dev Callable by MULTISIG_ROLE.
*/
function pause() external requiresAuth {
isPaused = true;
emit Paused();
}
/**
* @notice Unpause this contract, which allows future calls to `deposit` and `depositWithPermit`.
* @dev Callable by MULTISIG_ROLE.
*/
function unpause() external requiresAuth {
isPaused = false;
emit Unpaused();
}
/**
* @notice Updates the asset data for a given asset.
* @dev The accountant must also support pricing this asset, else the `deposit` call will revert.
* @dev Callable by OWNER_ROLE.
*/
function updateAssetData(ERC20 asset, bool allowDeposits, bool allowWithdraws, uint16 sharePremium)
external
requiresAuth
{
if (sharePremium > MAX_SHARE_PREMIUM) revert TellerWithMultiAssetSupport__SharePremiumTooLarge();
assetData[asset] = Asset(allowDeposits, allowWithdraws, sharePremium);
emit AssetDataUpdated(address(asset), allowDeposits, allowWithdraws, sharePremium);
}
/**
* @notice Sets the share lock period.
* @dev This not only locks shares to the user address, but also serves as the pending deposit period, where deposits can be reverted.
* @dev If a new shorter share lock period is set, users with pending share locks could make a new deposit to receive 1 wei shares,
* and have their shares unlock sooner than their original deposit allows. This state would allow for the user deposit to be refunded,
* but only if they have not transferred their shares out of there wallet. This is an accepted limitation, and should be known when decreasing
* the share lock period.
* @dev Callable by OWNER_ROLE.
*/
function setShareLockPeriod(uint64 _shareLockPeriod) external requiresAuth {
if (_shareLockPeriod > MAX_SHARE_LOCK_PERIOD) revert TellerWithMultiAssetSupport__ShareLockPeriodTooLong();
shareLockPeriod = _shareLockPeriod;
}
/**
* @notice Deny a user from transferring or receiving shares.
* @dev Callable by OWNER_ROLE, and DENIER_ROLE.
*/
function denyAll(address user) external requiresAuth {
fromDenyList[user] = true;
toDenyList[user] = true;
operatorDenyList[user] = true;
emit DenyFrom(user);
emit DenyTo(user);
emit DenyOperator(user);
}
/**
* @notice Allow a user to transfer or receive shares.
* @dev Callable by OWNER_ROLE, and DENIER_ROLE.
*/
function allowAll(address user) external requiresAuth {
fromDenyList[user] = false;
toDenyList[user] = false;
operatorDenyList[user] = false;
emit AllowFrom(user);
emit AllowTo(user);
emit AllowOperator(user);
}
/**
* @notice Deny a user from transferring shares.
* @dev Callable by OWNER_ROLE, and DENIER_ROLE.
*/
function denyFrom(address user) external requiresAuth {
fromDenyList[user] = true;
emit DenyFrom(user);
}
/**
* @notice Allow a user to transfer shares.
* @dev Callable by OWNER_ROLE, and DENIER_ROLE.
*/
function allowFrom(address user) external requiresAuth {
fromDenyList[user] = false;
emit AllowFrom(user);
}
/**
* @notice Deny a user from receiving shares.
* @dev Callable by OWNER_ROLE, and DENIER_ROLE.
*/
function denyTo(address user) external requiresAuth {
toDenyList[user] = true;
emit DenyTo(user);
}
/**
* @notice Allow a user to receive shares.
* @dev Callable by OWNER_ROLE, and DENIER_ROLE.
*/
function allowTo(address user) external requiresAuth {
toDenyList[user] = false;
emit AllowTo(user);
}
/**
* @notice Deny an operator from transferring shares.
* @dev Callable by OWNER_ROLE, and DENIER_ROLE.
*/
function denyOperator(address user) external requiresAuth {
operatorDenyList[user] = true;
emit DenyOperator(user);
}
/**
* @notice Allow an operator to transfer shares.
* @dev Callable by OWNER_ROLE, and DENIER_ROLE.
*/
function allowOperator(address user) external requiresAuth {
operatorDenyList[user] = false;
emit AllowOperator(user);
}
// ========================================= BeforeTransferHook FUNCTIONS =========================================
/**
* @notice Implement beforeTransfer hook to check if shares are locked, or if `from`, `to`, or `operator` are on the deny list.
* @notice If share lock period is set to zero, then users will be able to mint and transfer in the same tx.
* if this behavior is not desired then a share lock period of >=1 should be used.
*/
function beforeTransfer(address from, address to, address operator) public view virtual {
if (fromDenyList[from] || toDenyList[to] || operatorDenyList[operator]) {
revert TellerWithMultiAssetSupport__TransferDenied(from, to, operator);
}
if (shareUnlockTime[from] > block.timestamp) revert TellerWithMultiAssetSupport__SharesAreLocked();
}
/**
* @notice Implement legacy beforeTransfer hook to check if shares are locked, or if `from`is on the deny list.
*/
function beforeTransfer(address from) public view virtual {
if (fromDenyList[from]) {
revert TellerWithMultiAssetSupport__TransferDenied(from, address(0), address(0));
}
if (shareUnlockTime[from] > block.timestamp) revert TellerWithMultiAssetSupport__SharesAreLocked();
}
// ========================================= REVERT DEPOSIT FUNCTIONS =========================================
/**
* @notice Allows DEPOSIT_REFUNDER_ROLE to revert a pending deposit.
* @dev Once a deposit share lock period has passed, it can no longer be reverted.
* @dev It is possible the admin does not setup the BoringVault to call the transfer hook,
* but this contract can still be saving share lock state. In the event this happens
* deposits are still refundable if the user has not transferred their shares.
* But there is no guarantee that the user has not transferred their shares.
* @dev Callable by STRATEGIST_MULTISIG_ROLE.
*/
function refundDeposit(
uint256 nonce,
address receiver,
address depositAsset,
uint256 depositAmount,
uint256 shareAmount,
uint256 depositTimestamp,
uint256 shareLockUpPeriodAtTimeOfDeposit
) external requiresAuth {
if ((block.timestamp - depositTimestamp) >= shareLockUpPeriodAtTimeOfDeposit) {
// Shares are already unlocked, so we can not revert deposit.
revert TellerWithMultiAssetSupport__SharesAreUnLocked();
}
bytes32 depositHash = keccak256(
abi.encode(
receiver, depositAsset, depositAmount, shareAmount, depositTimestamp, shareLockUpPeriodAtTimeOfDeposit
)
);
if (publicDepositHistory[nonce] != depositHash) revert TellerWithMultiAssetSupport__BadDepositHash();
// Delete hash to prevent refund gas.
delete publicDepositHistory[nonce];
// If deposit used native asset, send user back wrapped native asset.
depositAsset = depositAsset == NATIVE ? address(nativeWrapper) : depositAsset;
// Burn shares and refund assets to receiver.
vault.exit(receiver, ERC20(depositAsset), depositAmount, receiver, shareAmount);
emit DepositRefunded(nonce, depositHash, receiver);
}
// ========================================= USER FUNCTIONS =========================================
/**
* @notice Allows users to deposit into the BoringVault, if this contract is not paused.
* @dev Publicly callable.
*/
function deposit(ERC20 depositAsset, uint256 depositAmount, uint256 minimumMint)
external
payable
requiresAuth
nonReentrant
returns (uint256 shares)
{
Asset memory asset = _beforeDeposit(depositAsset);
address from;
if (address(depositAsset) == NATIVE) {
if (msg.value == 0) revert TellerWithMultiAssetSupport__ZeroAssets();
nativeWrapper.deposit{value: msg.value}();
// Set depositAmount to msg.value.
depositAmount = msg.value;
nativeWrapper.safeApprove(address(vault), depositAmount);
// Update depositAsset to nativeWrapper.
depositAsset = nativeWrapper;
// Set from to this address since user transferred value.
from = address(this);
} else {
if (msg.value > 0) revert TellerWithMultiAssetSupport__DualDeposit();
from = msg.sender;
}
shares = _erc20Deposit(depositAsset, depositAmount, minimumMint, from, msg.sender, asset);
_afterPublicDeposit(msg.sender, depositAsset, depositAmount, shares, shareLockPeriod);
}
/**
* @notice Allows users to deposit into BoringVault using permit.
* @dev Publicly callable.
*/
function depositWithPermit(
ERC20 depositAsset,
uint256 depositAmount,
uint256 minimumMint,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external requiresAuth nonReentrant revertOnNativeDeposit(address(depositAsset)) returns (uint256 shares) {
Asset memory asset = _beforeDeposit(depositAsset);
_handlePermit(depositAsset, depositAmount, deadline, v, r, s);
shares = _erc20Deposit(depositAsset, depositAmount, minimumMint, msg.sender, msg.sender, asset);
_afterPublicDeposit(msg.sender, depositAsset, depositAmount, shares, shareLockPeriod);
}
/**
* @notice Allows on ramp role to deposit into this contract.
* @dev Does NOT support native deposits.
* @dev Callable by SOLVER_ROLE.
*/
function bulkDeposit(ERC20 depositAsset, uint256 depositAmount, uint256 minimumMint, address to)
external
requiresAuth
nonReentrant
returns (uint256 shares)
{
Asset memory asset = _beforeDeposit(depositAsset);
shares = _erc20Deposit(depositAsset, depositAmount, minimumMint, msg.sender, to, asset);
emit BulkDeposit(address(depositAsset), depositAmount);
}
/**
* @notice Allows off ramp role to withdraw from this contract.
* @dev Callable by SOLVER_ROLE.
*/
function bulkWithdraw(ERC20 withdrawAsset, uint256 shareAmount, uint256 minimumAssets, address to)
external
requiresAuth
returns (uint256 assetsOut)
{
if (isPaused) revert TellerWithMultiAssetSupport__Paused();
Asset memory asset = assetData[withdrawAsset];
if (!asset.allowWithdraws) revert TellerWithMultiAssetSupport__AssetNotSupported();
if (shareAmount == 0) revert TellerWithMultiAssetSupport__ZeroShares();
assetsOut = shareAmount.mulDivDown(accountant.getRateInQuoteSafe(withdrawAsset), ONE_SHARE);
if (assetsOut < minimumAssets) revert TellerWithMultiAssetSupport__MinimumAssetsNotMet();
vault.exit(to, withdrawAsset, assetsOut, msg.sender, shareAmount);
emit BulkWithdraw(address(withdrawAsset), shareAmount);
}
// ========================================= INTERNAL HELPER FUNCTIONS =========================================
/**
* @notice Implements a common ERC20 deposit into BoringVault.
*/
function _erc20Deposit(
ERC20 depositAsset,
uint256 depositAmount,
uint256 minimumMint,
address from,
address to,
Asset memory asset
) internal returns (uint256 shares) {
if (depositAmount == 0) revert TellerWithMultiAssetSupport__ZeroAssets();
shares = depositAmount.mulDivDown(ONE_SHARE, accountant.getRateInQuoteSafe(depositAsset));
shares = asset.sharePremium > 0 ? shares.mulDivDown(1e4 - asset.sharePremium, 1e4) : shares;
if (shares < minimumMint) revert TellerWithMultiAssetSupport__MinimumMintNotMet();
vault.enter(from, depositAsset, depositAmount, to, shares);
}
/**
* @notice Handle pre-deposit checks.
*/
function _beforeDeposit(ERC20 depositAsset) internal view returns (Asset memory asset) {
if (isPaused) revert TellerWithMultiAssetSupport__Paused();
asset = assetData[depositAsset];
if (!asset.allowDeposits) revert TellerWithMultiAssetSupport__AssetNotSupported();
}
/**
* @notice Handle share lock logic, and event.
*/
function _afterPublicDeposit(
address user,
ERC20 depositAsset,
uint256 depositAmount,
uint256 shares,
uint256 currentShareLockPeriod
) internal {
// Increment then assign as its slightly more gas efficient.
uint256 nonce = ++depositNonce;
// Only set share unlock time and history if share lock period is greater than 0.
if (currentShareLockPeriod > 0) {
shareUnlockTime[user] = block.timestamp + currentShareLockPeriod;
publicDepositHistory[nonce] = keccak256(
abi.encode(user, depositAsset, depositAmount, shares, block.timestamp, currentShareLockPeriod)
);
}
emit Deposit(nonce, user, address(depositAsset), depositAmount, shares, block.timestamp, currentShareLockPeriod);
}
/**
* @notice Handle permit logic.
*/
function _handlePermit(ERC20 depositAsset, uint256 depositAmount, uint256 deadline, uint8 v, bytes32 r, bytes32 s)
internal
{
try depositAsset.permit(msg.sender, address(vault), depositAmount, deadline, v, r, s) {}
catch {
if (depositAsset.allowance(msg.sender, address(vault)) < depositAmount) {
revert TellerWithMultiAssetSupport__PermitFailedAndAllowanceTooLow();
}
}
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol)
/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)
/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.
abstract contract ERC20 {
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/
event Transfer(address indexed from, address indexed to, uint256 amount);
event Approval(address indexed owner, address indexed spender, uint256 amount);
/*//////////////////////////////////////////////////////////////
METADATA STORAGE
//////////////////////////////////////////////////////////////*/
string public name;
string public symbol;
uint8 public immutable decimals;
/*//////////////////////////////////////////////////////////////
ERC20 STORAGE
//////////////////////////////////////////////////////////////*/
uint256 public totalSupply;
mapping(address => uint256) public balanceOf;
mapping(address => mapping(address => uint256)) public allowance;
/*//////////////////////////////////////////////////////////////
EIP-2612 STORAGE
//////////////////////////////////////////////////////////////*/
uint256 internal immutable INITIAL_CHAIN_ID;
bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;
mapping(address => uint256) public nonces;
/*//////////////////////////////////////////////////////////////
CONSTRUCTOR
//////////////////////////////////////////////////////////////*/
constructor(
string memory _name,
string memory _symbol,
uint8 _decimals
) {
name = _name;
symbol = _symbol;
decimals = _decimals;
INITIAL_CHAIN_ID = block.chainid;
INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
}
/*//////////////////////////////////////////////////////////////
ERC20 LOGIC
//////////////////////////////////////////////////////////////*/
function approve(address spender, uint256 amount) public virtual returns (bool) {
allowance[msg.sender][spender] = amount;
emit Approval(msg.sender, spender, amount);
return true;
}
function transfer(address to, uint256 amount) public virtual returns (bool) {
balanceOf[msg.sender] -= amount;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += amount;
}
emit Transfer(msg.sender, to, amount);
return true;
}
function transferFrom(
address from,
address to,
uint256 amount
) public virtual returns (bool) {
uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.
if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;
balanceOf[from] -= amount;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += amount;
}
emit Transfer(from, to, amount);
return true;
}
/*//////////////////////////////////////////////////////////////
EIP-2612 LOGIC
//////////////////////////////////////////////////////////////*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) public virtual {
require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED");
// Unchecked because the only math done is incrementing
// the owner's nonce which cannot realistically overflow.
unchecked {
address recoveredAddress = ecrecover(
keccak256(
abi.encodePacked(
"\x19\x01",
DOMAIN_SEPARATOR(),
keccak256(
abi.encode(
keccak256(
"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
),
owner,
spender,
value,
nonces[owner]++,
deadline
)
)
)
),
v,
r,
s
);
require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER");
allowance[recoveredAddress][spender] = value;
}
emit Approval(owner, spender, value);
}
function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();
}
function computeDomainSeparator() internal view virtual returns (bytes32) {
return
keccak256(
abi.encode(
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
keccak256(bytes(name)),
keccak256("1"),
block.chainid,
address(this)
)
);
}
/*//////////////////////////////////////////////////////////////
INTERNAL MINT/BURN LOGIC
//////////////////////////////////////////////////////////////*/
function _mint(address to, uint256 amount) internal virtual {
totalSupply += amount;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += amount;
}
emit Transfer(address(0), to, amount);
}
function _burn(address from, uint256 amount) internal virtual {
balanceOf[from] -= amount;
// Cannot underflow because a user's balance
// will never be larger than the total supply.
unchecked {
totalSupply -= amount;
}
emit Transfer(from, address(0), amount);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {SafeTransferLib, ERC20} from "@solmate/utils/SafeTransferLib.sol";
import {
MessagingParams,
MessagingFee,
MessagingReceipt
} from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroEndpointV2.sol";
import {OAppAuthCore} from "./OAppAuthCore.sol";
/**
* @title OAppSender
* @dev Abstract contract implementing the OAppSender functionality for sending messages to a LayerZero endpoint.
*/
abstract contract OAppAuthSender is OAppAuthCore {
using SafeTransferLib for ERC20;
// Custom error messages
error NotEnoughNative(uint256 msgValue);
error LzTokenUnavailable();
// @dev The version of the OAppSender implementation.
// @dev Version is bumped when changes are made to this contract.
uint64 internal constant SENDER_VERSION = 1;
/**
* @notice Retrieves the OApp version information.
* @return senderVersion The version of the OAppSender.sol contract.
* @return receiverVersion The version of the OAppReceiver.sol contract.
*
* @dev Providing 0 as the default for OAppReceiver version. Indicates that the OAppReceiver is not implemented.
* ie. this is a SEND only OApp.
* @dev If the OApp uses both OAppSender and OAppReceiver, then this needs to be override returning the correct versions
*/
function oAppVersion() public view virtual returns (uint64 senderVersion, uint64 receiverVersion) {
return (SENDER_VERSION, 0);
}
/**
* @dev Internal function to interact with the LayerZero EndpointV2.quote() for fee calculation.
* @param _dstEid The destination endpoint ID.
* @param _message The message payload.
* @param _options Additional options for the message.
* @param _payInLzToken Flag indicating whether to pay the fee in LZ tokens.
* @return fee The calculated MessagingFee for the message.
* - nativeFee: The native fee for the message.
* - lzTokenFee: The LZ token fee for the message.
*/
function _quote(uint32 _dstEid, bytes memory _message, bytes memory _options, bool _payInLzToken)
internal
view
virtual
returns (MessagingFee memory fee)
{
return endpoint.quote(
MessagingParams(_dstEid, _getPeerOrRevert(_dstEid), _message, _options, _payInLzToken), address(this)
);
}
/**
* @dev Internal function to interact with the LayerZero EndpointV2.send() for sending a message.
* @param _dstEid The destination endpoint ID.
* @param _message The message payload.
* @param _options Additional options for the message.
* @param _fee The calculated LayerZero fee for the message.
* - nativeFee: The native fee.
* - lzTokenFee: The lzToken fee.
* @param _refundAddress The address to receive any excess fee values sent to the endpoint.
* @return receipt The receipt for the sent message.
* - guid: The unique identifier for the sent message.
* - nonce: The nonce of the sent message.
* - fee: The LayerZero fee incurred for the message.
*/
function _lzSend(
uint32 _dstEid,
bytes memory _message,
bytes memory _options,
MessagingFee memory _fee,
address _refundAddress
) internal virtual returns (MessagingReceipt memory receipt) {
// @dev Push corresponding fees to the endpoint, any excess is sent back to the _refundAddress from the endpoint.
uint256 messageValue = _payNative(_fee.nativeFee);
if (_fee.lzTokenFee > 0) _payLzToken(_fee.lzTokenFee);
return endpoint
// solhint-disable-next-line check-send-result
.send{value: messageValue}(
MessagingParams(_dstEid, _getPeerOrRevert(_dstEid), _message, _options, _fee.lzTokenFee > 0), _refundAddress
);
}
/**
* @dev Internal function to pay the native fee associated with the message.
* @param _nativeFee The native fee to be paid.
* @return nativeFee The amount of native currency paid.
*
* @dev If the OApp needs to initiate MULTIPLE LayerZero messages in a single transaction,
* this will need to be overridden because msg.value would contain multiple lzFees.
* @dev Should be overridden in the event the LayerZero endpoint requires a different native currency.
* @dev Some EVMs use an ERC20 as a method for paying transactions/gasFees.
* @dev The endpoint is EITHER/OR, ie. it will NOT support both types of native payment at a time.
*/
function _payNative(uint256 _nativeFee) internal virtual returns (uint256 nativeFee) {
if (msg.value != _nativeFee) revert NotEnoughNative(msg.value);
return _nativeFee;
}
/**
* @dev Internal function to pay the LZ token fee associated with the message.
* @param _lzTokenFee The LZ token fee to be paid.
*
* @dev If the caller is trying to pay in the specified lzToken, then the lzTokenFee is passed to the endpoint.
* @dev Any excess sent, is passed back to the specified _refundAddress in the _lzSend().
*/
function _payLzToken(uint256 _lzTokenFee) internal virtual {
// @dev Cannot cache the token because it is not immutable in the endpoint.
address lzToken = endpoint.lzToken();
if (lzToken == address(0)) revert LzTokenUnavailable();
// Pay LZ token fee by sending tokens to the endpoint.
ERC20(lzToken).safeTransferFrom(msg.sender, address(endpoint), _lzTokenFee);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {IOAppReceiver, Origin} from "@lz-oapp-evm/interfaces/IOAppReceiver.sol";
import {OAppAuthCore} from "./OAppAuthCore.sol";
/**
* @title OAppReceiver
* @dev Abstract contract implementing the ILayerZeroReceiver interface and extending OAppCore for OApp receivers.
*/
abstract contract OAppAuthReceiver is IOAppReceiver, OAppAuthCore {
// Custom error message for when the caller is not the registered endpoint/
error OnlyEndpoint(address addr);
// @dev The version of the OAppReceiver implementation.
// @dev Version is bumped when changes are made to this contract.
uint64 internal constant RECEIVER_VERSION = 1;
/**
* @notice Retrieves the OApp version information.
* @return senderVersion The version of the OAppSender.sol contract.
* @return receiverVersion The version of the OAppReceiver.sol contract.
*
* @dev Providing 0 as the default for OAppSender version. Indicates that the OAppSender is not implemented.
* ie. this is a RECEIVE only OApp.
* @dev If the OApp uses both OAppSender and OAppReceiver, then this needs to be override returning the correct versions.
*/
function oAppVersion() public view virtual returns (uint64 senderVersion, uint64 receiverVersion) {
return (0, RECEIVER_VERSION);
}
/**
* @notice Retrieves the address responsible for 'sending' composeMsg's to the Endpoint.
* @return sender The address responsible for 'sending' composeMsg's to the Endpoint.
*
* @dev Applications can optionally choose to implement a separate composeMsg sender that is NOT the bridging layer.
* @dev The default sender IS the OApp implementer.
*/
function composeMsgSender() public view virtual returns (address sender) {
return address(this);
}
/**
* @notice Checks if the path initialization is allowed based on the provided origin.
* @param origin The origin information containing the source endpoint and sender address.
* @return Whether the path has been initialized.
*
* @dev This indicates to the endpoint that the OApp has enabled msgs for this particular path to be received.
* @dev This defaults to assuming if a peer has been set, its initialized.
* Can be overridden by the OApp if there is other logic to determine this.
*/
function allowInitializePath(Origin calldata origin) public view virtual returns (bool) {
return peers[origin.srcEid] == origin.sender;
}
/**
* @notice Retrieves the next nonce for a given source endpoint and sender address.
* @dev _srcEid The source endpoint ID.
* @dev _sender The sender address.
* @return nonce The next nonce.
*
* @dev The path nonce starts from 1. If 0 is returned it means that there is NO nonce ordered enforcement.
* @dev Is required by the off-chain executor to determine the OApp expects msg execution is ordered.
* @dev This is also enforced by the OApp.
* @dev By default this is NOT enabled. ie. nextNonce is hardcoded to return 0.
*/
function nextNonce(uint32, /*_srcEid*/ bytes32 /*_sender*/ ) public view virtual returns (uint64 nonce) {
return 0;
}
/**
* @dev Entry point for receiving messages or packets from the endpoint.
* @param _origin The origin information containing the source endpoint and sender address.
* - srcEid: The source chain endpoint ID.
* - sender: The sender address on the src chain.
* - nonce: The nonce of the message.
* @param _guid The unique identifier for the received LayerZero message.
* @param _message The payload of the received message.
* @param _executor The address of the executor for the received message.
* @param _extraData Additional arbitrary data provided by the corresponding executor.
*
* @dev Entry point for receiving msg/packet from the LayerZero endpoint.
*/
function lzReceive(
Origin calldata _origin,
bytes32 _guid,
bytes calldata _message,
address _executor,
bytes calldata _extraData
) public payable virtual {
// Ensures that only the endpoint can attempt to lzReceive() messages to this OApp.
if (address(endpoint) != msg.sender) revert OnlyEndpoint(msg.sender);
// Ensure that the sender matches the expected peer for the source endpoint.
if (_getPeerOrRevert(_origin.srcEid) != _origin.sender) revert OnlyPeer(_origin.srcEid, _origin.sender);
// Call the internal OApp implementation of lzReceive.
_lzReceive(_origin, _guid, _message, _executor, _extraData);
}
/**
* @dev Internal function to implement lzReceive logic without needing to copy the basic parameter validation.
*/
function _lzReceive(
Origin calldata _origin,
bytes32 _guid,
bytes calldata _message,
address _executor,
bytes calldata _extraData
) internal virtual;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {Auth, Authority} from "@solmate/auth/Auth.sol";
import {IOAppCore, ILayerZeroEndpointV2} from "@lz-oapp-evm/interfaces/IOAppCore.sol";
/**
* @title OAppCore
* @dev Abstract contract implementing the IOAppCore interface with basic OApp configurations.
*/
abstract contract OAppAuthCore is IOAppCore, Auth {
// The LayerZero endpoint associated with the given OApp
ILayerZeroEndpointV2 public immutable endpoint;
// Mapping to store peers associated with corresponding endpoints
mapping(uint32 eid => bytes32 peer) public peers;
/**
* @dev Constructor to initialize the OAppCore with the provided endpoint and delegate.
* @param _endpoint The address of the LOCAL Layer Zero endpoint.
* @param _delegate The delegate capable of making OApp configurations inside of the endpoint.
*
* @dev The delegate typically should be set as the owner of the contract.
*/
constructor(address _endpoint, address _delegate) {
endpoint = ILayerZeroEndpointV2(_endpoint);
if (_delegate == address(0)) revert InvalidDelegate();
endpoint.setDelegate(_delegate);
}
/**
* @notice Sets the peer address (OApp instance) for a corresponding endpoint.
* @param _eid The endpoint ID.
* @param _peer The address of the peer to be associated with the corresponding endpoint.
*
* @dev Only the owner/admin of the OApp can call this function.
* @dev Indicates that the peer is trusted to send LayerZero messages to this OApp.
* @dev Set this to bytes32(0) to remove the peer address.
* @dev Peer is a bytes32 to accommodate non-evm chains.
*/
function setPeer(uint32 _eid, bytes32 _peer) public virtual requiresAuth {
_setPeer(_eid, _peer);
}
/**
* @notice Sets the peer address (OApp instance) for a corresponding endpoint.
* @param _eid The endpoint ID.
* @param _peer The address of the peer to be associated with the corresponding endpoint.
*
* @dev Indicates that the peer is trusted to send LayerZero messages to this OApp.
* @dev Set this to bytes32(0) to remove the peer address.
* @dev Peer is a bytes32 to accommodate non-evm chains.
*/
function _setPeer(uint32 _eid, bytes32 _peer) internal virtual {
peers[_eid] = _peer;
emit PeerSet(_eid, _peer);
}
/**
* @notice Internal function to get the peer address associated with a specific endpoint; reverts if NOT set.
* ie. the peer is set to bytes32(0).
* @param _eid The endpoint ID.
* @return peer The address of the peer associated with the specified endpoint.
*/
function _getPeerOrRevert(uint32 _eid) internal view virtual returns (bytes32) {
bytes32 peer = peers[_eid];
if (peer == bytes32(0)) revert NoPeer(_eid);
return peer;
}
/**
* @notice Sets the delegate address for the OApp.
* @param _delegate The address of the delegate to be set.
*
* @dev Only the owner/admin of the OApp can call this function.
* @dev Provides the ability for a delegate to set configs, on behalf of the OApp, directly on the Endpoint contract.
*/
function setDelegate(address _delegate) public requiresAuth {
endpoint.setDelegate(_delegate);
}
}// 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: 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: AGPL-3.0-only
pragma solidity >=0.8.0;
import {ERC20} from "./ERC20.sol";
import {SafeTransferLib} from "../utils/SafeTransferLib.sol";
/// @notice Minimalist and modern Wrapped Ether implementation.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/WETH.sol)
/// @author Inspired by WETH9 (https://github.com/dapphub/ds-weth/blob/master/src/weth9.sol)
contract WETH is ERC20("Wrapped Ether", "WETH", 18) {
using SafeTransferLib for address;
event Deposit(address indexed from, uint256 amount);
event Withdrawal(address indexed to, uint256 amount);
function deposit() public payable virtual {
_mint(msg.sender, msg.value);
emit Deposit(msg.sender, msg.value);
}
function withdraw(uint256 amount) public virtual {
_burn(msg.sender, amount);
emit Withdrawal(msg.sender, amount);
msg.sender.safeTransferETH(amount);
}
receive() external payable virtual {
deposit();
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.21;
import {Address} from "@openzeppelin/contracts/utils/Address.sol";
import {ERC721Holder} from "@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol";
import {ERC1155Holder} from "@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol";
import {FixedPointMathLib} from "@solmate/utils/FixedPointMathLib.sol";
import {SafeTransferLib} from "@solmate/utils/SafeTransferLib.sol";
import {ERC20} from "@solmate/tokens/ERC20.sol";
import {BeforeTransferHook} from "src/interfaces/BeforeTransferHook.sol";
import {Auth, Authority} from "@solmate/auth/Auth.sol";
contract BoringVault is ERC20, Auth, ERC721Holder, ERC1155Holder {
using Address for address;
using SafeTransferLib for ERC20;
using FixedPointMathLib for uint256;
// ========================================= STATE =========================================
/**
* @notice Contract responsbile for implementing `beforeTransfer`.
*/
BeforeTransferHook public hook;
//============================== EVENTS ===============================
event Enter(address indexed from, address indexed asset, uint256 amount, address indexed to, uint256 shares);
event Exit(address indexed to, address indexed asset, uint256 amount, address indexed from, uint256 shares);
//============================== CONSTRUCTOR ===============================
constructor(address _owner, string memory _name, string memory _symbol, uint8 _decimals)
ERC20(_name, _symbol, _decimals)
Auth(_owner, Authority(address(0)))
{}
//============================== MANAGE ===============================
/**
* @notice Allows manager to make an arbitrary function call from this contract.
* @dev Callable by MANAGER_ROLE.
*/
function manage(address target, bytes calldata data, uint256 value)
external
requiresAuth
returns (bytes memory result)
{
result = target.functionCallWithValue(data, value);
}
/**
* @notice Allows manager to make arbitrary function calls from this contract.
* @dev Callable by MANAGER_ROLE.
*/
function manage(address[] calldata targets, bytes[] calldata data, uint256[] calldata values)
external
requiresAuth
returns (bytes[] memory results)
{
uint256 targetsLength = targets.length;
results = new bytes[](targetsLength);
for (uint256 i; i < targetsLength; ++i) {
results[i] = targets[i].functionCallWithValue(data[i], values[i]);
}
}
//============================== ENTER ===============================
/**
* @notice Allows minter to mint shares, in exchange for assets.
* @dev If assetAmount is zero, no assets are transferred in.
* @dev Callable by MINTER_ROLE.
*/
function enter(address from, ERC20 asset, uint256 assetAmount, address to, uint256 shareAmount)
external
requiresAuth
{
// Transfer assets in
if (assetAmount > 0) asset.safeTransferFrom(from, address(this), assetAmount);
// Mint shares.
_mint(to, shareAmount);
emit Enter(from, address(asset), assetAmount, to, shareAmount);
}
//============================== EXIT ===============================
/**
* @notice Allows burner to burn shares, in exchange for assets.
* @dev If assetAmount is zero, no assets are transferred out.
* @dev Callable by BURNER_ROLE.
*/
function exit(address to, ERC20 asset, uint256 assetAmount, address from, uint256 shareAmount)
external
requiresAuth
{
// Burn shares.
_burn(from, shareAmount);
// Transfer assets out.
if (assetAmount > 0) asset.safeTransfer(to, assetAmount);
emit Exit(to, address(asset), assetAmount, from, shareAmount);
}
//============================== BEFORE TRANSFER HOOK ===============================
/**
* @notice Sets the share locker.
* @notice If set to zero address, the share locker logic is disabled.
* @dev Callable by OWNER_ROLE.
*/
function setBeforeTransferHook(address _hook) external requiresAuth {
hook = BeforeTransferHook(_hook);
}
/**
* @notice Call `beforeTransferHook` passing in `from` `to`, and `msg.sender`.
*/
function _callBeforeTransfer(address from, address to) internal view {
if (address(hook) != address(0)) hook.beforeTransfer(from, to, msg.sender);
}
function transfer(address to, uint256 amount) public override returns (bool) {
_callBeforeTransfer(msg.sender, to);
return super.transfer(to, amount);
}
function transferFrom(address from, address to, uint256 amount) public override returns (bool) {
_callBeforeTransfer(from, to);
return super.transferFrom(from, to, amount);
}
//============================== RECEIVE ===============================
receive() external payable {}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.21;
import {FixedPointMathLib} from "@solmate/utils/FixedPointMathLib.sol";
import {IRateProvider} from "src/interfaces/IRateProvider.sol";
import {ERC20} from "@solmate/tokens/ERC20.sol";
import {SafeTransferLib} from "@solmate/utils/SafeTransferLib.sol";
import {BoringVault} from "src/base/BoringVault.sol";
import {Auth, Authority} from "@solmate/auth/Auth.sol";
import {IPausable} from "src/interfaces/IPausable.sol";
contract AccountantWithRateProviders is Auth, IRateProvider, IPausable {
using FixedPointMathLib for uint256;
using SafeTransferLib for ERC20;
// ========================================= STRUCTS =========================================
/**
* @param payoutAddress the address `claimFees` sends fees to
* @param highwaterMark the highest value of the BoringVault's share price
* @param feesOwedInBase total pending fees owed in terms of base
* @param totalSharesLastUpdate total amount of shares the last exchange rate update
* @param exchangeRate the current exchange rate in terms of base
* @param allowedExchangeRateChangeUpper the max allowed change to exchange rate from an update
* @param allowedExchangeRateChangeLower the min allowed change to exchange rate from an update
* @param lastUpdateTimestamp the block timestamp of the last exchange rate update
* @param isPaused whether or not this contract is paused
* @param minimumUpdateDelayInSeconds the minimum amount of time that must pass between
* exchange rate updates, such that the update won't trigger the contract to be paused
* @param platformFee the platform fee
* @param performanceFee the performance fee
*/
struct AccountantState {
address payoutAddress;
uint96 highwaterMark;
uint128 feesOwedInBase;
uint128 totalSharesLastUpdate;
uint96 exchangeRate;
uint16 allowedExchangeRateChangeUpper;
uint16 allowedExchangeRateChangeLower;
uint64 lastUpdateTimestamp;
bool isPaused;
uint24 minimumUpdateDelayInSeconds;
uint16 platformFee;
uint16 performanceFee;
}
/**
* @param isPeggedToBase whether or not the asset is 1:1 with the base asset
* @param rateProvider the rate provider for this asset if `isPeggedToBase` is false
*/
struct RateProviderData {
bool isPeggedToBase;
IRateProvider rateProvider;
}
// ========================================= STATE =========================================
/**
* @notice Store the accountant state in 3 packed slots.
*/
AccountantState public accountantState;
/**
* @notice Maps ERC20s to their RateProviderData.
*/
mapping(ERC20 => RateProviderData) public rateProviderData;
//============================== ERRORS ===============================
error AccountantWithRateProviders__UpperBoundTooSmall();
error AccountantWithRateProviders__LowerBoundTooLarge();
error AccountantWithRateProviders__PlatformFeeTooLarge();
error AccountantWithRateProviders__PerformanceFeeTooLarge();
error AccountantWithRateProviders__Paused();
error AccountantWithRateProviders__ZeroFeesOwed();
error AccountantWithRateProviders__OnlyCallableByBoringVault();
error AccountantWithRateProviders__UpdateDelayTooLarge();
error AccountantWithRateProviders__ExchangeRateAboveHighwaterMark();
//============================== EVENTS ===============================
event Paused();
event Unpaused();
event DelayInSecondsUpdated(uint24 oldDelay, uint24 newDelay);
event UpperBoundUpdated(uint16 oldBound, uint16 newBound);
event LowerBoundUpdated(uint16 oldBound, uint16 newBound);
event PlatformFeeUpdated(uint16 oldFee, uint16 newFee);
event PerformanceFeeUpdated(uint16 oldFee, uint16 newFee);
event PayoutAddressUpdated(address oldPayout, address newPayout);
event RateProviderUpdated(address asset, bool isPegged, address rateProvider);
event ExchangeRateUpdated(uint96 oldRate, uint96 newRate, uint64 currentTime);
event FeesClaimed(address indexed feeAsset, uint256 amount);
event HighwaterMarkReset();
//============================== IMMUTABLES ===============================
/**
* @notice The base asset rates are provided in.
*/
ERC20 public immutable base;
/**
* @notice The decimals rates are provided in.
*/
uint8 public immutable decimals;
/**
* @notice The BoringVault this accountant is working with.
* Used to determine share supply for fee calculation.
*/
BoringVault public immutable vault;
/**
* @notice One share of the BoringVault.
*/
uint256 internal immutable ONE_SHARE;
constructor(
address _owner,
address _vault,
address payoutAddress,
uint96 startingExchangeRate,
address _base,
uint16 allowedExchangeRateChangeUpper,
uint16 allowedExchangeRateChangeLower,
uint24 minimumUpdateDelayInSeconds,
uint16 platformFee,
uint16 performanceFee
) Auth(_owner, Authority(address(0))) {
base = ERC20(_base);
decimals = ERC20(_base).decimals();
vault = BoringVault(payable(_vault));
ONE_SHARE = 10 ** vault.decimals();
accountantState = AccountantState({
payoutAddress: payoutAddress,
highwaterMark: startingExchangeRate,
feesOwedInBase: 0,
totalSharesLastUpdate: uint128(vault.totalSupply()),
exchangeRate: startingExchangeRate,
allowedExchangeRateChangeUpper: allowedExchangeRateChangeUpper,
allowedExchangeRateChangeLower: allowedExchangeRateChangeLower,
lastUpdateTimestamp: uint64(block.timestamp),
isPaused: false,
minimumUpdateDelayInSeconds: minimumUpdateDelayInSeconds,
platformFee: platformFee,
performanceFee: performanceFee
});
}
// ========================================= ADMIN FUNCTIONS =========================================
/**
* @notice Pause this contract, which prevents future calls to `updateExchangeRate`, and any safe rate
* calls will revert.
* @dev Callable by MULTISIG_ROLE.
*/
function pause() external requiresAuth {
accountantState.isPaused = true;
emit Paused();
}
/**
* @notice Unpause this contract, which allows future calls to `updateExchangeRate`, and any safe rate
* calls will stop reverting.
* @dev Callable by MULTISIG_ROLE.
*/
function unpause() external requiresAuth {
accountantState.isPaused = false;
emit Unpaused();
}
/**
* @notice Update the minimum time delay between `updateExchangeRate` calls.
* @dev There are no input requirements, as it is possible the admin would want
* the exchange rate updated as frequently as needed.
* @dev Callable by OWNER_ROLE.
*/
function updateDelay(uint24 minimumUpdateDelayInSeconds) external requiresAuth {
if (minimumUpdateDelayInSeconds > 14 days) revert AccountantWithRateProviders__UpdateDelayTooLarge();
uint24 oldDelay = accountantState.minimumUpdateDelayInSeconds;
accountantState.minimumUpdateDelayInSeconds = minimumUpdateDelayInSeconds;
emit DelayInSecondsUpdated(oldDelay, minimumUpdateDelayInSeconds);
}
/**
* @notice Update the allowed upper bound change of exchange rate between `updateExchangeRateCalls`.
* @dev Callable by OWNER_ROLE.
*/
function updateUpper(uint16 allowedExchangeRateChangeUpper) external requiresAuth {
if (allowedExchangeRateChangeUpper < 1e4) revert AccountantWithRateProviders__UpperBoundTooSmall();
uint16 oldBound = accountantState.allowedExchangeRateChangeUpper;
accountantState.allowedExchangeRateChangeUpper = allowedExchangeRateChangeUpper;
emit UpperBoundUpdated(oldBound, allowedExchangeRateChangeUpper);
}
/**
* @notice Update the allowed lower bound change of exchange rate between `updateExchangeRateCalls`.
* @dev Callable by OWNER_ROLE.
*/
function updateLower(uint16 allowedExchangeRateChangeLower) external requiresAuth {
if (allowedExchangeRateChangeLower > 1e4) revert AccountantWithRateProviders__LowerBoundTooLarge();
uint16 oldBound = accountantState.allowedExchangeRateChangeLower;
accountantState.allowedExchangeRateChangeLower = allowedExchangeRateChangeLower;
emit LowerBoundUpdated(oldBound, allowedExchangeRateChangeLower);
}
/**
* @notice Update the platform fee to a new value.
* @dev Callable by OWNER_ROLE.
*/
function updatePlatformFee(uint16 platformFee) external requiresAuth {
if (platformFee > 0.2e4) revert AccountantWithRateProviders__PlatformFeeTooLarge();
uint16 oldFee = accountantState.platformFee;
accountantState.platformFee = platformFee;
emit PlatformFeeUpdated(oldFee, platformFee);
}
/**
* @notice Update the performance fee to a new value.
* @dev Callable by OWNER_ROLE.
*/
function updatePerformanceFee(uint16 performanceFee) external requiresAuth {
if (performanceFee > 0.5e4) revert AccountantWithRateProviders__PerformanceFeeTooLarge();
uint16 oldFee = accountantState.performanceFee;
accountantState.performanceFee = performanceFee;
emit PerformanceFeeUpdated(oldFee, performanceFee);
}
/**
* @notice Update the payout address fees are sent to.
* @dev Callable by OWNER_ROLE.
*/
function updatePayoutAddress(address payoutAddress) external requiresAuth {
address oldPayout = accountantState.payoutAddress;
accountantState.payoutAddress = payoutAddress;
emit PayoutAddressUpdated(oldPayout, payoutAddress);
}
/**
* @notice Update the rate provider data for a specific `asset`.
* @dev Rate providers must return rates in terms of `base` or
* an asset pegged to base and they must use the same decimals
* as `asset`.
* @dev Callable by OWNER_ROLE.
*/
function setRateProviderData(ERC20 asset, bool isPeggedToBase, address rateProvider) external requiresAuth {
rateProviderData[asset] =
RateProviderData({isPeggedToBase: isPeggedToBase, rateProvider: IRateProvider(rateProvider)});
emit RateProviderUpdated(address(asset), isPeggedToBase, rateProvider);
}
/**
* @notice Reset the highwater mark to the current exchange rate.
* @dev Callable by OWNER_ROLE.
*/
function resetHighwaterMark() external virtual requiresAuth {
AccountantState storage state = accountantState;
if (state.exchangeRate > state.highwaterMark) {
revert AccountantWithRateProviders__ExchangeRateAboveHighwaterMark();
}
uint64 currentTime = uint64(block.timestamp);
uint256 currentTotalShares = vault.totalSupply();
_calculateFeesOwed(state, state.exchangeRate, state.exchangeRate, currentTotalShares, currentTime);
state.totalSharesLastUpdate = uint128(currentTotalShares);
state.highwaterMark = accountantState.exchangeRate;
state.lastUpdateTimestamp = currentTime;
emit HighwaterMarkReset();
}
// ========================================= UPDATE EXCHANGE RATE/FEES FUNCTIONS =========================================
/**
* @notice Updates this contract exchangeRate.
* @dev If new exchange rate is outside of accepted bounds, or if not enough time has passed, this
* will pause the contract, and this function will NOT calculate fees owed.
* @dev Callable by UPDATE_EXCHANGE_RATE_ROLE.
*/
function updateExchangeRate(uint96 newExchangeRate) external virtual requiresAuth {
(
bool shouldPause,
AccountantState storage state,
uint64 currentTime,
uint256 currentExchangeRate,
uint256 currentTotalShares
) = _beforeUpdateExchangeRate(newExchangeRate);
if (shouldPause) {
// Instead of reverting, pause the contract. This way the exchange rate updater is able to update the exchange rate
// to a better value, and pause it.
state.isPaused = true;
} else {
_calculateFeesOwed(state, newExchangeRate, currentExchangeRate, currentTotalShares, currentTime);
}
newExchangeRate = _setExchangeRate(newExchangeRate, state);
state.totalSharesLastUpdate = uint128(currentTotalShares);
state.lastUpdateTimestamp = currentTime;
emit ExchangeRateUpdated(uint96(currentExchangeRate), newExchangeRate, currentTime);
}
/**
* @notice Claim pending fees.
* @dev This function must be called by the BoringVault.
* @dev This function will lose precision if the exchange rate
* decimals is greater than the feeAsset's decimals.
*/
function claimFees(ERC20 feeAsset) external {
if (msg.sender != address(vault)) revert AccountantWithRateProviders__OnlyCallableByBoringVault();
AccountantState storage state = accountantState;
if (state.isPaused) revert AccountantWithRateProviders__Paused();
if (state.feesOwedInBase == 0) revert AccountantWithRateProviders__ZeroFeesOwed();
// Determine amount of fees owed in feeAsset.
uint256 feesOwedInFeeAsset;
RateProviderData memory data = rateProviderData[feeAsset];
if (address(feeAsset) == address(base)) {
feesOwedInFeeAsset = state.feesOwedInBase;
} else {
uint8 feeAssetDecimals = ERC20(feeAsset).decimals();
uint256 feesOwedInBaseUsingFeeAssetDecimals =
_changeDecimals(state.feesOwedInBase, decimals, feeAssetDecimals);
if (data.isPeggedToBase) {
feesOwedInFeeAsset = feesOwedInBaseUsingFeeAssetDecimals;
} else {
uint256 rate = data.rateProvider.getRate();
feesOwedInFeeAsset = feesOwedInBaseUsingFeeAssetDecimals.mulDivDown(10 ** feeAssetDecimals, rate);
}
}
// Zero out fees owed.
state.feesOwedInBase = 0;
// Transfer fee asset to payout address.
feeAsset.safeTransferFrom(msg.sender, state.payoutAddress, feesOwedInFeeAsset);
emit FeesClaimed(address(feeAsset), feesOwedInFeeAsset);
}
// ========================================= VIEW FUNCTIONS =========================================
/**
* @notice Get this BoringVault's current rate in the base.
*/
function getRate() public view returns (uint256 rate) {
rate = accountantState.exchangeRate;
}
/**
* @notice Get this BoringVault's current rate in the base.
* @dev Revert if paused.
*/
function getRateSafe() external view returns (uint256 rate) {
if (accountantState.isPaused) revert AccountantWithRateProviders__Paused();
rate = getRate();
}
/**
* @notice Get this BoringVault's current rate in the provided quote.
* @dev `quote` must have its RateProviderData set, else this will revert.
* @dev This function will lose precision if the exchange rate
* decimals is greater than the quote's decimals.
*/
function getRateInQuote(ERC20 quote) public view returns (uint256 rateInQuote) {
if (address(quote) == address(base)) {
rateInQuote = accountantState.exchangeRate;
} else {
RateProviderData memory data = rateProviderData[quote];
uint8 quoteDecimals = ERC20(quote).decimals();
uint256 exchangeRateInQuoteDecimals = _changeDecimals(accountantState.exchangeRate, decimals, quoteDecimals);
if (data.isPeggedToBase) {
rateInQuote = exchangeRateInQuoteDecimals;
} else {
uint256 quoteRate = data.rateProvider.getRate();
uint256 oneQuote = 10 ** quoteDecimals;
rateInQuote = oneQuote.mulDivDown(exchangeRateInQuoteDecimals, quoteRate);
}
}
}
/**
* @notice Get this BoringVault's current rate in the provided quote.
* @dev `quote` must have its RateProviderData set, else this will revert.
* @dev Revert if paused.
*/
function getRateInQuoteSafe(ERC20 quote) external view returns (uint256 rateInQuote) {
if (accountantState.isPaused) revert AccountantWithRateProviders__Paused();
rateInQuote = getRateInQuote(quote);
}
/**
* @notice Preview the result of an update to the exchange rate.
* @return updateWillPause Whether the update will pause the contract.
* @return newFeesOwedInBase The new fees owed in base.
* @return totalFeesOwedInBase The total fees owed in base.
*/
function previewUpdateExchangeRate(uint96 newExchangeRate)
external
view
virtual
returns (bool updateWillPause, uint256 newFeesOwedInBase, uint256 totalFeesOwedInBase)
{
(
bool shouldPause,
AccountantState storage state,
uint64 currentTime,
uint256 currentExchangeRate,
uint256 currentTotalShares
) = _beforeUpdateExchangeRate(newExchangeRate);
updateWillPause = shouldPause;
totalFeesOwedInBase = state.feesOwedInBase;
if (!shouldPause) {
(uint256 platformFeesOwedInBase, uint256 shareSupplyToUse) = _calculatePlatformFee(
state.totalSharesLastUpdate,
state.lastUpdateTimestamp,
state.platformFee,
newExchangeRate,
currentExchangeRate,
currentTotalShares,
currentTime
);
uint256 performanceFeesOwedInBase;
if (newExchangeRate > state.highwaterMark) {
(performanceFeesOwedInBase,) = _calculatePerformanceFee(
newExchangeRate, shareSupplyToUse, state.highwaterMark, state.performanceFee
);
}
newFeesOwedInBase = platformFeesOwedInBase + performanceFeesOwedInBase;
totalFeesOwedInBase += newFeesOwedInBase;
}
}
// ========================================= INTERNAL HELPER FUNCTIONS =========================================
/**
* @notice Used to change the decimals of precision used for an amount.
*/
function _changeDecimals(uint256 amount, uint8 fromDecimals, uint8 toDecimals) internal pure returns (uint256) {
if (fromDecimals == toDecimals) {
return amount;
} else if (fromDecimals < toDecimals) {
return amount * 10 ** (toDecimals - fromDecimals);
} else {
return amount / 10 ** (fromDecimals - toDecimals);
}
}
/**
* @notice Check if the new exchange rate is outside of the allowed bounds or if not enough time has passed.
*/
function _beforeUpdateExchangeRate(uint96 newExchangeRate)
internal
view
returns (
bool shouldPause,
AccountantState storage state,
uint64 currentTime,
uint256 currentExchangeRate,
uint256 currentTotalShares
)
{
state = accountantState;
if (state.isPaused) revert AccountantWithRateProviders__Paused();
currentTime = uint64(block.timestamp);
currentExchangeRate = state.exchangeRate;
currentTotalShares = vault.totalSupply();
shouldPause = currentTime < state.lastUpdateTimestamp + state.minimumUpdateDelayInSeconds
|| newExchangeRate > currentExchangeRate.mulDivDown(state.allowedExchangeRateChangeUpper, 1e4)
|| newExchangeRate < currentExchangeRate.mulDivDown(state.allowedExchangeRateChangeLower, 1e4);
}
/**
* @notice Set the exchange rate.
*/
function _setExchangeRate(uint96 newExchangeRate, AccountantState storage state)
internal
virtual
returns (uint96)
{
state.exchangeRate = newExchangeRate;
return newExchangeRate;
}
/**
* @notice Calculate platform fees.
*/
function _calculatePlatformFee(
uint128 totalSharesLastUpdate,
uint64 lastUpdateTimestamp,
uint16 platformFee,
uint96 newExchangeRate,
uint256 currentExchangeRate,
uint256 currentTotalShares,
uint64 currentTime
) internal view returns (uint256 platformFeesOwedInBase, uint256 shareSupplyToUse) {
shareSupplyToUse = currentTotalShares;
// Use the minimum between current total supply and total supply for last update.
if (totalSharesLastUpdate < shareSupplyToUse) {
shareSupplyToUse = totalSharesLastUpdate;
}
// Determine platform fees owned.
if (platformFee > 0) {
uint256 timeDelta = currentTime - lastUpdateTimestamp;
uint256 minimumAssets = newExchangeRate > currentExchangeRate
? shareSupplyToUse.mulDivDown(currentExchangeRate, ONE_SHARE)
: shareSupplyToUse.mulDivDown(newExchangeRate, ONE_SHARE);
uint256 platformFeesAnnual = minimumAssets.mulDivDown(platformFee, 1e4);
platformFeesOwedInBase = platformFeesAnnual.mulDivDown(timeDelta, 365 days);
}
}
/**
* @notice Calculate performance fees.
*/
function _calculatePerformanceFee(
uint96 newExchangeRate,
uint256 shareSupplyToUse,
uint96 datum,
uint16 performanceFee
) internal view returns (uint256 performanceFeesOwedInBase, uint256 yieldEarned) {
uint256 changeInExchangeRate = newExchangeRate - datum;
yieldEarned = changeInExchangeRate.mulDivDown(shareSupplyToUse, ONE_SHARE);
if (performanceFee > 0) {
performanceFeesOwedInBase = yieldEarned.mulDivDown(performanceFee, 1e4);
}
}
/**
* @notice Calculate fees owed in base.
* @dev This function will update the highwater mark if the new exchange rate is higher.
*/
function _calculateFeesOwed(
AccountantState storage state,
uint96 newExchangeRate,
uint256 currentExchangeRate,
uint256 currentTotalShares,
uint64 currentTime
) internal virtual {
// Only update fees if we are not paused.
// Update fee accounting.
(uint256 newFeesOwedInBase, uint256 shareSupplyToUse) = _calculatePlatformFee(
state.totalSharesLastUpdate,
state.lastUpdateTimestamp,
state.platformFee,
newExchangeRate,
currentExchangeRate,
currentTotalShares,
currentTime
);
// Account for performance fees.
if (newExchangeRate > state.highwaterMark) {
(uint256 performanceFeesOwedInBase,) =
_calculatePerformanceFee(newExchangeRate, shareSupplyToUse, state.highwaterMark, state.performanceFee);
// Add performance fees to fees owed.
newFeesOwedInBase += performanceFeesOwedInBase;
// Always update the highwater mark if the new exchange rate is higher.
// This way if we are not iniitiall taking performance fees, we can start taking them
// without back charging them on past performance.
state.highwaterMark = newExchangeRate;
}
state.feesOwedInBase += uint128(newFeesOwedInBase);
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
/// @notice Arithmetic library with operations for fixed-point numbers.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol)
/// @author Inspired by USM (https://github.com/usmfum/USM/blob/master/contracts/WadMath.sol)
library FixedPointMathLib {
/*//////////////////////////////////////////////////////////////
SIMPLIFIED FIXED POINT OPERATIONS
//////////////////////////////////////////////////////////////*/
uint256 internal constant MAX_UINT256 = 2**256 - 1;
uint256 internal constant WAD = 1e18; // The scalar of ETH and most ERC20s.
function mulWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivDown(x, y, WAD); // Equivalent to (x * y) / WAD rounded down.
}
function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivUp(x, y, WAD); // Equivalent to (x * y) / WAD rounded up.
}
function divWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivDown(x, WAD, y); // Equivalent to (x * WAD) / y rounded down.
}
function divWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivUp(x, WAD, y); // Equivalent to (x * WAD) / y rounded up.
}
/*//////////////////////////////////////////////////////////////
LOW LEVEL FIXED POINT OPERATIONS
//////////////////////////////////////////////////////////////*/
function mulDivDown(
uint256 x,
uint256 y,
uint256 denominator
) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y))
if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) {
revert(0, 0)
}
// Divide x * y by the denominator.
z := div(mul(x, y), denominator)
}
}
function mulDivUp(
uint256 x,
uint256 y,
uint256 denominator
) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y))
if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) {
revert(0, 0)
}
// If x * y modulo the denominator is strictly greater than 0,
// 1 is added to round up the division of x * y by the denominator.
z := add(gt(mod(mul(x, y), denominator), 0), div(mul(x, y), denominator))
}
}
function rpow(
uint256 x,
uint256 n,
uint256 scalar
) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
switch x
case 0 {
switch n
case 0 {
// 0 ** 0 = 1
z := scalar
}
default {
// 0 ** n = 0
z := 0
}
}
default {
switch mod(n, 2)
case 0 {
// If n is even, store scalar in z for now.
z := scalar
}
default {
// If n is odd, store x in z for now.
z := x
}
// Shifting right by 1 is like dividing by 2.
let half := shr(1, scalar)
for {
// Shift n right by 1 before looping to halve it.
n := shr(1, n)
} n {
// Shift n right by 1 each iteration to halve it.
n := shr(1, n)
} {
// Revert immediately if x ** 2 would overflow.
// Equivalent to iszero(eq(div(xx, x), x)) here.
if shr(128, x) {
revert(0, 0)
}
// Store x squared.
let xx := mul(x, x)
// Round to the nearest number.
let xxRound := add(xx, half)
// Revert if xx + half overflowed.
if lt(xxRound, xx) {
revert(0, 0)
}
// Set x to scaled xxRound.
x := div(xxRound, scalar)
// If n is even:
if mod(n, 2) {
// Compute z * x.
let zx := mul(z, x)
// If z * x overflowed:
if iszero(eq(div(zx, x), z)) {
// Revert if x is non-zero.
if iszero(iszero(x)) {
revert(0, 0)
}
}
// Round to the nearest number.
let zxRound := add(zx, half)
// Revert if zx + half overflowed.
if lt(zxRound, zx) {
revert(0, 0)
}
// Return properly scaled zxRound.
z := div(zxRound, scalar)
}
}
}
}
}
/*//////////////////////////////////////////////////////////////
GENERAL NUMBER UTILITIES
//////////////////////////////////////////////////////////////*/
function sqrt(uint256 x) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
let y := x // We start y at x, which will help us make our initial estimate.
z := 181 // The "correct" value is 1, but this saves a multiplication later.
// This segment is to get a reasonable initial estimate for the Babylonian method. With a bad
// start, the correct # of bits increases ~linearly each iteration instead of ~quadratically.
// We check y >= 2^(k + 8) but shift right by k bits
// each branch to ensure that if x >= 256, then y >= 256.
if iszero(lt(y, 0x10000000000000000000000000000000000)) {
y := shr(128, y)
z := shl(64, z)
}
if iszero(lt(y, 0x1000000000000000000)) {
y := shr(64, y)
z := shl(32, z)
}
if iszero(lt(y, 0x10000000000)) {
y := shr(32, y)
z := shl(16, z)
}
if iszero(lt(y, 0x1000000)) {
y := shr(16, y)
z := shl(8, z)
}
// Goal was to get z*z*y within a small factor of x. More iterations could
// get y in a tighter range. Currently, we will have y in [256, 256*2^16).
// We ensured y >= 256 so that the relative difference between y and y+1 is small.
// That's not possible if x < 256 but we can just verify those cases exhaustively.
// Now, z*z*y <= x < z*z*(y+1), and y <= 2^(16+8), and either y >= 256, or x < 256.
// Correctness can be checked exhaustively for x < 256, so we assume y >= 256.
// Then z*sqrt(y) is within sqrt(257)/sqrt(256) of sqrt(x), or about 20bps.
// For s in the range [1/256, 256], the estimate f(s) = (181/1024) * (s+1) is in the range
// (1/2.84 * sqrt(s), 2.84 * sqrt(s)), with largest error when s = 1 and when s = 256 or 1/256.
// Since y is in [256, 256*2^16), let a = y/65536, so that a is in [1/256, 256). Then we can estimate
// sqrt(y) using sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2^18.
// There is no overflow risk here since y < 2^136 after the first branch above.
z := shr(18, mul(z, add(y, 65536))) // A mul() is saved from starting z at 181.
// Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough.
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
// If x+1 is a perfect square, the Babylonian method cycles between
// floor(sqrt(x)) and ceil(sqrt(x)). This statement ensures we return floor.
// See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division
// Since the ceil is rare, we save gas on the assignment and repeat division in the rare case.
// If you don't care whether the floor or ceil square root is returned, you can remove this statement.
z := sub(z, lt(div(x, z), z))
}
}
function unsafeMod(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Mod x by y. Note this will return
// 0 instead of reverting if y is zero.
z := mod(x, y)
}
}
function unsafeDiv(uint256 x, uint256 y) internal pure returns (uint256 r) {
/// @solidity memory-safe-assembly
assembly {
// Divide x by y. Note this will return
// 0 instead of reverting if y is zero.
r := div(x, y)
}
}
function unsafeDivUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Add 1 to x * y if x % y > 0. Note this will
// return 0 instead of reverting if y is zero.
z := add(gt(mod(x, y), 0), div(x, y))
}
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.21;
interface BeforeTransferHook {
function beforeTransfer(address from, address to, address operator) external view;
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
/// @notice Provides a flexible and updatable auth pattern which is completely separate from application logic.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/auth/Auth.sol)
/// @author Modified from Dappsys (https://github.com/dapphub/ds-auth/blob/master/src/auth.sol)
abstract contract Auth {
event OwnershipTransferred(address indexed user, address indexed newOwner);
event AuthorityUpdated(address indexed user, Authority indexed newAuthority);
address public owner;
Authority public authority;
constructor(address _owner, Authority _authority) {
owner = _owner;
authority = _authority;
emit OwnershipTransferred(msg.sender, _owner);
emit AuthorityUpdated(msg.sender, _authority);
}
modifier requiresAuth() virtual {
require(isAuthorized(msg.sender, msg.sig), "UNAUTHORIZED");
_;
}
function isAuthorized(address user, bytes4 functionSig) internal view virtual returns (bool) {
Authority auth = authority; // Memoizing authority saves us a warm SLOAD, around 100 gas.
// Checking if the caller is the owner only after calling the authority saves gas in most cases, but be
// aware that this makes protected functions uncallable even to the owner if the authority is out of order.
return (address(auth) != address(0) && auth.canCall(user, address(this), functionSig)) || user == owner;
}
function setAuthority(Authority newAuthority) public virtual {
// We check if the caller is the owner first because we want to ensure they can
// always swap out the authority even if it's reverting or using up a lot of gas.
require(msg.sender == owner || authority.canCall(msg.sender, address(this), msg.sig));
authority = newAuthority;
emit AuthorityUpdated(msg.sender, newAuthority);
}
function transferOwnership(address newOwner) public virtual requiresAuth {
owner = newOwner;
emit OwnershipTransferred(msg.sender, newOwner);
}
}
/// @notice A generic interface for a contract which provides authorization data to an Auth instance.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/auth/Auth.sol)
/// @author Modified from Dappsys (https://github.com/dapphub/ds-auth/blob/master/src/auth.sol)
interface Authority {
function canCall(
address user,
address target,
bytes4 functionSig
) external view returns (bool);
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
/// @notice Gas optimized reentrancy protection for smart contracts.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/ReentrancyGuard.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/security/ReentrancyGuard.sol)
abstract contract ReentrancyGuard {
uint256 private locked = 1;
modifier nonReentrant() virtual {
require(locked == 1, "REENTRANCY");
locked = 2;
_;
locked = 1;
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.21;
interface IPausable {
function pause() external;
function unpause() external;
}// 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 { ILayerZeroReceiver, Origin } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroReceiver.sol";
interface IOAppReceiver is ILayerZeroReceiver {
/**
* @notice Retrieves the address responsible for 'sending' composeMsg's to the Endpoint.
* @return sender The address responsible for 'sending' composeMsg's to the Endpoint.
*
* @dev Applications can optionally choose to implement a separate composeMsg sender that is NOT the bridging layer.
* @dev The default sender IS the OApp implementer.
*/
function composeMsgSender() external view returns (address sender);
}// 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 v5.0.0) (utils/Address.sol)
pragma solidity ^0.8.20;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/
error AddressInsufficientBalance(address account);
/**
* @dev There's no code at `target` (it is not a contract).
*/
error AddressEmptyCode(address target);
/**
* @dev A call to an address target failed. The target may have reverted.
*/
error FailedInnerCall();
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert AddressInsufficientBalance(address(this));
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert FailedInnerCall();
}
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason or custom error, it is bubbled
* up by this function (like regular Solidity function calls). However, if
* the call reverted with no returned reason, this function reverts with a
* {FailedInnerCall} error.
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert AddressInsufficientBalance(address(this));
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
* was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
* unsuccessful call.
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
// only check if target is a contract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
/**
* @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
* revert reason or with a default {FailedInnerCall} error.
*/
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
/**
* @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
*/
function _revert(bytes memory returndata) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert FailedInnerCall();
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/utils/ERC721Holder.sol)
pragma solidity ^0.8.20;
import {IERC721Receiver} from "../IERC721Receiver.sol";
/**
* @dev Implementation of the {IERC721Receiver} interface.
*
* Accepts all token transfers.
* Make sure the contract is able to use its token with {IERC721-safeTransferFrom}, {IERC721-approve} or
* {IERC721-setApprovalForAll}.
*/
abstract contract ERC721Holder is IERC721Receiver {
/**
* @dev See {IERC721Receiver-onERC721Received}.
*
* Always returns `IERC721Receiver.onERC721Received.selector`.
*/
function onERC721Received(address, address, uint256, bytes memory) public virtual returns (bytes4) {
return this.onERC721Received.selector;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/utils/ERC1155Holder.sol)
pragma solidity ^0.8.20;
import {IERC165, ERC165} from "../../../utils/introspection/ERC165.sol";
import {IERC1155Receiver} from "../IERC1155Receiver.sol";
/**
* @dev Simple implementation of `IERC1155Receiver` that will allow a contract to hold ERC1155 tokens.
*
* IMPORTANT: When inheriting this contract, you must include a way to use the received tokens, otherwise they will be
* stuck.
*/
abstract contract ERC1155Holder is ERC165, IERC1155Receiver {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
return interfaceId == type(IERC1155Receiver).interfaceId || super.supportsInterface(interfaceId);
}
function onERC1155Received(
address,
address,
uint256,
uint256,
bytes memory
) public virtual override returns (bytes4) {
return this.onERC1155Received.selector;
}
function onERC1155BatchReceived(
address,
address,
uint256[] memory,
uint256[] memory,
bytes memory
) public virtual override returns (bytes4) {
return this.onERC1155BatchReceived.selector;
}
}// SPDX-License-Identifier: UNLICENSED
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
pragma solidity ^0.8.0;
interface IRateProvider {
function getRate() external view returns (uint256);
}// 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 _timeout) external;
function defaultReceiveLibrary(uint32 _eid) external view returns (address);
function setDefaultReceiveLibraryTimeout(uint32 _eid, address _lib, uint256 _expiry) external;
function defaultReceiveLibraryTimeout(uint32 _eid) external view returns (address lib, uint256 expiry);
function isSupportedEid(uint32 _eid) external view returns (bool);
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 _gracePeriod) external;
function receiveLibraryTimeout(address _receiver, uint32 _eid) external view returns (address lib, uint256 expiry);
function setConfig(address _oapp, address _lib, SetConfigParam[] calldata _params) external;
function getConfig(
address _oapp,
address _lib,
uint32 _eid,
uint32 _configType
) external view returns (bytes memory config);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
interface 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
pragma solidity >=0.8.0;
import { Origin } from "./ILayerZeroEndpointV2.sol";
interface ILayerZeroReceiver {
function allowInitializePath(Origin calldata _origin) external view returns (bool);
function nextNonce(uint32 _eid, bytes32 _sender) external view returns (uint64);
function lzReceive(
Origin calldata _origin,
bytes32 _guid,
bytes calldata _message,
address _executor,
bytes calldata _extraData
) external payable;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721Receiver.sol)
pragma solidity ^0.8.20;
/**
* @title ERC721 token receiver interface
* @dev Interface for any contract that wants to support safeTransfers
* from ERC721 asset contracts.
*/
interface IERC721Receiver {
/**
* @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
* by `operator` from `from`, this function is called.
*
* It must return its Solidity selector to confirm the token transfer.
* If any other value is returned or the interface is not implemented by the recipient, the transfer will be
* reverted.
*
* The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
*/
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/IERC1155Receiver.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../../utils/introspection/IERC165.sol";
/**
* @dev Interface that must be implemented by smart contracts in order to receive
* ERC-1155 token transfers.
*/
interface IERC1155Receiver is IERC165 {
/**
* @dev Handles the receipt of a single ERC1155 token type. This function is
* called at the end of a `safeTransferFrom` after the balance has been updated.
*
* NOTE: To accept the transfer, this must return
* `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
* (i.e. 0xf23a6e61, or its own function selector).
*
* @param operator The address which initiated the transfer (i.e. msg.sender)
* @param from The address which previously owned the token
* @param id The ID of the token being transferred
* @param value The amount of tokens being transferred
* @param data Additional data with no specified format
* @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed
*/
function onERC1155Received(
address operator,
address from,
uint256 id,
uint256 value,
bytes calldata data
) external returns (bytes4);
/**
* @dev Handles the receipt of a multiple ERC1155 token types. This function
* is called at the end of a `safeBatchTransferFrom` after the balances have
* been updated.
*
* NOTE: To accept the transfer(s), this must return
* `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
* (i.e. 0xbc197c81, or its own function selector).
*
* @param operator The address which initiated the batch transfer (i.e. msg.sender)
* @param from The address which previously owned the token
* @param ids An array containing ids of each token being transferred (order and length must match values array)
* @param values An array containing amounts of each token being transferred (order and length must match ids array)
* @param data Additional data with no specified format
* @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed
*/
function onERC1155BatchReceived(
address operator,
address from,
uint256[] calldata ids,
uint256[] calldata values,
bytes calldata data
) external returns (bytes4);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}{
"remappings": [
"@solmate/=lib/solmate/src/",
"@forge-std/=lib/forge-std/src/",
"@ds-test/=lib/forge-std/lib/ds-test/src/",
"ds-test/=lib/forge-std/lib/ds-test/src/",
"@openzeppelin/=lib/openzeppelin-contracts/",
"@ccip/=lib/ccip/",
"@oapp-auth/=lib/OAppAuth/src/",
"@devtools-oapp-evm/=lib/OAppAuth/lib/devtools/packages/oapp-evm/contracts/oapp/",
"@layerzerolabs/lz-evm-messagelib-v2/=lib/OAppAuth/node_modules/@layerzerolabs/lz-evm-messagelib-v2/",
"@layerzerolabs/lz-evm-protocol-v2/=lib/OAppAuth/lib/LayerZero-V2/packages/layerzero-v2/evm/protocol/",
"@layerzerolabs/oapp-evm/=lib/OAppAuth/lib/devtools/packages/oapp-evm/",
"@lz-oapp-evm/=lib/OAppAuth/lib/LayerZero-V2/packages/layerzero-v2/evm/oapp/contracts/oapp/",
"@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
"@sbu/=lib/OAppAuth/lib/solidity-bytes-utils/",
"LayerZero-V2/=lib/OAppAuth/lib/",
"OAppAuth/=lib/OAppAuth/",
"ccip/=lib/ccip/contracts/",
"erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
"forge-std/=lib/forge-std/src/",
"halmos-cheatcodes/=lib/OAppAuth/lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/",
"solidity-bytes-utils/=lib/OAppAuth/node_modules/solidity-bytes-utils/",
"solmate/=lib/solmate/src/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "shanghai",
"viaIR": false,
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_vault","type":"address"},{"internalType":"address","name":"_accountant","type":"address"},{"internalType":"address","name":"_weth","type":"address"},{"internalType":"address","name":"_lzEndPoint","type":"address"},{"internalType":"address","name":"_delegate","type":"address"},{"internalType":"address","name":"_lzToken","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"CrossChainTellerWithGenericBridge__UnsafeCastToUint96","type":"error"},{"inputs":[],"name":"InboundRateLimitExceeded","type":"error"},{"inputs":[],"name":"InvalidDelegate","type":"error"},{"inputs":[],"name":"InvalidEndpointCall","type":"error"},{"inputs":[{"internalType":"uint16","name":"optionType","type":"uint16"}],"name":"InvalidOptionType","type":"error"},{"inputs":[],"name":"LayerZeroTeller__BadFeeToken","type":"error"},{"inputs":[{"internalType":"uint256","name":"chainSelector","type":"uint256"},{"internalType":"uint256","name":"fee","type":"uint256"},{"internalType":"uint256","name":"maxFee","type":"uint256"}],"name":"LayerZeroTeller__FeeExceedsMax","type":"error"},{"inputs":[{"internalType":"uint256","name":"chainSelector","type":"uint256"}],"name":"LayerZeroTeller__MessagesNotAllowedFrom","type":"error"},{"inputs":[{"internalType":"uint256","name":"chainSelector","type":"uint256"},{"internalType":"address","name":"sender","type":"address"}],"name":"LayerZeroTeller__MessagesNotAllowedFromSender","type":"error"},{"inputs":[{"internalType":"uint256","name":"chainSelector","type":"uint256"}],"name":"LayerZeroTeller__MessagesNotAllowedTo","type":"error"},{"inputs":[],"name":"LayerZeroTeller__ZeroMessageGasLimit","type":"error"},{"inputs":[],"name":"LzTokenUnavailable","type":"error"},{"inputs":[],"name":"MessageLib__ShareAmountOverflow","type":"error"},{"inputs":[{"internalType":"uint32","name":"eid","type":"uint32"}],"name":"NoPeer","type":"error"},{"inputs":[{"internalType":"uint256","name":"msgValue","type":"uint256"}],"name":"NotEnoughNative","type":"error"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"OnlyEndpoint","type":"error"},{"inputs":[{"internalType":"uint32","name":"eid","type":"uint32"},{"internalType":"bytes32","name":"sender","type":"bytes32"}],"name":"OnlyPeer","type":"error"},{"inputs":[],"name":"OutboundRateLimitExceeded","type":"error"},{"inputs":[{"internalType":"uint8","name":"bits","type":"uint8"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"SafeCastOverflowedUintDowncast","type":"error"},{"inputs":[],"name":"TellerWithMultiAssetSupport__AssetNotSupported","type":"error"},{"inputs":[],"name":"TellerWithMultiAssetSupport__BadDepositHash","type":"error"},{"inputs":[],"name":"TellerWithMultiAssetSupport__CannotDepositNative","type":"error"},{"inputs":[],"name":"TellerWithMultiAssetSupport__DualDeposit","type":"error"},{"inputs":[],"name":"TellerWithMultiAssetSupport__MinimumAssetsNotMet","type":"error"},{"inputs":[],"name":"TellerWithMultiAssetSupport__MinimumMintNotMet","type":"error"},{"inputs":[],"name":"TellerWithMultiAssetSupport__Paused","type":"error"},{"inputs":[],"name":"TellerWithMultiAssetSupport__PermitFailedAndAllowanceTooLow","type":"error"},{"inputs":[],"name":"TellerWithMultiAssetSupport__ShareLockPeriodTooLong","type":"error"},{"inputs":[],"name":"TellerWithMultiAssetSupport__SharePremiumTooLarge","type":"error"},{"inputs":[],"name":"TellerWithMultiAssetSupport__SharesAreLocked","type":"error"},{"inputs":[],"name":"TellerWithMultiAssetSupport__SharesAreUnLocked","type":"error"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"TellerWithMultiAssetSupport__TransferDenied","type":"error"},{"inputs":[],"name":"TellerWithMultiAssetSupport__ZeroAssets","type":"error"},{"inputs":[],"name":"TellerWithMultiAssetSupport__ZeroShares","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"}],"name":"AllowFrom","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"}],"name":"AllowOperator","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"}],"name":"AllowTo","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"bool","name":"allowDeposits","type":"bool"},{"indexed":false,"internalType":"bool","name":"allowWithdraws","type":"bool"},{"indexed":false,"internalType":"uint16","name":"sharePremium","type":"uint16"}],"name":"AssetDataUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"contract Authority","name":"newAuthority","type":"address"}],"name":"AuthorityUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"depositAmount","type":"uint256"}],"name":"BulkDeposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"shareAmount","type":"uint256"}],"name":"BulkWithdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"chainId","type":"uint256"},{"indexed":false,"internalType":"bool","name":"allowMessagesFrom","type":"bool"},{"indexed":false,"internalType":"bool","name":"allowMessagesTo","type":"bool"},{"indexed":false,"internalType":"address","name":"targetTeller","type":"address"}],"name":"ChainAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"chainId","type":"uint256"},{"indexed":false,"internalType":"address","name":"targetTeller","type":"address"}],"name":"ChainAllowMessagesFrom","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"chainId","type":"uint256"},{"indexed":false,"internalType":"address","name":"targetTeller","type":"address"}],"name":"ChainAllowMessagesTo","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"chainId","type":"uint256"}],"name":"ChainRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"chainId","type":"uint256"},{"indexed":false,"internalType":"uint128","name":"messageGasLimit","type":"uint128"}],"name":"ChainSetGasLimit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"chainId","type":"uint256"}],"name":"ChainStopMessagesFrom","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"chainId","type":"uint256"}],"name":"ChainStopMessagesTo","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"}],"name":"DenyFrom","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"}],"name":"DenyOperator","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"}],"name":"DenyTo","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"nonce","type":"uint256"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":true,"internalType":"address","name":"depositAsset","type":"address"},{"indexed":false,"internalType":"uint256","name":"depositAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shareAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"depositTimestamp","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shareLockPeriodAtTimeOfDeposit","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"nonce","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"depositHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"user","type":"address"}],"name":"DepositRefunded","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"uint32","name":"peerEid","type":"uint32"},{"internalType":"uint256","name":"limit","type":"uint256"},{"internalType":"uint256","name":"window","type":"uint256"}],"indexed":false,"internalType":"struct PairwiseRateLimiter.RateLimitConfig[]","name":"rateLimitConfigs","type":"tuple[]"}],"name":"InboundRateLimitsChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"messageId","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"shareAmount","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"MessageReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"messageId","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"shareAmount","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"MessageSent","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"uint32","name":"peerEid","type":"uint32"},{"internalType":"uint256","name":"limit","type":"uint256"},{"internalType":"uint256","name":"window","type":"uint256"}],"indexed":false,"internalType":"struct PairwiseRateLimiter.RateLimitConfig[]","name":"rateLimitConfigs","type":"tuple[]"}],"name":"OutboundRateLimitsChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"eid","type":"uint32"},{"indexed":false,"internalType":"bytes32","name":"peer","type":"bytes32"}],"name":"PeerSet","type":"event"},{"anonymous":false,"inputs":[],"name":"Unpaused","type":"event"},{"inputs":[],"name":"accountant","outputs":[{"internalType":"contract AccountantWithRateProviders","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"chainId","type":"uint32"},{"internalType":"bool","name":"allowMessagesFrom","type":"bool"},{"internalType":"bool","name":"allowMessagesTo","type":"bool"},{"internalType":"address","name":"targetTeller","type":"address"},{"internalType":"uint128","name":"messageGasLimit","type":"uint128"}],"name":"addChain","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"allowAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"allowFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"srcEid","type":"uint32"},{"internalType":"bytes32","name":"sender","type":"bytes32"},{"internalType":"uint64","name":"nonce","type":"uint64"}],"internalType":"struct Origin","name":"origin","type":"tuple"}],"name":"allowInitializePath","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"chainId","type":"uint32"},{"internalType":"address","name":"targetTeller","type":"address"}],"name":"allowMessagesFromChain","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"chainId","type":"uint32"},{"internalType":"address","name":"targetTeller","type":"address"},{"internalType":"uint128","name":"messageGasLimit","type":"uint128"}],"name":"allowMessagesToChain","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"allowOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"allowTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ERC20","name":"","type":"address"}],"name":"assetData","outputs":[{"internalType":"bool","name":"allowDeposits","type":"bool"},{"internalType":"bool","name":"allowWithdraws","type":"bool"},{"internalType":"uint16","name":"sharePremium","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"authority","outputs":[{"internalType":"contract Authority","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"beforeTransfer","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"}],"name":"beforeTransfer","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint96","name":"shareAmount","type":"uint96"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bytes","name":"bridgeWildCard","type":"bytes"},{"internalType":"contract ERC20","name":"feeToken","type":"address"},{"internalType":"uint256","name":"maxFee","type":"uint256"}],"name":"bridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract ERC20","name":"depositAsset","type":"address"},{"internalType":"uint256","name":"depositAmount","type":"uint256"},{"internalType":"uint256","name":"minimumMint","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"bulkDeposit","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ERC20","name":"withdrawAsset","type":"address"},{"internalType":"uint256","name":"shareAmount","type":"uint256"},{"internalType":"uint256","name":"minimumAssets","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"bulkWithdraw","outputs":[{"internalType":"uint256","name":"assetsOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"composeMsgSender","outputs":[{"internalType":"address","name":"sender","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"denyAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"denyFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"denyOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"denyTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ERC20","name":"depositAsset","type":"address"},{"internalType":"uint256","name":"depositAmount","type":"uint256"},{"internalType":"uint256","name":"minimumMint","type":"uint256"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract ERC20","name":"depositAsset","type":"address"},{"internalType":"uint256","name":"depositAmount","type":"uint256"},{"internalType":"uint256","name":"minimumMint","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bytes","name":"bridgeWildCard","type":"bytes"},{"internalType":"contract ERC20","name":"feeToken","type":"address"},{"internalType":"uint256","name":"maxFee","type":"uint256"}],"name":"depositAndBridge","outputs":[{"internalType":"uint256","name":"sharesBridged","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract ERC20","name":"depositAsset","type":"address"},{"internalType":"uint256","name":"depositAmount","type":"uint256"},{"internalType":"uint256","name":"minimumMint","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bytes","name":"bridgeWildCard","type":"bytes"},{"internalType":"contract ERC20","name":"feeToken","type":"address"},{"internalType":"uint256","name":"maxFee","type":"uint256"}],"name":"depositAndBridgeWithPermit","outputs":[{"internalType":"uint256","name":"sharesBridged","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"depositNonce","outputs":[{"internalType":"uint96","name":"","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ERC20","name":"depositAsset","type":"address"},{"internalType":"uint256","name":"depositAmount","type":"uint256"},{"internalType":"uint256","name":"minimumMint","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"depositWithPermit","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"endpoint","outputs":[{"internalType":"contract ILayerZeroEndpointV2","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"fromDenyList","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"_srcEid","type":"uint32"}],"name":"getAmountCanBeReceived","outputs":[{"internalType":"uint256","name":"inboundAmountInFlight","type":"uint256"},{"internalType":"uint256","name":"amountCanBeReceived","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"_dstEid","type":"uint32"}],"name":"getAmountCanBeSent","outputs":[{"internalType":"uint256","name":"outboundAmountInFlight","type":"uint256"},{"internalType":"uint256","name":"amountCanBeSent","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"","type":"uint32"}],"name":"idToChains","outputs":[{"internalType":"bool","name":"allowMessagesFrom","type":"bool"},{"internalType":"bool","name":"allowMessagesTo","type":"bool"},{"internalType":"uint128","name":"messageGasLimit","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"srcEid","type":"uint32"}],"name":"inboundRateLimits","outputs":[{"internalType":"uint256","name":"amountInFlight","type":"uint256"},{"internalType":"uint256","name":"lastUpdated","type":"uint256"},{"internalType":"uint256","name":"limit","type":"uint256"},{"internalType":"uint256","name":"window","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"srcEid","type":"uint32"},{"internalType":"bytes32","name":"sender","type":"bytes32"},{"internalType":"uint64","name":"nonce","type":"uint64"}],"internalType":"struct Origin","name":"_origin","type":"tuple"},{"internalType":"bytes32","name":"_guid","type":"bytes32"},{"internalType":"bytes","name":"_message","type":"bytes"},{"internalType":"address","name":"_executor","type":"address"},{"internalType":"bytes","name":"_extraData","type":"bytes"}],"name":"lzReceive","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"nativeWrapper","outputs":[{"internalType":"contract WETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"","type":"uint32"},{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"nextNonce","outputs":[{"internalType":"uint64","name":"nonce","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"oAppVersion","outputs":[{"internalType":"uint64","name":"senderVersion","type":"uint64"},{"internalType":"uint64","name":"receiverVersion","type":"uint64"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"operatorDenyList","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"dstEid","type":"uint32"}],"name":"outboundRateLimits","outputs":[{"internalType":"uint256","name":"amountInFlight","type":"uint256"},{"internalType":"uint256","name":"lastUpdated","type":"uint256"},{"internalType":"uint256","name":"limit","type":"uint256"},{"internalType":"uint256","name":"window","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"eid","type":"uint32"}],"name":"peers","outputs":[{"internalType":"bytes32","name":"peer","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint96","name":"shareAmount","type":"uint96"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bytes","name":"bridgeWildCard","type":"bytes"},{"internalType":"contract ERC20","name":"feeToken","type":"address"}],"name":"previewFee","outputs":[{"internalType":"uint256","name":"fee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"publicDepositHistory","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"depositAsset","type":"address"},{"internalType":"uint256","name":"depositAmount","type":"uint256"},{"internalType":"uint256","name":"shareAmount","type":"uint256"},{"internalType":"uint256","name":"depositTimestamp","type":"uint256"},{"internalType":"uint256","name":"shareLockUpPeriodAtTimeOfDeposit","type":"uint256"}],"name":"refundDeposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"chainId","type":"uint32"}],"name":"removeChain","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract Authority","name":"newAuthority","type":"address"}],"name":"setAuthority","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"chainId","type":"uint32"},{"internalType":"uint128","name":"messageGasLimit","type":"uint128"}],"name":"setChainGasLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_delegate","type":"address"}],"name":"setDelegate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"peerEid","type":"uint32"},{"internalType":"uint256","name":"limit","type":"uint256"},{"internalType":"uint256","name":"window","type":"uint256"}],"internalType":"struct PairwiseRateLimiter.RateLimitConfig[]","name":"_rateLimitConfigs","type":"tuple[]"}],"name":"setInboundRateLimits","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"peerEid","type":"uint32"},{"internalType":"uint256","name":"limit","type":"uint256"},{"internalType":"uint256","name":"window","type":"uint256"}],"internalType":"struct PairwiseRateLimiter.RateLimitConfig[]","name":"_rateLimitConfigs","type":"tuple[]"}],"name":"setOutboundRateLimits","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_eid","type":"uint32"},{"internalType":"bytes32","name":"_peer","type":"bytes32"}],"name":"setPeer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"_shareLockPeriod","type":"uint64"}],"name":"setShareLockPeriod","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"shareLockPeriod","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"shareUnlockTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"chainId","type":"uint32"}],"name":"stopMessagesFromChain","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"chainId","type":"uint32"}],"name":"stopMessagesToChain","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"toDenyList","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ERC20","name":"asset","type":"address"},{"internalType":"bool","name":"allowDeposits","type":"bool"},{"internalType":"bool","name":"allowWithdraws","type":"bool"},{"internalType":"uint16","name":"sharePremium","type":"uint16"}],"name":"updateAssetData","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"vault","outputs":[{"internalType":"contract BoringVault","name":"","type":"address"}],"stateMutability":"view","type":"function"}]Contract Creation Code
610140604052600160025534801562000016575f80fd5b506040516200547138038062005471833981016040819052620000399162000237565b5f80546001600160a01b0389166001600160a01b0319918216811783556001805490921690915560405185928592849284928d928d928d928d9286928692869286928692919033907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908490a36040516001600160a01b0382169033907fa3396fd7f6e0a21b50e5089d2da70d5ac0a3bbbd1f617a93f134b76389980198905f90a350506001600160a01b03831660808190526040805163313ce56760e01b8152905163313ce567916004808201926020929091908290030181865afa15801562000126573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906200014c9190620002c7565b6200015990600a620003ff565b60c0526001600160a01b0391821660a052811660e05288811661010052871695506200019e94505050505057604051632d618d8160e21b815260040160405180910390fd5b6101005160405163ca5eb5e160e01b81526001600160a01b0383811660048301529091169063ca5eb5e1906024015f604051808303815f87803b158015620001e4575f80fd5b505af1158015620001f7573d5f803e3d5ffd5b5050506001600160a01b0390951661012052506200040f9950505050505050505050565b80516001600160a01b038116811462000232575f80fd5b919050565b5f805f805f805f60e0888a0312156200024e575f80fd5b62000259886200021b565b965062000269602089016200021b565b955062000279604089016200021b565b945062000289606089016200021b565b935062000299608089016200021b565b9250620002a960a089016200021b565b9150620002b960c089016200021b565b905092959891949750929550565b5f60208284031215620002d8575f80fd5b815160ff81168114620002e9575f80fd5b9392505050565b634e487b7160e01b5f52601160045260245ffd5b600181815b808511156200034457815f1904821115620003285762000328620002f0565b808516156200033657918102915b93841c939080029062000309565b509250929050565b5f826200035c57506001620003f9565b816200036a57505f620003f9565b81600181146200038357600281146200038e57620003ae565b6001915050620003f9565b60ff841115620003a257620003a2620002f0565b50506001821b620003f9565b5060208310610133831016604e8410600b8410161715620003d3575081810a620003f9565b620003df838362000304565b805f1904821115620003f557620003f5620002f0565b0290505b92915050565b5f620002e960ff8416836200034c565b60805160a05160c05160e0516101005161012051614f80620004f15f395f81816135cb0152613af601525f818161081f015281816110230152818161274801528181613d8101528181613ed70152818161411401526141cb01525f818161040a01528181610e3901528181610eb601528181610f040152611c7401525f81816119570152612f4601525f818161072d015281816118e80152612f6801525f8181610ca601528181610eda015281816119b501528181611cae01528181612cce0152818161304d01528181613388015281816134280152613c4e0152614f805ff3fe60806040526004361061039d575f3560e01c80637a9e5e4b116101de578063bf7e214f11610108578063de35f5cb1161009d578063f2fde38b1161006d578063f2fde38b14610c57578063f51b1aca14610c76578063fbfa77cf14610c95578063ff7bd03d14610cc8575f80fd5b8063de35f5cb14610bb4578063e83931af14610beb578063e96e38e214610c0a578063f07f287d14610c29575f80fd5b8063cab716e8116100d8578063cab716e814610af4578063d182221614610b07578063d555f36814610b76578063d7424e3314610b95575f80fd5b8063bf7e214f14610a78578063c272198d14610a97578063c29d2f1014610ab6578063ca5eb5e114610ad5575f80fd5b80639d5744201161017e578063b187bd261161014e578063b187bd26146109fc578063b5ba618214610a1c578063b92d0eff14610a3b578063bb0b6a5314610a4d575f80fd5b80639d574420146109795780639fdb11b614610998578063a924bf61146109be578063abd626b0146109dd575f80fd5b80638da5cb5b116101b95780638da5cb5b146108fe5780638dfd8ba11461091c57806394f512891461093b5780639a94d3d01461094e575f80fd5b80637a9e5e4b146108945780637d25a05e146108b35780638456cb59146108ea575f80fd5b80633400288b116102ca57806346b563f41161025f57806355b56c0c1161022f57806355b56c0c146107ce5780635e280f111461080e5780635f45bac814610841578063703d376814610860575f80fd5b806346b563f4146106fd5780634fb3ccc51461071c57806351c32a881461074f57806355a2d64d146107af575f80fd5b80633e64ce991161029a5780633e64ce99146106465780633f4ba83a1461066557806341fee44a1461067957806345ad6063146106de575f80fd5b80633400288b146105ca57806334dafd6b146105e95780633b575407146106085780633d935d9e14610627575f80fd5b806317442b70116103405780631ba9a458116103105780631ba9a4581461053f578063202eac571461055e57806326a64b401461057d5780632c524c42146105ab575f80fd5b806317442b70146104b65780631899ea81146104d657806318aed921146105015780631b62636c14610520575f80fd5b80630efe6a8b1161037b5780630efe6a8b1461044457806312056e2d1461046557806313137d65146104845780631568fc5814610497575f80fd5b806304ded84a146103a157806305921740146103e45780630b48a8b8146103f9575b5f80fd5b3480156103ac575f80fd5b506103cf6103bb366004614311565b60086020525f908152604090205460ff1681565b60405190151581526020015b60405180910390f35b6103f76103f2366004614386565b610ce7565b005b348015610404575f80fd5b5061042c7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016103db565b610457610452366004614403565b610d8d565b6040519081526020016103db565b348015610470575f80fd5b506103f761047f366004614449565b610f96565b6103f761049236600461447a565b611021565b3480156104a2575f80fd5b506103f76104b136600461453b565b6110dc565b3480156104c1575f80fd5b506040805160018082526020820152016103db565b3480156104e1575f80fd5b506104576104f0366004614311565b60066020525f908152604090205481565b34801561050c575f80fd5b506103f761051b366004614311565b6111b1565b34801561052b575f80fd5b506103f761053a366004614311565b6112b9565b34801561054a575f80fd5b506103f7610559366004614311565b611335565b348015610569575f80fd5b506103f761057836600461456c565b6113ae565b348015610588575f80fd5b506103cf610597366004614311565b60076020525f908152604090205460ff1681565b3480156105b6575f80fd5b506103f76105c5366004614311565b611455565b3480156105d5575f80fd5b506103f76105e43660046145a1565b6114d1565b3480156105f4575f80fd5b506103f76106033660046145d6565b611510565b348015610613575f80fd5b506103f7610622366004614311565b611664565b348015610632575f80fd5b5061045761064136600461464d565b6116e0565b348015610651575f80fd5b506104576106603660046146ad565b6117de565b348015610670575f80fd5b506103f7611a6b565b348015610684575f80fd5b506106bd610693366004614311565b60036020525f908152604090205460ff8082169161010081049091169062010000900461ffff1683565b604080519315158452911515602084015261ffff16908201526060016103db565b3480156106e9575f80fd5b506103f76106f83660046146f4565b611ad3565b348015610708575f80fd5b506103f761071736600461470d565b611b5c565b348015610727575f80fd5b5061042c7f000000000000000000000000000000000000000000000000000000000000000081565b34801561075a575f80fd5b5061078f6107693660046146f4565b600b6020525f908152604090208054600182015460028301546003909301549192909184565b6040805194855260208501939093529183015260608201526080016103db565b3480156107ba575f80fd5b506103f76107c93660046146f4565b611d66565b3480156107d9575f80fd5b5061078f6107e83660046146f4565b600c6020525f908152604090208054600182015460028301546003909301549192909184565b348015610819575f80fd5b5061042c7f000000000000000000000000000000000000000000000000000000000000000081565b34801561084c575f80fd5b506103f761085b366004614311565b611e0c565b34801561086b575f80fd5b5061087f61087a3660046146f4565b611e85565b604080519283526020830191909152016103db565b34801561089f575f80fd5b506103f76108ae366004614311565b611ee5565b3480156108be575f80fd5b506108d26108cd3660046145a1565b611fc9565b6040516001600160401b0390911681526020016103db565b3480156108f5575f80fd5b506103f7611fd1565b348015610909575f80fd5b505f5461042c906001600160a01b031681565b348015610927575f80fd5b506103f761093636600461476d565b61203f565b6104576109493660046147c1565b612158565b348015610959575f80fd5b50610457610968366004614885565b60056020525f908152604090205481565b348015610984575f80fd5b506104576109933660046146ad565b612291565b3480156109a3575f80fd5b506004546108d290600160601b90046001600160401b031681565b3480156109c9575f80fd5b506103f76109d8366004614311565b612356565b3480156109e8575f80fd5b506103f76109f736600461489c565b6123cf565b348015610a07575f80fd5b506004546103cf90600160a01b900460ff1681565b348015610a27575f80fd5b506103f7610a363660046148e4565b6124a4565b348015610a46575f80fd5b503061042c565b348015610a58575f80fd5b50610457610a673660046146f4565b600a6020525f908152604090205481565b348015610a83575f80fd5b5060015461042c906001600160a01b031681565b348015610aa2575f80fd5b5061087f610ab13660046146f4565b6125a1565b348015610ac1575f80fd5b506103f7610ad0366004614311565b6125f7565b348015610ae0575f80fd5b506103f7610aef366004614311565b6126f8565b610457610b02366004614926565b6127a2565b348015610b12575f80fd5b50610b50610b213660046146f4565b600d6020525f908152604090205460ff808216916101008104909116906201000090046001600160801b031683565b60408051931515845291151560208401526001600160801b0316908201526060016103db565b348015610b81575f80fd5b506103f7610b903660046146f4565b6128c9565b348015610ba0575f80fd5b50610457610baf3660046149b8565b612949565b348015610bbf575f80fd5b50600454610bd3906001600160601b031681565b6040516001600160601b0390911681526020016103db565b348015610bf6575f80fd5b506103f7610c05366004614311565b612994565b348015610c15575f80fd5b506103f7610c24366004614a2d565b612a20565b348015610c34575f80fd5b506103cf610c43366004614311565b60096020525f908152604090205460ff1681565b348015610c62575f80fd5b506103f7610c71366004614311565b612aab565b348015610c81575f80fd5b506103f7610c90366004614a2d565b612b26565b348015610ca0575f80fd5b5061042c7f000000000000000000000000000000000000000000000000000000000000000081565b348015610cd3575f80fd5b506103cf610ce2366004614a9b565b612bb1565b610cfc335f356001600160e01b031916612be5565b610d215760405162461bcd60e51b8152600401610d1890614ab5565b60405180910390fd5b600254600114610d435760405162461bcd60e51b8152600401610d1890614adb565b60028055600454600160a01b900460ff1615610d725760405163e0f9e71d60e01b815260040160405180910390fd5b610d80868686868686612c8b565b5050600160025550505050565b5f610da3335f356001600160e01b031916612be5565b610dbf5760405162461bcd60e51b8152600401610d1890614ab5565b600254600114610de15760405162461bcd60e51b8152600401610d1890614adb565b600280555f610def85612dc5565b90505f73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03871601610f2b57345f03610e375760405163259be69560e11b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004015f604051808303818588803b158015610e90575f80fd5b505af1158015610ea2573d5f803e3d5ffd5b50349850610f019350506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691507f0000000000000000000000000000000000000000000000000000000000000000905087612e80565b507f0000000000000000000000000000000000000000000000000000000000000000945030610f4d565b3415610f4a57604051631cf02cf960e21b815260040160405180910390fd5b50335b610f5b868686843387612f02565b9250610f88338787866004600c9054906101000a90046001600160401b03166001600160401b03166130c1565b505060016002559392505050565b610fab335f356001600160e01b031916612be5565b610fc75760405162461bcd60e51b8152600401610d1890614ab5565b6203f480816001600160401b03161115610ff457604051631fac010160e21b815260040160405180910390fd5b600480546001600160401b03909216600160601b0267ffffffffffffffff60601b19909216919091179055565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316331461106c576040516391ac5e4f60e01b8152336004820152602401610d18565b6020870180359061108690611081908a6146f4565b6131f0565b146110c45761109860208801886146f4565b60405163309afaf360e21b815263ffffffff909116600482015260208801356024820152604401610d18565b6110d38787878787878761322b565b50505050505050565b6110f1335f356001600160e01b031916612be5565b61110d5760405162461bcd60e51b8152600401610d1890614ab5565b806001600160801b03165f036111365760405163c80ed59560e01b815260040160405180910390fd5b63ffffffff82165f818152600d6020908152604091829020805462010000600160901b031916620100006001600160801b038716908102919091178255835194855291840191909152917f0aa48359f83e8464fda3f4ea4bd3f2d6af01e90b46ab9464aa7d538e1772947a91015b60405180910390a1505050565b6111c6335f356001600160e01b031916612be5565b6111e25760405162461bcd60e51b8152600401610d1890614ab5565b6001600160a01b0381165f8181526007602090815260408083208054600160ff1991821681179092556008845282852080548216831790556009909352818420805490931617909155517fd658022b1a3aaf6ad3b3c615253712807f21a8f7bc3e4996e10618175d4afb2b9190a26040516001600160a01b038216907f79fc685a7dbabb75a67df5e69a90602cef1f19bc465b060eab1ac56685e04a13905f90a26040516001600160a01b038216907f3afb02134e37f7205acf470adc2fc4ebb70614b1599a602d069790915380e2aa905f90a250565b6112ce335f356001600160e01b031916612be5565b6112ea5760405162461bcd60e51b8152600401610d1890614ab5565b6001600160a01b0381165f81815260096020526040808220805460ff19166001179055517f3afb02134e37f7205acf470adc2fc4ebb70614b1599a602d069790915380e2aa9190a250565b61134a335f356001600160e01b031916612be5565b6113665760405162461bcd60e51b8152600401610d1890614ab5565b6001600160a01b0381165f81815260096020526040808220805460ff19169055517f77cb944c14da76928795279d1519ce9150085a06e0a53c61d5a86fc4e0fd57c69190a250565b6113c3335f356001600160e01b031916612be5565b6113df5760405162461bcd60e51b8152600401610d1890614ab5565b63ffffffff82165f908152600d60205260409020805460ff19166001178155611411836001600160a01b03841661331e565b6040805163ffffffff851681526001600160a01b03841660208201527fe925de263dcdbdc20307c9ab92758ed8cc0edf3d173dad4a3aa54c070f27a54391016111a4565b61146a335f356001600160e01b031916612be5565b6114865760405162461bcd60e51b8152600401610d1890614ab5565b6001600160a01b0381165f81815260076020526040808220805460ff19166001179055517fd658022b1a3aaf6ad3b3c615253712807f21a8f7bc3e4996e10618175d4afb2b9190a250565b6114e6335f356001600160e01b031916612be5565b6115025760405162461bcd60e51b8152600401610d1890614ab5565b61150c828261331e565b5050565b611525335f356001600160e01b031916612be5565b6115415760405162461bcd60e51b8152600401610d1890614ab5565b82801561155557506001600160801b038116155b156115735760405163c80ed59560e01b815260040160405180910390fd5b60408051606081018252851515815284151560208083019182526001600160801b0385811684860190815263ffffffff8b165f908152600d90935294909120925183549251945161ffff1990931690151561ff00191617610100941515949094029390931762010000600160901b031916620100009190931602919091179055611606856001600160a01b03841661331e565b6040805163ffffffff871681528515156020820152841515818301526001600160a01b038416606082015290517f5dbe727bffd24a6d61a5aeef919510389c66c0deeaa82634862cf4f098961fb89181900360800190a15050505050565b611679335f356001600160e01b031916612be5565b6116955760405162461bcd60e51b8152600401610d1890614ab5565b6001600160a01b0381165f81815260086020526040808220805460ff19166001179055517f79fc685a7dbabb75a67df5e69a90602cef1f19bc465b060eab1ac56685e04a139190a250565b5f6116f6335f356001600160e01b031916612be5565b6117125760405162461bcd60e51b8152600401610d1890614ab5565b6002546001146117345760405162461bcd60e51b8152600401610d1890614adb565b600280558773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03821601611777576040516316df5df960e31b815260040160405180910390fd5b5f6117818a612dc5565b90506117918a8a8989898961336b565b61179f8a8a8a333386612f02565b92506117cc338b8b866004600c9054906101000a90046001600160401b03166001600160401b03166130c1565b50506001600255979650505050505050565b5f6117f4335f356001600160e01b031916612be5565b6118105760405162461bcd60e51b8152600401610d1890614ab5565b600454600160a01b900460ff161561183b5760405163e0f9e71d60e01b815260040160405180910390fd5b6001600160a01b0385165f908152600360209081526040918290208251606081018452905460ff80821615158352610100820416151592820183905262010000900461ffff16928101929092526118a55760405163645fd19f60e11b815260040160405180910390fd5b845f036118c557604051630ea3153160e21b815260040160405180910390fd5b604051634104b9ed60e11b81526001600160a01b03878116600483015261197b917f00000000000000000000000000000000000000000000000000000000000000009091169063820973da90602401602060405180830381865afa15801561192f573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119539190614aff565b86907f00000000000000000000000000000000000000000000000000000000000000006134c3565b91508382101561199e576040516302620f6160e61b815260040160405180910390fd5b6040516318457e6160e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906318457e61906119f29086908a90879033908c90600401614b16565b5f604051808303815f87803b158015611a09575f80fd5b505af1158015611a1b573d5f803e3d5ffd5b50505050856001600160a01b03167fdcc60b41ff1c604459e6aa4a7299817416b19fc586a392f111646e26597c4af986604051611a5a91815260200190565b60405180910390a250949350505050565b611a80335f356001600160e01b031916612be5565b611a9c5760405162461bcd60e51b8152600401610d1890614ab5565b6004805460ff60a01b191690556040517fa45f47fdea8a1efdd9029a5691c7f759c32b7c698632b563573e155625d16933905f90a1565b611ae8335f356001600160e01b031916612be5565b611b045760405162461bcd60e51b8152600401610d1890614ab5565b63ffffffff81165f818152600d6020908152604091829020805461ff0019168155915192835290917fc45af64a13a09ef916a1114c59589294ec9c3095f2bfbbb093a7a96656858ded91015b60405180910390a15050565b611b71335f356001600160e01b031916612be5565b611b8d5760405162461bcd60e51b8152600401610d1890614ab5565b80611b988342614b5d565b10611bb657604051634c1eef1760e11b815260040160405180910390fd5b604080516001600160a01b038089166020830152871691810191909152606081018590526080810184905260a0810183905260c081018290525f9060e00160408051601f1981840301815291815281516020928301205f8b815260059093529120549091508114611c3a5760405163fa174ecb60e01b815260040160405180910390fd5b5f888152600560205260408120556001600160a01b03861673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14611c725785611c94565b7f00000000000000000000000000000000000000000000000000000000000000005b6040516318457e6160e01b81529096506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906318457e6190611ceb908a908a908a9083908b90600401614b16565b5f604051808303815f87803b158015611d02575f80fd5b505af1158015611d14573d5f803e3d5ffd5b50505050866001600160a01b0316887faf98ea774275cadfa3e477a7b52cba03e01197445a76bd5d0d561608708c362483604051611d5491815260200190565b60405180910390a35050505050505050565b611d7b335f356001600160e01b031916612be5565b611d975760405162461bcd60e51b8152600401610d1890614ab5565b63ffffffff81165f908152600d60205260408120805471ffffffffffffffffffffffffffffffffffff19169055611dcf90829061331e565b60405163ffffffff821681527f11a9d1a77f76361ed131c19b1dc5758504c51dbde2e49fc973a0ef9577ad13d5906020015b60405180910390a150565b611e21335f356001600160e01b031916612be5565b611e3d5760405162461bcd60e51b8152600401610d1890614ab5565b6001600160a01b0381165f81815260086020526040808220805460ff19169055517f039bcf51833310242b8b7c6aa0fbabf1bf2b5e5270807ee020f1920ef200666b9190a250565b63ffffffff81165f908152600c6020908152604080832081516080810183528154808252600183015494820185905260028301549382018490526003909201546060820181905285949193611edb9392916134de565b9250925050915091565b5f546001600160a01b0316331480611f76575060015460405163b700961360e01b81526001600160a01b039091169063b700961390611f3790339030906001600160e01b03195f351690600401614b70565b602060405180830381865afa158015611f52573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611f769190614b9d565b611f7e575f80fd5b600180546001600160a01b0319166001600160a01b03831690811790915560405133907fa3396fd7f6e0a21b50e5089d2da70d5ac0a3bbbd1f617a93f134b76389980198905f90a350565b5f5b92915050565b611fe6335f356001600160e01b031916612be5565b6120025760405162461bcd60e51b8152600401610d1890614ab5565b6004805460ff60a01b1916600160a01b1790556040517f9e87fac88ff661f02d44f95383c817fece4bce600a3dab7a54406878b965e752905f90a1565b612054335f356001600160e01b031916612be5565b6120705760405162461bcd60e51b8152600401610d1890614ab5565b6103e861ffff8216111561209757604051636c5cde8760e01b815260040160405180910390fd5b6040805160608082018352851515808352851515602080850182815261ffff8881168789018181526001600160a01b038e165f818152600387528b902099518a549551925161ffff1990961690151561ff00191617610100921515929092029190911763ffff0000191662010000949093169390930291909117909655865193845290830191909152938101929092527fe08301321781ac43935a2099b2c3fd42de0a0ee87a519cac00e8c9cecd26ff12910160405180910390a250505050565b5f61216e335f356001600160e01b031916612be5565b61218a5760405162461bcd60e51b8152600401610d1890614ab5565b6002546001146121ac5760405162461bcd60e51b8152600401610d1890614adb565b600280558c73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b038216016121ef576040516316df5df960e31b815260040160405180910390fd5b5f6121f98f612dc5565b90506122098f8f8e8e8e8e61336b565b6122178f8f8f333386612f02565b925050612245338f8f856004600c9054906101000a90046001600160401b03166001600160401b03166130c1565b6001600160601b0382111561226d576040516389588ab360e01b815260040160405180910390fd5b61227b828888888888612c8b565b5060016002559c9b505050505050505050505050565b5f6122a7335f356001600160e01b031916612be5565b6122c35760405162461bcd60e51b8152600401610d1890614ab5565b6002546001146122e55760405162461bcd60e51b8152600401610d1890614adb565b600280555f6122f386612dc5565b9050612303868686338786612f02565b9150856001600160a01b03167f6f9b974223f85a1ae805c33b8b519039e2435481d949db1110de151a94d587af8660405161234091815260200190565b60405180910390a2506001600255949350505050565b61236b335f356001600160e01b031916612be5565b6123875760405162461bcd60e51b8152600401610d1890614ab5565b6001600160a01b0381165f81815260076020526040808220805460ff19169055517fae893dda71e2eee548f8291f458cceae4bd22b56a79906928591e4420444c0e99190a250565b6001600160a01b0383165f9081526007602052604090205460ff168061240c57506001600160a01b0382165f9081526008602052604090205460ff165b8061242e57506001600160a01b0381165f9081526009602052604090205460ff165b1561246757604051632821264f60e01b81526001600160a01b038085166004830152808416602483015282166044820152606401610d18565b6001600160a01b0383165f9081526006602052604090205442101561249f5760405163f64059db60e01b815260040160405180910390fd5b505050565b6124b9335f356001600160e01b031916612be5565b6124d55760405162461bcd60e51b8152600401610d1890614ab5565b806001600160801b03165f036124fe5760405163c80ed59560e01b815260040160405180910390fd5b63ffffffff83165f908152600d60205260409020805461010071ffffffffffffffffffffffffffffffffff0019909116620100006001600160801b0385160217178155612554846001600160a01b03851661331e565b6040805163ffffffff861681526001600160a01b03851660208201527f34fe916485e02ec88e487b0e611e5c9bacabba9e3eaae7a900aa08be8197d419910160405180910390a150505050565b63ffffffff81165f908152600b6020908152604080832081516080810183528154808252600183015494820185905260028301549382018490526003909201546060820181905285949193611edb9392916134de565b61260c335f356001600160e01b031916612be5565b6126285760405162461bcd60e51b8152600401610d1890614ab5565b6001600160a01b0381165f818152600760209081526040808320805460ff199081169091556008835281842080548216905560099092528083208054909216909155517fae893dda71e2eee548f8291f458cceae4bd22b56a79906928591e4420444c0e99190a26040516001600160a01b038216907f039bcf51833310242b8b7c6aa0fbabf1bf2b5e5270807ee020f1920ef200666b905f90a26040516001600160a01b038216907f77cb944c14da76928795279d1519ce9150085a06e0a53c61d5a86fc4e0fd57c6905f90a250565b61270d335f356001600160e01b031916612be5565b6127295760405162461bcd60e51b8152600401610d1890614ab5565b60405163ca5eb5e160e01b81526001600160a01b0382811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063ca5eb5e1906024015f604051808303815f87803b158015612789575f80fd5b505af115801561279b573d5f803e3d5ffd5b5050505050565b5f6127b8335f356001600160e01b031916612be5565b6127d45760405162461bcd60e51b8152600401610d1890614ab5565b6002546001146127f65760405162461bcd60e51b8152600401610d1890614adb565b600280558873eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03821601612839576040516316df5df960e31b815260040160405180910390fd5b5f6128438b612dc5565b90506128538b8b8b333386612f02565b9250612880338c8c866004600c9054906101000a90046001600160401b03166001600160401b03166130c1565b6001600160601b038311156128a8576040516389588ab360e01b815260040160405180910390fd5b6128b6838989898989612c8b565b5050600160025598975050505050505050565b6128de335f356001600160e01b031916612be5565b6128fa5760405162461bcd60e51b8152600401610d1890614ab5565b63ffffffff81165f818152600d6020908152604091829020805460ff19168155915192835290917f1cb867ed6a020e020ea220d4f48bb8e36552abf9095e093e377d33933f2b31e49101611b50565b604080518082019091526001600160601b03861681526001600160a01b03851660208201525f908161297a82613559565b9050612988818787876135a0565b98975050505050505050565b6001600160a01b0381165f9081526007602052604090205460ff16156129e557604051632821264f60e01b81526001600160a01b03821660048201525f602482018190526044820152606401610d18565b6001600160a01b0381165f90815260066020526040902054421015612a1d5760405163f64059db60e01b815260040160405180910390fd5b50565b612a35335f356001600160e01b031916612be5565b612a515760405162461bcd60e51b8152600401610d1890614ab5565b61150c8282808060200260200160405190810160405280939291908181526020015f905b82821015612aa157612a9260608302860136819003810190614bec565b81526020019060010190612a75565b505050505061376f565b612ac0335f356001600160e01b031916612be5565b612adc5760405162461bcd60e51b8152600401610d1890614ab5565b5f80546001600160a01b0319166001600160a01b0383169081178255604051909133917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a350565b612b3b335f356001600160e01b031916612be5565b612b575760405162461bcd60e51b8152600401610d1890614ab5565b61150c8282808060200260200160405190810160405280939291908181526020015f905b82821015612ba757612b9860608302860136819003810190614bec565b81526020019060010190612b7b565b5050505050613861565b5f60208201803590600a908390612bc890866146f4565b63ffffffff16815260208101919091526040015f20541492915050565b6001545f906001600160a01b03168015801590612c6c575060405163b700961360e01b81526001600160a01b0382169063b700961390612c2d90879030908890600401614b70565b602060405180830381865afa158015612c48573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612c6c9190614b9d565b80612c8357505f546001600160a01b038581169116145b949350505050565b612c96335f336123cf565b6040516318457e6160e01b81525f600482018190526024820181905260448201523360648201526001600160601b03871660848201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906318457e619060a4015f604051808303815f87803b158015612d17575f80fd5b505af1158015612d29573d5f803e3d5ffd5b5050604080518082019091526001600160601b03891681526001600160a01b038816602082015291505f9050612d5e82613559565b90505f612d6e8288888888613953565b6040516001600160601b038b1681529091506001600160a01b0389169082907fe0ec62d39b054dc2fd626dbc271483735df6e6fa1ef8389754bf8ab27a75eab29060200160405180910390a3505050505050505050565b604080516060810182525f8082526020820181905291810191909152600454600160a01b900460ff1615612e0c5760405163e0f9e71d60e01b815260040160405180910390fd5b506001600160a01b0381165f908152600360209081526040918290208251606081018452905460ff8082161515808452610100830490911615159383019390935262010000900461ffff1692810192909252612e7b5760405163645fd19f60e11b815260040160405180910390fd5b919050565b5f60405163095ea7b360e01b81526001600160a01b038416600482015282602482015260205f6044835f895af13d15601f3d1160015f511416171691505080612efc5760405162461bcd60e51b815260206004820152600e60248201526d1054141493d59157d1905253115160921b6044820152606401610d18565b50505050565b5f855f03612f235760405163259be69560e11b815260040160405180910390fd5b604051634104b9ed60e11b81526001600160a01b038881166004830152612fd9917f0000000000000000000000000000000000000000000000000000000000000000917f0000000000000000000000000000000000000000000000000000000000000000169063820973da90602401602060405180830381865afa158015612fad573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612fd19190614aff565b8891906134c3565b90505f826040015161ffff1611612ff05780613013565b61301382604001516127106130059190614c2d565b829061ffff166127106134c3565b9050848110156130365760405163097b2ad560e31b815260040160405180910390fd5b604051631ceb5d1960e11b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906339d6ba329061308a9087908b908b9089908890600401614b16565b5f604051808303815f87803b1580156130a1575f80fd5b505af11580156130b3573d5f803e3d5ffd5b505050509695505050505050565b600480545f919082906130dc906001600160601b0316614c4f565b82546001600160601b039182166101009390930a8381029202191617909155905081156131805761310d8242614c74565b6001600160a01b038781165f81815260066020908152604091829020949094558051938401919091529087169082015260608101859052608081018490524260a082015260c0810183905260e00160408051601f1981840301815291815281516020928301205f84815260059093529120555b846001600160a01b0316866001600160a01b0316827fe96d7872363f475d18b2f5390caaa5eaa96b2d38e42c62afe4ac08ebd2b13c3a878742886040516131e0949392919093845260208401929092526040830152606082015260800190565b60405180910390a4505050505050565b63ffffffff81165f908152600a602052604081205480611fcb5760405163f6ff4fb760e01b815263ffffffff84166004820152602401610d18565b5f600d8161323c60208b018b6146f4565b63ffffffff16815260208082019290925260409081015f208151606081018352905460ff808216151580845261010083049091161515948301949094526201000090046001600160801b03169181019190915291506132c4576132a260208901896146f4565b6040516315b73a2960e21b815263ffffffff9091166004820152602401610d18565b5f6132d186880188614885565b90506133096132e360208b018b6146f4565b6040805180820190915260a084901c81526001600160a01b038416602082015251613ba6565b6133138882613c1b565b505050505050505050565b63ffffffff82165f818152600a6020908152604091829020849055815192835282018390527f238399d427b947898edb290f5ff0f9109849b1c3ba196a42e35f00c50a54b98b9101611b50565b60405163d505accf60e01b81523360048201526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166024830152604482018790526064820186905260ff8516608483015260a4820184905260c4820183905287169063d505accf9060e4015f604051808303815f87803b1580156133f6575f80fd5b505af1925050508015613407575060015b6134bb57604051636eb1769f60e11b81523360048201526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116602483015286919088169063dd62ed3e90604401602060405180830381865afa158015613478573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061349c9190614aff565b10156134bb576040516301b8851f60e41b815260040160405180910390fd5b505050505050565b5f825f1904841183021582026134d7575f80fd5b5091020490565b5f80806134eb8642614b5d565b90508381106134ff575f925084915061354f565b5f8461350b8388614c87565b6135159190614c9e565b90508088111561352e576135298189614b5d565b613530565b5f5b935083861115613549576135448487614b5d565b61354b565b5f5b9250505b5094509492505050565b80515f906001600160601b03101561358457604051633524486360e01b815260040160405180910390fd5b81516020909201516001600160a01b031660a09290921b171790565b5f6001600160a01b03821673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1480159061360057507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031614155b1561361e57604051637f3cd08160e11b815260040160405180910390fd5b5f61362b848601866146f4565b63ffffffff81165f908152600d60209081526040918290208251606081018452905460ff8082161515835261010082041615159282018390526201000090046001600160801b031692810192909252919250906136a35760405163420eae3760e01b815263ffffffff83166004820152602401610d18565b5f876040516020016136b791815260200190565b60405160208183030381529060405290505f6136ff83604001515f6136f860408051600360f01b602082015281516002818303018152602290910190915290565b9190613d07565b90505f61372e8584846001600160a01b038b1673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1415613d6c565b90506001600160a01b03871673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1461375e578060200151613761565b80515b9a9950505050505050505050565b5f5b8151811015613831575f600b5f84848151811061379057613790614cbd565b60200260200101515f015163ffffffff1663ffffffff1681526020019081526020015f2090506137dc8383815181106137cb576137cb614cbd565b60200260200101515f01515f613e4a565b8282815181106137ee576137ee614cbd565b602002602001015160200151816002018190555082828151811061381457613814614cbd565b602090810291909101015160400151600390910155600101613771565b507f55254e344b7fc8e2e038c1f7f20a1c7afe659c1a3bbfc4e35dd1ca9bba0ca0a081604051611e019190614cd1565b5f5b8151811015613923575f600c5f84848151811061388257613882614cbd565b60200260200101515f015163ffffffff1663ffffffff1681526020019081526020015f2090506138ce8383815181106138bd576138bd614cbd565b60200260200101515f01515f613ba6565b8282815181106138e0576138e0614cbd565b602002602001015160200151816002018190555082828151811061390657613906614cbd565b602090810291909101015160400151600390910155600101613863565b507f983af742b0b5ca79aa5c0be76cea126e1baf3139ecd04624deac13853c4bebde81604051611e019190614cd1565b5f80613961858701876146f4565b90506139958161398f896040805180820190915260a082901c81526001600160a01b03909116602082015290565b51613e4a565b63ffffffff81165f908152600d60209081526040918290208251606081018452905460ff8082161515835261010082041615159282018390526201000090046001600160801b031692810192909252613a095760405163420eae3760e01b815263ffffffff83166004820152602401610d18565b5f88604051602001613a1d91815260200190565b60405160208183030381529060405290505f613a5e83604001515f6136f860408051600360f01b602082015281516002818303018152602290910190915290565b90505f613a8d8584846001600160a01b038c1673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1415613d6c565b905073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03891601613af4578051871015613aef57805160405163f5ac3fa760e01b815263ffffffff87166004820152602481019190915260448101889052606401610d18565b613b87565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316886001600160a01b031603613b6e578681602001511115613aef57602081015160405163f5ac3fa760e01b815263ffffffff87166004820152602481019190915260448101889052606401610d18565b604051637f3cd08160e11b815260040160405180910390fd5b5f613b958685858533613ea6565b519c9b505050505050505050505050565b63ffffffff82165f908152600c6020526040812080546001820154600283015460038401549394938493613bdd93909290916134de565b9150915080841115613c0257604051636a526abb60e01b815260040160405180910390fd5b613c0c8483614c74565b83555050426001909101555050565b60408051808201825260a083901c8082526001600160a01b03808516602084018190529351631ceb5d1960e11b815292937f0000000000000000000000000000000000000000000000000000000000000000909116926339d6ba3292613c8a925f928392839291600401614b16565b5f604051808303815f87803b158015613ca1575f80fd5b505af1158015613cb3573d5f803e3d5ffd5b5050505080602001516001600160a01b0316837fb944fddc61d7fedb8b736790454ba972000703b0d21c7481d6dbf95b7c2cc2f1835f0151604051613cfa91815260200190565b60405180910390a3505050565b6060836003613d16825f613fac565b61ffff1614613d4957613d29815f613fac565b604051633a51740d60e01b815261ffff9091166004820152602401610d18565b5f613d548585614008565b9050613d6286600183614081565b9695505050505050565b604080518082019091525f80825260208201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663ddc28c586040518060a001604052808863ffffffff168152602001613dce896131f0565b8152602001878152602001868152602001851515815250306040518363ffffffff1660e01b8152600401613e03929190614d7c565b6040805180830381865afa158015613e1d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613e419190614e4c565b95945050505050565b63ffffffff82165f908152600b6020526040812080546001820154600283015460038401549394938493613e8193909290916134de565b9150915080841115613c02576040516324292aa760e01b815260040160405180910390fd5b613eae6142af565b5f613ebb845f01516140ea565b602085015190915015613ed557613ed58460200151614111565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316632637a450826040518060a001604052808b63ffffffff168152602001613f258c6131f0565b81526020018a81526020018981526020015f8960200151111515815250866040518463ffffffff1660e01b8152600401613f60929190614d7c565b60806040518083038185885af1158015613f7c573d5f803e3d5ffd5b50505050506040513d601f19601f82011682018060405250810190613fa19190614e66565b979650505050505050565b5f613fb8826002614c74565b83511015613fff5760405162461bcd60e51b8152602060048201526014602482015273746f55696e7431365f6f75744f66426f756e647360601b6044820152606401610d18565b50016002015190565b60606001600160801b0382161561405057604080516001600160801b0319608086811b8216602084015285901b1660308201520160405160208183030381529060405261407a565b6040516001600160801b0319608085901b1660208201526030016040516020818303038152906040525b9392505050565b6060836003614090825f613fac565b61ffff16146140a357613d29815f613fac565b8460016140b085516141f0565b6140bb906001614eae565b86866040516020016140d1959493929190614ec9565b6040516020818303038152906040529150509392505050565b5f81341461410d576040516304fb820960e51b8152346004820152602401610d18565b5090565b5f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e4fe1d946040518163ffffffff1660e01b8152600401602060405180830381865afa15801561416e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906141929190614f2f565b90506001600160a01b0381166141bb576040516329b99a9560e11b815260040160405180910390fd5b61150c6001600160a01b038216337f00000000000000000000000000000000000000000000000000000000000000008561421e565b5f61ffff82111561410d576040516306dfcc6560e41b81526010600482015260248101839052604401610d18565b5f6040516323b872dd60e01b81526001600160a01b03851660048201526001600160a01b038416602482015282604482015260205f6064835f8a5af13d15601f3d1160015f51141617169150508061279b5760405162461bcd60e51b81526020600482015260146024820152731514905394d1915497d19493d357d1905253115160621b6044820152606401610d18565b60405180606001604052805f80191681526020015f6001600160401b031681526020016142ed60405180604001604052805f81526020015f81525090565b905290565b6001600160a01b0381168114612a1d575f80fd5b8035612e7b816142f2565b5f60208284031215614321575f80fd5b813561407a816142f2565b80356001600160601b0381168114612e7b575f80fd5b5f8083601f840112614352575f80fd5b5081356001600160401b03811115614368575f80fd5b60208301915083602082850101111561437f575f80fd5b9250929050565b5f805f805f8060a0878903121561439b575f80fd5b6143a48761432c565b955060208701356143b4816142f2565b945060408701356001600160401b038111156143ce575f80fd5b6143da89828a01614342565b90955093505060608701356143ee816142f2565b80925050608087013590509295509295509295565b5f805f60608486031215614415575f80fd5b8335614420816142f2565b95602085013595506040909401359392505050565b6001600160401b0381168114612a1d575f80fd5b5f60208284031215614459575f80fd5b813561407a81614435565b5f60608284031215614474575f80fd5b50919050565b5f805f805f805f60e0888a031215614490575f80fd5b61449a8989614464565b96506060880135955060808801356001600160401b03808211156144bc575f80fd5b6144c88b838c01614342565b909750955060a08a013591506144dd826142f2565b90935060c089013590808211156144f2575f80fd5b506144ff8a828b01614342565b989b979a50959850939692959293505050565b803563ffffffff81168114612e7b575f80fd5b80356001600160801b0381168114612e7b575f80fd5b5f806040838503121561454c575f80fd5b61455583614512565b915061456360208401614525565b90509250929050565b5f806040838503121561457d575f80fd5b61458683614512565b91506020830135614596816142f2565b809150509250929050565b5f80604083850312156145b2575f80fd5b6145bb83614512565b946020939093013593505050565b8015158114612a1d575f80fd5b5f805f805f60a086880312156145ea575f80fd5b6145f386614512565b94506020860135614603816145c9565b93506040860135614613816145c9565b92506060860135614623816142f2565b915061463160808701614525565b90509295509295909350565b803560ff81168114612e7b575f80fd5b5f805f805f805f60e0888a031215614663575f80fd5b873561466e816142f2565b96506020880135955060408801359450606088013593506146916080890161463d565b925060a0880135915060c0880135905092959891949750929550565b5f805f80608085870312156146c0575f80fd5b84356146cb816142f2565b9350602085013592506040850135915060608501356146e9816142f2565b939692955090935050565b5f60208284031215614704575f80fd5b61407a82614512565b5f805f805f805f60e0888a031215614723575f80fd5b873596506020880135614735816142f2565b95506040880135614745816142f2565b969995985095966060810135965060808101359560a0820135955060c0909101359350915050565b5f805f8060808587031215614780575f80fd5b843561478b816142f2565b9350602085013561479b816145c9565b925060408501356147ab816145c9565b9150606085013561ffff811681146146e9575f80fd5b5f805f805f805f805f805f806101608d8f0312156147dd575f80fd5b6147e78d356142f2565b8c359b5060208d01359a5060408d0135995060608d0135985061480c60808e0161463d565b975060a08d0135965060c08d0135955061482960e08e01356142f2565b60e08d013594506001600160401b036101008e01351115614848575f80fd5b6148598e6101008f01358f01614342565b909450925061486b6101208e01614306565b91506101408d013590509295989b509295989b509295989b565b5f60208284031215614895575f80fd5b5035919050565b5f805f606084860312156148ae575f80fd5b83356148b9816142f2565b925060208401356148c9816142f2565b915060408401356148d9816142f2565b809150509250925092565b5f805f606084860312156148f6575f80fd5b6148ff84614512565b9250602084013561490f816142f2565b915061491d60408501614525565b90509250925092565b5f805f805f805f8060e0898b03121561493d575f80fd5b8835614948816142f2565b975060208901359650604089013595506060890135614966816142f2565b945060808901356001600160401b03811115614980575f80fd5b61498c8b828c01614342565b90955093505060a08901356149a0816142f2565b8092505060c089013590509295985092959890939650565b5f805f805f608086880312156149cc575f80fd5b6149d58661432c565b945060208601356149e5816142f2565b935060408601356001600160401b038111156149ff575f80fd5b614a0b88828901614342565b9094509250506060860135614a1f816142f2565b809150509295509295909350565b5f8060208385031215614a3e575f80fd5b82356001600160401b0380821115614a54575f80fd5b818501915085601f830112614a67575f80fd5b813581811115614a75575f80fd5b866020606083028501011115614a89575f80fd5b60209290920196919550909350505050565b5f60608284031215614aab575f80fd5b61407a8383614464565b6020808252600c908201526b15539055551213d49256915160a21b604082015260600190565b6020808252600a90820152695245454e5452414e435960b01b604082015260600190565b5f60208284031215614b0f575f80fd5b5051919050565b6001600160a01b039586168152938516602085015260408401929092529092166060820152608081019190915260a00190565b634e487b7160e01b5f52601160045260245ffd5b81810381811115611fcb57611fcb614b49565b6001600160a01b0393841681529190921660208201526001600160e01b0319909116604082015260600190565b5f60208284031215614bad575f80fd5b815161407a816145c9565b604051606081016001600160401b0381118282101715614be657634e487b7160e01b5f52604160045260245ffd5b60405290565b5f60608284031215614bfc575f80fd5b614c04614bb8565b614c0d83614512565b815260208301356020820152604083013560408201528091505092915050565b61ffff828116828216039080821115614c4857614c48614b49565b5092915050565b5f6001600160601b03808316818103614c6a57614c6a614b49565b6001019392505050565b80820180821115611fcb57611fcb614b49565b8082028115828204841417611fcb57611fcb614b49565b5f82614cb857634e487b7160e01b5f52601260045260245ffd5b500490565b634e487b7160e01b5f52603260045260245ffd5b602080825282518282018190525f919060409081850190868401855b82811015614d22578151805163ffffffff16855286810151878601528501518585015260609093019290850190600101614ced565b5091979650505050505050565b5f5b83811015614d49578181015183820152602001614d31565b50505f910152565b5f8151808452614d68816020860160208601614d2f565b601f01601f19169290920160200192915050565b6040815263ffffffff8351166040820152602083015160608201525f604084015160a06080840152614db160e0840182614d51565b90506060850151603f198483030160a0850152614dce8282614d51565b60809690960151151560c08501525050506001600160a01b039190911660209091015290565b5f60408284031215614e04575f80fd5b604051604081018181106001600160401b0382111715614e3257634e487b7160e01b5f52604160045260245ffd5b604052825181526020928301519281019290925250919050565b5f60408284031215614e5c575f80fd5b61407a8383614df4565b5f60808284031215614e76575f80fd5b614e7e614bb8565b825181526020830151614e9081614435565b6020820152614ea28460408501614df4565b60408201529392505050565b61ffff818116838216019080821115614c4857614c48614b49565b5f8651614eda818460208b01614d2f565b6001600160f81b031960f888811b82169285019283526001600160f01b031960f089901b16600184015286901b1660038201528351614f20816004840160208801614d2f565b01600401979650505050505050565b5f60208284031215614f3f575f80fd5b815161407a816142f256fea26469706673582212200216655861d29097518938c81858a539139f28246f820f0e447622517a4ed44164736f6c63430008150033000000000000000000000000f8553c8552f906c19286f21711721e206ee4909e00000000000000000000000008c6f91e2b681faf5e17227f2a44c307b3c1364c000000000000000000000000c315d6e14ddcdc7407784e2caf815d131bc1d3e700000000000000000000000053000000000000000000000000000000000000040000000000000000000000001a44076050125825900e736c501f859c50fe728c000000000000000000000000f8553c8552f906c19286f21711721e206ee4909e0000000000000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x60806040526004361061039d575f3560e01c80637a9e5e4b116101de578063bf7e214f11610108578063de35f5cb1161009d578063f2fde38b1161006d578063f2fde38b14610c57578063f51b1aca14610c76578063fbfa77cf14610c95578063ff7bd03d14610cc8575f80fd5b8063de35f5cb14610bb4578063e83931af14610beb578063e96e38e214610c0a578063f07f287d14610c29575f80fd5b8063cab716e8116100d8578063cab716e814610af4578063d182221614610b07578063d555f36814610b76578063d7424e3314610b95575f80fd5b8063bf7e214f14610a78578063c272198d14610a97578063c29d2f1014610ab6578063ca5eb5e114610ad5575f80fd5b80639d5744201161017e578063b187bd261161014e578063b187bd26146109fc578063b5ba618214610a1c578063b92d0eff14610a3b578063bb0b6a5314610a4d575f80fd5b80639d574420146109795780639fdb11b614610998578063a924bf61146109be578063abd626b0146109dd575f80fd5b80638da5cb5b116101b95780638da5cb5b146108fe5780638dfd8ba11461091c57806394f512891461093b5780639a94d3d01461094e575f80fd5b80637a9e5e4b146108945780637d25a05e146108b35780638456cb59146108ea575f80fd5b80633400288b116102ca57806346b563f41161025f57806355b56c0c1161022f57806355b56c0c146107ce5780635e280f111461080e5780635f45bac814610841578063703d376814610860575f80fd5b806346b563f4146106fd5780634fb3ccc51461071c57806351c32a881461074f57806355a2d64d146107af575f80fd5b80633e64ce991161029a5780633e64ce99146106465780633f4ba83a1461066557806341fee44a1461067957806345ad6063146106de575f80fd5b80633400288b146105ca57806334dafd6b146105e95780633b575407146106085780633d935d9e14610627575f80fd5b806317442b70116103405780631ba9a458116103105780631ba9a4581461053f578063202eac571461055e57806326a64b401461057d5780632c524c42146105ab575f80fd5b806317442b70146104b65780631899ea81146104d657806318aed921146105015780631b62636c14610520575f80fd5b80630efe6a8b1161037b5780630efe6a8b1461044457806312056e2d1461046557806313137d65146104845780631568fc5814610497575f80fd5b806304ded84a146103a157806305921740146103e45780630b48a8b8146103f9575b5f80fd5b3480156103ac575f80fd5b506103cf6103bb366004614311565b60086020525f908152604090205460ff1681565b60405190151581526020015b60405180910390f35b6103f76103f2366004614386565b610ce7565b005b348015610404575f80fd5b5061042c7f000000000000000000000000530000000000000000000000000000000000000481565b6040516001600160a01b0390911681526020016103db565b610457610452366004614403565b610d8d565b6040519081526020016103db565b348015610470575f80fd5b506103f761047f366004614449565b610f96565b6103f761049236600461447a565b611021565b3480156104a2575f80fd5b506103f76104b136600461453b565b6110dc565b3480156104c1575f80fd5b506040805160018082526020820152016103db565b3480156104e1575f80fd5b506104576104f0366004614311565b60066020525f908152604090205481565b34801561050c575f80fd5b506103f761051b366004614311565b6111b1565b34801561052b575f80fd5b506103f761053a366004614311565b6112b9565b34801561054a575f80fd5b506103f7610559366004614311565b611335565b348015610569575f80fd5b506103f761057836600461456c565b6113ae565b348015610588575f80fd5b506103cf610597366004614311565b60076020525f908152604090205460ff1681565b3480156105b6575f80fd5b506103f76105c5366004614311565b611455565b3480156105d5575f80fd5b506103f76105e43660046145a1565b6114d1565b3480156105f4575f80fd5b506103f76106033660046145d6565b611510565b348015610613575f80fd5b506103f7610622366004614311565b611664565b348015610632575f80fd5b5061045761064136600461464d565b6116e0565b348015610651575f80fd5b506104576106603660046146ad565b6117de565b348015610670575f80fd5b506103f7611a6b565b348015610684575f80fd5b506106bd610693366004614311565b60036020525f908152604090205460ff8082169161010081049091169062010000900461ffff1683565b604080519315158452911515602084015261ffff16908201526060016103db565b3480156106e9575f80fd5b506103f76106f83660046146f4565b611ad3565b348015610708575f80fd5b506103f761071736600461470d565b611b5c565b348015610727575f80fd5b5061042c7f000000000000000000000000c315d6e14ddcdc7407784e2caf815d131bc1d3e781565b34801561075a575f80fd5b5061078f6107693660046146f4565b600b6020525f908152604090208054600182015460028301546003909301549192909184565b6040805194855260208501939093529183015260608201526080016103db565b3480156107ba575f80fd5b506103f76107c93660046146f4565b611d66565b3480156107d9575f80fd5b5061078f6107e83660046146f4565b600c6020525f908152604090208054600182015460028301546003909301549192909184565b348015610819575f80fd5b5061042c7f0000000000000000000000001a44076050125825900e736c501f859c50fe728c81565b34801561084c575f80fd5b506103f761085b366004614311565b611e0c565b34801561086b575f80fd5b5061087f61087a3660046146f4565b611e85565b604080519283526020830191909152016103db565b34801561089f575f80fd5b506103f76108ae366004614311565b611ee5565b3480156108be575f80fd5b506108d26108cd3660046145a1565b611fc9565b6040516001600160401b0390911681526020016103db565b3480156108f5575f80fd5b506103f7611fd1565b348015610909575f80fd5b505f5461042c906001600160a01b031681565b348015610927575f80fd5b506103f761093636600461476d565b61203f565b6104576109493660046147c1565b612158565b348015610959575f80fd5b50610457610968366004614885565b60056020525f908152604090205481565b348015610984575f80fd5b506104576109933660046146ad565b612291565b3480156109a3575f80fd5b506004546108d290600160601b90046001600160401b031681565b3480156109c9575f80fd5b506103f76109d8366004614311565b612356565b3480156109e8575f80fd5b506103f76109f736600461489c565b6123cf565b348015610a07575f80fd5b506004546103cf90600160a01b900460ff1681565b348015610a27575f80fd5b506103f7610a363660046148e4565b6124a4565b348015610a46575f80fd5b503061042c565b348015610a58575f80fd5b50610457610a673660046146f4565b600a6020525f908152604090205481565b348015610a83575f80fd5b5060015461042c906001600160a01b031681565b348015610aa2575f80fd5b5061087f610ab13660046146f4565b6125a1565b348015610ac1575f80fd5b506103f7610ad0366004614311565b6125f7565b348015610ae0575f80fd5b506103f7610aef366004614311565b6126f8565b610457610b02366004614926565b6127a2565b348015610b12575f80fd5b50610b50610b213660046146f4565b600d6020525f908152604090205460ff808216916101008104909116906201000090046001600160801b031683565b60408051931515845291151560208401526001600160801b0316908201526060016103db565b348015610b81575f80fd5b506103f7610b903660046146f4565b6128c9565b348015610ba0575f80fd5b50610457610baf3660046149b8565b612949565b348015610bbf575f80fd5b50600454610bd3906001600160601b031681565b6040516001600160601b0390911681526020016103db565b348015610bf6575f80fd5b506103f7610c05366004614311565b612994565b348015610c15575f80fd5b506103f7610c24366004614a2d565b612a20565b348015610c34575f80fd5b506103cf610c43366004614311565b60096020525f908152604090205460ff1681565b348015610c62575f80fd5b506103f7610c71366004614311565b612aab565b348015610c81575f80fd5b506103f7610c90366004614a2d565b612b26565b348015610ca0575f80fd5b5061042c7f00000000000000000000000008c6f91e2b681faf5e17227f2a44c307b3c1364c81565b348015610cd3575f80fd5b506103cf610ce2366004614a9b565b612bb1565b610cfc335f356001600160e01b031916612be5565b610d215760405162461bcd60e51b8152600401610d1890614ab5565b60405180910390fd5b600254600114610d435760405162461bcd60e51b8152600401610d1890614adb565b60028055600454600160a01b900460ff1615610d725760405163e0f9e71d60e01b815260040160405180910390fd5b610d80868686868686612c8b565b5050600160025550505050565b5f610da3335f356001600160e01b031916612be5565b610dbf5760405162461bcd60e51b8152600401610d1890614ab5565b600254600114610de15760405162461bcd60e51b8152600401610d1890614adb565b600280555f610def85612dc5565b90505f73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03871601610f2b57345f03610e375760405163259be69560e11b815260040160405180910390fd5b7f00000000000000000000000053000000000000000000000000000000000000046001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004015f604051808303818588803b158015610e90575f80fd5b505af1158015610ea2573d5f803e3d5ffd5b50349850610f019350506001600160a01b037f00000000000000000000000053000000000000000000000000000000000000041691507f00000000000000000000000008c6f91e2b681faf5e17227f2a44c307b3c1364c905087612e80565b507f0000000000000000000000005300000000000000000000000000000000000004945030610f4d565b3415610f4a57604051631cf02cf960e21b815260040160405180910390fd5b50335b610f5b868686843387612f02565b9250610f88338787866004600c9054906101000a90046001600160401b03166001600160401b03166130c1565b505060016002559392505050565b610fab335f356001600160e01b031916612be5565b610fc75760405162461bcd60e51b8152600401610d1890614ab5565b6203f480816001600160401b03161115610ff457604051631fac010160e21b815260040160405180910390fd5b600480546001600160401b03909216600160601b0267ffffffffffffffff60601b19909216919091179055565b7f0000000000000000000000001a44076050125825900e736c501f859c50fe728c6001600160a01b0316331461106c576040516391ac5e4f60e01b8152336004820152602401610d18565b6020870180359061108690611081908a6146f4565b6131f0565b146110c45761109860208801886146f4565b60405163309afaf360e21b815263ffffffff909116600482015260208801356024820152604401610d18565b6110d38787878787878761322b565b50505050505050565b6110f1335f356001600160e01b031916612be5565b61110d5760405162461bcd60e51b8152600401610d1890614ab5565b806001600160801b03165f036111365760405163c80ed59560e01b815260040160405180910390fd5b63ffffffff82165f818152600d6020908152604091829020805462010000600160901b031916620100006001600160801b038716908102919091178255835194855291840191909152917f0aa48359f83e8464fda3f4ea4bd3f2d6af01e90b46ab9464aa7d538e1772947a91015b60405180910390a1505050565b6111c6335f356001600160e01b031916612be5565b6111e25760405162461bcd60e51b8152600401610d1890614ab5565b6001600160a01b0381165f8181526007602090815260408083208054600160ff1991821681179092556008845282852080548216831790556009909352818420805490931617909155517fd658022b1a3aaf6ad3b3c615253712807f21a8f7bc3e4996e10618175d4afb2b9190a26040516001600160a01b038216907f79fc685a7dbabb75a67df5e69a90602cef1f19bc465b060eab1ac56685e04a13905f90a26040516001600160a01b038216907f3afb02134e37f7205acf470adc2fc4ebb70614b1599a602d069790915380e2aa905f90a250565b6112ce335f356001600160e01b031916612be5565b6112ea5760405162461bcd60e51b8152600401610d1890614ab5565b6001600160a01b0381165f81815260096020526040808220805460ff19166001179055517f3afb02134e37f7205acf470adc2fc4ebb70614b1599a602d069790915380e2aa9190a250565b61134a335f356001600160e01b031916612be5565b6113665760405162461bcd60e51b8152600401610d1890614ab5565b6001600160a01b0381165f81815260096020526040808220805460ff19169055517f77cb944c14da76928795279d1519ce9150085a06e0a53c61d5a86fc4e0fd57c69190a250565b6113c3335f356001600160e01b031916612be5565b6113df5760405162461bcd60e51b8152600401610d1890614ab5565b63ffffffff82165f908152600d60205260409020805460ff19166001178155611411836001600160a01b03841661331e565b6040805163ffffffff851681526001600160a01b03841660208201527fe925de263dcdbdc20307c9ab92758ed8cc0edf3d173dad4a3aa54c070f27a54391016111a4565b61146a335f356001600160e01b031916612be5565b6114865760405162461bcd60e51b8152600401610d1890614ab5565b6001600160a01b0381165f81815260076020526040808220805460ff19166001179055517fd658022b1a3aaf6ad3b3c615253712807f21a8f7bc3e4996e10618175d4afb2b9190a250565b6114e6335f356001600160e01b031916612be5565b6115025760405162461bcd60e51b8152600401610d1890614ab5565b61150c828261331e565b5050565b611525335f356001600160e01b031916612be5565b6115415760405162461bcd60e51b8152600401610d1890614ab5565b82801561155557506001600160801b038116155b156115735760405163c80ed59560e01b815260040160405180910390fd5b60408051606081018252851515815284151560208083019182526001600160801b0385811684860190815263ffffffff8b165f908152600d90935294909120925183549251945161ffff1990931690151561ff00191617610100941515949094029390931762010000600160901b031916620100009190931602919091179055611606856001600160a01b03841661331e565b6040805163ffffffff871681528515156020820152841515818301526001600160a01b038416606082015290517f5dbe727bffd24a6d61a5aeef919510389c66c0deeaa82634862cf4f098961fb89181900360800190a15050505050565b611679335f356001600160e01b031916612be5565b6116955760405162461bcd60e51b8152600401610d1890614ab5565b6001600160a01b0381165f81815260086020526040808220805460ff19166001179055517f79fc685a7dbabb75a67df5e69a90602cef1f19bc465b060eab1ac56685e04a139190a250565b5f6116f6335f356001600160e01b031916612be5565b6117125760405162461bcd60e51b8152600401610d1890614ab5565b6002546001146117345760405162461bcd60e51b8152600401610d1890614adb565b600280558773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03821601611777576040516316df5df960e31b815260040160405180910390fd5b5f6117818a612dc5565b90506117918a8a8989898961336b565b61179f8a8a8a333386612f02565b92506117cc338b8b866004600c9054906101000a90046001600160401b03166001600160401b03166130c1565b50506001600255979650505050505050565b5f6117f4335f356001600160e01b031916612be5565b6118105760405162461bcd60e51b8152600401610d1890614ab5565b600454600160a01b900460ff161561183b5760405163e0f9e71d60e01b815260040160405180910390fd5b6001600160a01b0385165f908152600360209081526040918290208251606081018452905460ff80821615158352610100820416151592820183905262010000900461ffff16928101929092526118a55760405163645fd19f60e11b815260040160405180910390fd5b845f036118c557604051630ea3153160e21b815260040160405180910390fd5b604051634104b9ed60e11b81526001600160a01b03878116600483015261197b917f000000000000000000000000c315d6e14ddcdc7407784e2caf815d131bc1d3e79091169063820973da90602401602060405180830381865afa15801561192f573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119539190614aff565b86907f00000000000000000000000000000000000000000000000000000000000f42406134c3565b91508382101561199e576040516302620f6160e61b815260040160405180910390fd5b6040516318457e6160e01b81526001600160a01b037f00000000000000000000000008c6f91e2b681faf5e17227f2a44c307b3c1364c16906318457e61906119f29086908a90879033908c90600401614b16565b5f604051808303815f87803b158015611a09575f80fd5b505af1158015611a1b573d5f803e3d5ffd5b50505050856001600160a01b03167fdcc60b41ff1c604459e6aa4a7299817416b19fc586a392f111646e26597c4af986604051611a5a91815260200190565b60405180910390a250949350505050565b611a80335f356001600160e01b031916612be5565b611a9c5760405162461bcd60e51b8152600401610d1890614ab5565b6004805460ff60a01b191690556040517fa45f47fdea8a1efdd9029a5691c7f759c32b7c698632b563573e155625d16933905f90a1565b611ae8335f356001600160e01b031916612be5565b611b045760405162461bcd60e51b8152600401610d1890614ab5565b63ffffffff81165f818152600d6020908152604091829020805461ff0019168155915192835290917fc45af64a13a09ef916a1114c59589294ec9c3095f2bfbbb093a7a96656858ded91015b60405180910390a15050565b611b71335f356001600160e01b031916612be5565b611b8d5760405162461bcd60e51b8152600401610d1890614ab5565b80611b988342614b5d565b10611bb657604051634c1eef1760e11b815260040160405180910390fd5b604080516001600160a01b038089166020830152871691810191909152606081018590526080810184905260a0810183905260c081018290525f9060e00160408051601f1981840301815291815281516020928301205f8b815260059093529120549091508114611c3a5760405163fa174ecb60e01b815260040160405180910390fd5b5f888152600560205260408120556001600160a01b03861673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14611c725785611c94565b7f00000000000000000000000053000000000000000000000000000000000000045b6040516318457e6160e01b81529096506001600160a01b037f00000000000000000000000008c6f91e2b681faf5e17227f2a44c307b3c1364c16906318457e6190611ceb908a908a908a9083908b90600401614b16565b5f604051808303815f87803b158015611d02575f80fd5b505af1158015611d14573d5f803e3d5ffd5b50505050866001600160a01b0316887faf98ea774275cadfa3e477a7b52cba03e01197445a76bd5d0d561608708c362483604051611d5491815260200190565b60405180910390a35050505050505050565b611d7b335f356001600160e01b031916612be5565b611d975760405162461bcd60e51b8152600401610d1890614ab5565b63ffffffff81165f908152600d60205260408120805471ffffffffffffffffffffffffffffffffffff19169055611dcf90829061331e565b60405163ffffffff821681527f11a9d1a77f76361ed131c19b1dc5758504c51dbde2e49fc973a0ef9577ad13d5906020015b60405180910390a150565b611e21335f356001600160e01b031916612be5565b611e3d5760405162461bcd60e51b8152600401610d1890614ab5565b6001600160a01b0381165f81815260086020526040808220805460ff19169055517f039bcf51833310242b8b7c6aa0fbabf1bf2b5e5270807ee020f1920ef200666b9190a250565b63ffffffff81165f908152600c6020908152604080832081516080810183528154808252600183015494820185905260028301549382018490526003909201546060820181905285949193611edb9392916134de565b9250925050915091565b5f546001600160a01b0316331480611f76575060015460405163b700961360e01b81526001600160a01b039091169063b700961390611f3790339030906001600160e01b03195f351690600401614b70565b602060405180830381865afa158015611f52573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611f769190614b9d565b611f7e575f80fd5b600180546001600160a01b0319166001600160a01b03831690811790915560405133907fa3396fd7f6e0a21b50e5089d2da70d5ac0a3bbbd1f617a93f134b76389980198905f90a350565b5f5b92915050565b611fe6335f356001600160e01b031916612be5565b6120025760405162461bcd60e51b8152600401610d1890614ab5565b6004805460ff60a01b1916600160a01b1790556040517f9e87fac88ff661f02d44f95383c817fece4bce600a3dab7a54406878b965e752905f90a1565b612054335f356001600160e01b031916612be5565b6120705760405162461bcd60e51b8152600401610d1890614ab5565b6103e861ffff8216111561209757604051636c5cde8760e01b815260040160405180910390fd5b6040805160608082018352851515808352851515602080850182815261ffff8881168789018181526001600160a01b038e165f818152600387528b902099518a549551925161ffff1990961690151561ff00191617610100921515929092029190911763ffff0000191662010000949093169390930291909117909655865193845290830191909152938101929092527fe08301321781ac43935a2099b2c3fd42de0a0ee87a519cac00e8c9cecd26ff12910160405180910390a250505050565b5f61216e335f356001600160e01b031916612be5565b61218a5760405162461bcd60e51b8152600401610d1890614ab5565b6002546001146121ac5760405162461bcd60e51b8152600401610d1890614adb565b600280558c73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b038216016121ef576040516316df5df960e31b815260040160405180910390fd5b5f6121f98f612dc5565b90506122098f8f8e8e8e8e61336b565b6122178f8f8f333386612f02565b925050612245338f8f856004600c9054906101000a90046001600160401b03166001600160401b03166130c1565b6001600160601b0382111561226d576040516389588ab360e01b815260040160405180910390fd5b61227b828888888888612c8b565b5060016002559c9b505050505050505050505050565b5f6122a7335f356001600160e01b031916612be5565b6122c35760405162461bcd60e51b8152600401610d1890614ab5565b6002546001146122e55760405162461bcd60e51b8152600401610d1890614adb565b600280555f6122f386612dc5565b9050612303868686338786612f02565b9150856001600160a01b03167f6f9b974223f85a1ae805c33b8b519039e2435481d949db1110de151a94d587af8660405161234091815260200190565b60405180910390a2506001600255949350505050565b61236b335f356001600160e01b031916612be5565b6123875760405162461bcd60e51b8152600401610d1890614ab5565b6001600160a01b0381165f81815260076020526040808220805460ff19169055517fae893dda71e2eee548f8291f458cceae4bd22b56a79906928591e4420444c0e99190a250565b6001600160a01b0383165f9081526007602052604090205460ff168061240c57506001600160a01b0382165f9081526008602052604090205460ff165b8061242e57506001600160a01b0381165f9081526009602052604090205460ff165b1561246757604051632821264f60e01b81526001600160a01b038085166004830152808416602483015282166044820152606401610d18565b6001600160a01b0383165f9081526006602052604090205442101561249f5760405163f64059db60e01b815260040160405180910390fd5b505050565b6124b9335f356001600160e01b031916612be5565b6124d55760405162461bcd60e51b8152600401610d1890614ab5565b806001600160801b03165f036124fe5760405163c80ed59560e01b815260040160405180910390fd5b63ffffffff83165f908152600d60205260409020805461010071ffffffffffffffffffffffffffffffffff0019909116620100006001600160801b0385160217178155612554846001600160a01b03851661331e565b6040805163ffffffff861681526001600160a01b03851660208201527f34fe916485e02ec88e487b0e611e5c9bacabba9e3eaae7a900aa08be8197d419910160405180910390a150505050565b63ffffffff81165f908152600b6020908152604080832081516080810183528154808252600183015494820185905260028301549382018490526003909201546060820181905285949193611edb9392916134de565b61260c335f356001600160e01b031916612be5565b6126285760405162461bcd60e51b8152600401610d1890614ab5565b6001600160a01b0381165f818152600760209081526040808320805460ff199081169091556008835281842080548216905560099092528083208054909216909155517fae893dda71e2eee548f8291f458cceae4bd22b56a79906928591e4420444c0e99190a26040516001600160a01b038216907f039bcf51833310242b8b7c6aa0fbabf1bf2b5e5270807ee020f1920ef200666b905f90a26040516001600160a01b038216907f77cb944c14da76928795279d1519ce9150085a06e0a53c61d5a86fc4e0fd57c6905f90a250565b61270d335f356001600160e01b031916612be5565b6127295760405162461bcd60e51b8152600401610d1890614ab5565b60405163ca5eb5e160e01b81526001600160a01b0382811660048301527f0000000000000000000000001a44076050125825900e736c501f859c50fe728c169063ca5eb5e1906024015f604051808303815f87803b158015612789575f80fd5b505af115801561279b573d5f803e3d5ffd5b5050505050565b5f6127b8335f356001600160e01b031916612be5565b6127d45760405162461bcd60e51b8152600401610d1890614ab5565b6002546001146127f65760405162461bcd60e51b8152600401610d1890614adb565b600280558873eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03821601612839576040516316df5df960e31b815260040160405180910390fd5b5f6128438b612dc5565b90506128538b8b8b333386612f02565b9250612880338c8c866004600c9054906101000a90046001600160401b03166001600160401b03166130c1565b6001600160601b038311156128a8576040516389588ab360e01b815260040160405180910390fd5b6128b6838989898989612c8b565b5050600160025598975050505050505050565b6128de335f356001600160e01b031916612be5565b6128fa5760405162461bcd60e51b8152600401610d1890614ab5565b63ffffffff81165f818152600d6020908152604091829020805460ff19168155915192835290917f1cb867ed6a020e020ea220d4f48bb8e36552abf9095e093e377d33933f2b31e49101611b50565b604080518082019091526001600160601b03861681526001600160a01b03851660208201525f908161297a82613559565b9050612988818787876135a0565b98975050505050505050565b6001600160a01b0381165f9081526007602052604090205460ff16156129e557604051632821264f60e01b81526001600160a01b03821660048201525f602482018190526044820152606401610d18565b6001600160a01b0381165f90815260066020526040902054421015612a1d5760405163f64059db60e01b815260040160405180910390fd5b50565b612a35335f356001600160e01b031916612be5565b612a515760405162461bcd60e51b8152600401610d1890614ab5565b61150c8282808060200260200160405190810160405280939291908181526020015f905b82821015612aa157612a9260608302860136819003810190614bec565b81526020019060010190612a75565b505050505061376f565b612ac0335f356001600160e01b031916612be5565b612adc5760405162461bcd60e51b8152600401610d1890614ab5565b5f80546001600160a01b0319166001600160a01b0383169081178255604051909133917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a350565b612b3b335f356001600160e01b031916612be5565b612b575760405162461bcd60e51b8152600401610d1890614ab5565b61150c8282808060200260200160405190810160405280939291908181526020015f905b82821015612ba757612b9860608302860136819003810190614bec565b81526020019060010190612b7b565b5050505050613861565b5f60208201803590600a908390612bc890866146f4565b63ffffffff16815260208101919091526040015f20541492915050565b6001545f906001600160a01b03168015801590612c6c575060405163b700961360e01b81526001600160a01b0382169063b700961390612c2d90879030908890600401614b70565b602060405180830381865afa158015612c48573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612c6c9190614b9d565b80612c8357505f546001600160a01b038581169116145b949350505050565b612c96335f336123cf565b6040516318457e6160e01b81525f600482018190526024820181905260448201523360648201526001600160601b03871660848201527f00000000000000000000000008c6f91e2b681faf5e17227f2a44c307b3c1364c6001600160a01b0316906318457e619060a4015f604051808303815f87803b158015612d17575f80fd5b505af1158015612d29573d5f803e3d5ffd5b5050604080518082019091526001600160601b03891681526001600160a01b038816602082015291505f9050612d5e82613559565b90505f612d6e8288888888613953565b6040516001600160601b038b1681529091506001600160a01b0389169082907fe0ec62d39b054dc2fd626dbc271483735df6e6fa1ef8389754bf8ab27a75eab29060200160405180910390a3505050505050505050565b604080516060810182525f8082526020820181905291810191909152600454600160a01b900460ff1615612e0c5760405163e0f9e71d60e01b815260040160405180910390fd5b506001600160a01b0381165f908152600360209081526040918290208251606081018452905460ff8082161515808452610100830490911615159383019390935262010000900461ffff1692810192909252612e7b5760405163645fd19f60e11b815260040160405180910390fd5b919050565b5f60405163095ea7b360e01b81526001600160a01b038416600482015282602482015260205f6044835f895af13d15601f3d1160015f511416171691505080612efc5760405162461bcd60e51b815260206004820152600e60248201526d1054141493d59157d1905253115160921b6044820152606401610d18565b50505050565b5f855f03612f235760405163259be69560e11b815260040160405180910390fd5b604051634104b9ed60e11b81526001600160a01b038881166004830152612fd9917f00000000000000000000000000000000000000000000000000000000000f4240917f000000000000000000000000c315d6e14ddcdc7407784e2caf815d131bc1d3e7169063820973da90602401602060405180830381865afa158015612fad573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612fd19190614aff565b8891906134c3565b90505f826040015161ffff1611612ff05780613013565b61301382604001516127106130059190614c2d565b829061ffff166127106134c3565b9050848110156130365760405163097b2ad560e31b815260040160405180910390fd5b604051631ceb5d1960e11b81526001600160a01b037f00000000000000000000000008c6f91e2b681faf5e17227f2a44c307b3c1364c16906339d6ba329061308a9087908b908b9089908890600401614b16565b5f604051808303815f87803b1580156130a1575f80fd5b505af11580156130b3573d5f803e3d5ffd5b505050509695505050505050565b600480545f919082906130dc906001600160601b0316614c4f565b82546001600160601b039182166101009390930a8381029202191617909155905081156131805761310d8242614c74565b6001600160a01b038781165f81815260066020908152604091829020949094558051938401919091529087169082015260608101859052608081018490524260a082015260c0810183905260e00160408051601f1981840301815291815281516020928301205f84815260059093529120555b846001600160a01b0316866001600160a01b0316827fe96d7872363f475d18b2f5390caaa5eaa96b2d38e42c62afe4ac08ebd2b13c3a878742886040516131e0949392919093845260208401929092526040830152606082015260800190565b60405180910390a4505050505050565b63ffffffff81165f908152600a602052604081205480611fcb5760405163f6ff4fb760e01b815263ffffffff84166004820152602401610d18565b5f600d8161323c60208b018b6146f4565b63ffffffff16815260208082019290925260409081015f208151606081018352905460ff808216151580845261010083049091161515948301949094526201000090046001600160801b03169181019190915291506132c4576132a260208901896146f4565b6040516315b73a2960e21b815263ffffffff9091166004820152602401610d18565b5f6132d186880188614885565b90506133096132e360208b018b6146f4565b6040805180820190915260a084901c81526001600160a01b038416602082015251613ba6565b6133138882613c1b565b505050505050505050565b63ffffffff82165f818152600a6020908152604091829020849055815192835282018390527f238399d427b947898edb290f5ff0f9109849b1c3ba196a42e35f00c50a54b98b9101611b50565b60405163d505accf60e01b81523360048201526001600160a01b037f00000000000000000000000008c6f91e2b681faf5e17227f2a44c307b3c1364c81166024830152604482018790526064820186905260ff8516608483015260a4820184905260c4820183905287169063d505accf9060e4015f604051808303815f87803b1580156133f6575f80fd5b505af1925050508015613407575060015b6134bb57604051636eb1769f60e11b81523360048201526001600160a01b037f00000000000000000000000008c6f91e2b681faf5e17227f2a44c307b3c1364c8116602483015286919088169063dd62ed3e90604401602060405180830381865afa158015613478573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061349c9190614aff565b10156134bb576040516301b8851f60e41b815260040160405180910390fd5b505050505050565b5f825f1904841183021582026134d7575f80fd5b5091020490565b5f80806134eb8642614b5d565b90508381106134ff575f925084915061354f565b5f8461350b8388614c87565b6135159190614c9e565b90508088111561352e576135298189614b5d565b613530565b5f5b935083861115613549576135448487614b5d565b61354b565b5f5b9250505b5094509492505050565b80515f906001600160601b03101561358457604051633524486360e01b815260040160405180910390fd5b81516020909201516001600160a01b031660a09290921b171790565b5f6001600160a01b03821673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1480159061360057507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031614155b1561361e57604051637f3cd08160e11b815260040160405180910390fd5b5f61362b848601866146f4565b63ffffffff81165f908152600d60209081526040918290208251606081018452905460ff8082161515835261010082041615159282018390526201000090046001600160801b031692810192909252919250906136a35760405163420eae3760e01b815263ffffffff83166004820152602401610d18565b5f876040516020016136b791815260200190565b60405160208183030381529060405290505f6136ff83604001515f6136f860408051600360f01b602082015281516002818303018152602290910190915290565b9190613d07565b90505f61372e8584846001600160a01b038b1673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1415613d6c565b90506001600160a01b03871673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1461375e578060200151613761565b80515b9a9950505050505050505050565b5f5b8151811015613831575f600b5f84848151811061379057613790614cbd565b60200260200101515f015163ffffffff1663ffffffff1681526020019081526020015f2090506137dc8383815181106137cb576137cb614cbd565b60200260200101515f01515f613e4a565b8282815181106137ee576137ee614cbd565b602002602001015160200151816002018190555082828151811061381457613814614cbd565b602090810291909101015160400151600390910155600101613771565b507f55254e344b7fc8e2e038c1f7f20a1c7afe659c1a3bbfc4e35dd1ca9bba0ca0a081604051611e019190614cd1565b5f5b8151811015613923575f600c5f84848151811061388257613882614cbd565b60200260200101515f015163ffffffff1663ffffffff1681526020019081526020015f2090506138ce8383815181106138bd576138bd614cbd565b60200260200101515f01515f613ba6565b8282815181106138e0576138e0614cbd565b602002602001015160200151816002018190555082828151811061390657613906614cbd565b602090810291909101015160400151600390910155600101613863565b507f983af742b0b5ca79aa5c0be76cea126e1baf3139ecd04624deac13853c4bebde81604051611e019190614cd1565b5f80613961858701876146f4565b90506139958161398f896040805180820190915260a082901c81526001600160a01b03909116602082015290565b51613e4a565b63ffffffff81165f908152600d60209081526040918290208251606081018452905460ff8082161515835261010082041615159282018390526201000090046001600160801b031692810192909252613a095760405163420eae3760e01b815263ffffffff83166004820152602401610d18565b5f88604051602001613a1d91815260200190565b60405160208183030381529060405290505f613a5e83604001515f6136f860408051600360f01b602082015281516002818303018152602290910190915290565b90505f613a8d8584846001600160a01b038c1673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1415613d6c565b905073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03891601613af4578051871015613aef57805160405163f5ac3fa760e01b815263ffffffff87166004820152602481019190915260448101889052606401610d18565b613b87565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316886001600160a01b031603613b6e578681602001511115613aef57602081015160405163f5ac3fa760e01b815263ffffffff87166004820152602481019190915260448101889052606401610d18565b604051637f3cd08160e11b815260040160405180910390fd5b5f613b958685858533613ea6565b519c9b505050505050505050505050565b63ffffffff82165f908152600c6020526040812080546001820154600283015460038401549394938493613bdd93909290916134de565b9150915080841115613c0257604051636a526abb60e01b815260040160405180910390fd5b613c0c8483614c74565b83555050426001909101555050565b60408051808201825260a083901c8082526001600160a01b03808516602084018190529351631ceb5d1960e11b815292937f00000000000000000000000008c6f91e2b681faf5e17227f2a44c307b3c1364c909116926339d6ba3292613c8a925f928392839291600401614b16565b5f604051808303815f87803b158015613ca1575f80fd5b505af1158015613cb3573d5f803e3d5ffd5b5050505080602001516001600160a01b0316837fb944fddc61d7fedb8b736790454ba972000703b0d21c7481d6dbf95b7c2cc2f1835f0151604051613cfa91815260200190565b60405180910390a3505050565b6060836003613d16825f613fac565b61ffff1614613d4957613d29815f613fac565b604051633a51740d60e01b815261ffff9091166004820152602401610d18565b5f613d548585614008565b9050613d6286600183614081565b9695505050505050565b604080518082019091525f80825260208201527f0000000000000000000000001a44076050125825900e736c501f859c50fe728c6001600160a01b031663ddc28c586040518060a001604052808863ffffffff168152602001613dce896131f0565b8152602001878152602001868152602001851515815250306040518363ffffffff1660e01b8152600401613e03929190614d7c565b6040805180830381865afa158015613e1d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613e419190614e4c565b95945050505050565b63ffffffff82165f908152600b6020526040812080546001820154600283015460038401549394938493613e8193909290916134de565b9150915080841115613c02576040516324292aa760e01b815260040160405180910390fd5b613eae6142af565b5f613ebb845f01516140ea565b602085015190915015613ed557613ed58460200151614111565b7f0000000000000000000000001a44076050125825900e736c501f859c50fe728c6001600160a01b0316632637a450826040518060a001604052808b63ffffffff168152602001613f258c6131f0565b81526020018a81526020018981526020015f8960200151111515815250866040518463ffffffff1660e01b8152600401613f60929190614d7c565b60806040518083038185885af1158015613f7c573d5f803e3d5ffd5b50505050506040513d601f19601f82011682018060405250810190613fa19190614e66565b979650505050505050565b5f613fb8826002614c74565b83511015613fff5760405162461bcd60e51b8152602060048201526014602482015273746f55696e7431365f6f75744f66426f756e647360601b6044820152606401610d18565b50016002015190565b60606001600160801b0382161561405057604080516001600160801b0319608086811b8216602084015285901b1660308201520160405160208183030381529060405261407a565b6040516001600160801b0319608085901b1660208201526030016040516020818303038152906040525b9392505050565b6060836003614090825f613fac565b61ffff16146140a357613d29815f613fac565b8460016140b085516141f0565b6140bb906001614eae565b86866040516020016140d1959493929190614ec9565b6040516020818303038152906040529150509392505050565b5f81341461410d576040516304fb820960e51b8152346004820152602401610d18565b5090565b5f7f0000000000000000000000001a44076050125825900e736c501f859c50fe728c6001600160a01b031663e4fe1d946040518163ffffffff1660e01b8152600401602060405180830381865afa15801561416e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906141929190614f2f565b90506001600160a01b0381166141bb576040516329b99a9560e11b815260040160405180910390fd5b61150c6001600160a01b038216337f0000000000000000000000001a44076050125825900e736c501f859c50fe728c8561421e565b5f61ffff82111561410d576040516306dfcc6560e41b81526010600482015260248101839052604401610d18565b5f6040516323b872dd60e01b81526001600160a01b03851660048201526001600160a01b038416602482015282604482015260205f6064835f8a5af13d15601f3d1160015f51141617169150508061279b5760405162461bcd60e51b81526020600482015260146024820152731514905394d1915497d19493d357d1905253115160621b6044820152606401610d18565b60405180606001604052805f80191681526020015f6001600160401b031681526020016142ed60405180604001604052805f81526020015f81525090565b905290565b6001600160a01b0381168114612a1d575f80fd5b8035612e7b816142f2565b5f60208284031215614321575f80fd5b813561407a816142f2565b80356001600160601b0381168114612e7b575f80fd5b5f8083601f840112614352575f80fd5b5081356001600160401b03811115614368575f80fd5b60208301915083602082850101111561437f575f80fd5b9250929050565b5f805f805f8060a0878903121561439b575f80fd5b6143a48761432c565b955060208701356143b4816142f2565b945060408701356001600160401b038111156143ce575f80fd5b6143da89828a01614342565b90955093505060608701356143ee816142f2565b80925050608087013590509295509295509295565b5f805f60608486031215614415575f80fd5b8335614420816142f2565b95602085013595506040909401359392505050565b6001600160401b0381168114612a1d575f80fd5b5f60208284031215614459575f80fd5b813561407a81614435565b5f60608284031215614474575f80fd5b50919050565b5f805f805f805f60e0888a031215614490575f80fd5b61449a8989614464565b96506060880135955060808801356001600160401b03808211156144bc575f80fd5b6144c88b838c01614342565b909750955060a08a013591506144dd826142f2565b90935060c089013590808211156144f2575f80fd5b506144ff8a828b01614342565b989b979a50959850939692959293505050565b803563ffffffff81168114612e7b575f80fd5b80356001600160801b0381168114612e7b575f80fd5b5f806040838503121561454c575f80fd5b61455583614512565b915061456360208401614525565b90509250929050565b5f806040838503121561457d575f80fd5b61458683614512565b91506020830135614596816142f2565b809150509250929050565b5f80604083850312156145b2575f80fd5b6145bb83614512565b946020939093013593505050565b8015158114612a1d575f80fd5b5f805f805f60a086880312156145ea575f80fd5b6145f386614512565b94506020860135614603816145c9565b93506040860135614613816145c9565b92506060860135614623816142f2565b915061463160808701614525565b90509295509295909350565b803560ff81168114612e7b575f80fd5b5f805f805f805f60e0888a031215614663575f80fd5b873561466e816142f2565b96506020880135955060408801359450606088013593506146916080890161463d565b925060a0880135915060c0880135905092959891949750929550565b5f805f80608085870312156146c0575f80fd5b84356146cb816142f2565b9350602085013592506040850135915060608501356146e9816142f2565b939692955090935050565b5f60208284031215614704575f80fd5b61407a82614512565b5f805f805f805f60e0888a031215614723575f80fd5b873596506020880135614735816142f2565b95506040880135614745816142f2565b969995985095966060810135965060808101359560a0820135955060c0909101359350915050565b5f805f8060808587031215614780575f80fd5b843561478b816142f2565b9350602085013561479b816145c9565b925060408501356147ab816145c9565b9150606085013561ffff811681146146e9575f80fd5b5f805f805f805f805f805f806101608d8f0312156147dd575f80fd5b6147e78d356142f2565b8c359b5060208d01359a5060408d0135995060608d0135985061480c60808e0161463d565b975060a08d0135965060c08d0135955061482960e08e01356142f2565b60e08d013594506001600160401b036101008e01351115614848575f80fd5b6148598e6101008f01358f01614342565b909450925061486b6101208e01614306565b91506101408d013590509295989b509295989b509295989b565b5f60208284031215614895575f80fd5b5035919050565b5f805f606084860312156148ae575f80fd5b83356148b9816142f2565b925060208401356148c9816142f2565b915060408401356148d9816142f2565b809150509250925092565b5f805f606084860312156148f6575f80fd5b6148ff84614512565b9250602084013561490f816142f2565b915061491d60408501614525565b90509250925092565b5f805f805f805f8060e0898b03121561493d575f80fd5b8835614948816142f2565b975060208901359650604089013595506060890135614966816142f2565b945060808901356001600160401b03811115614980575f80fd5b61498c8b828c01614342565b90955093505060a08901356149a0816142f2565b8092505060c089013590509295985092959890939650565b5f805f805f608086880312156149cc575f80fd5b6149d58661432c565b945060208601356149e5816142f2565b935060408601356001600160401b038111156149ff575f80fd5b614a0b88828901614342565b9094509250506060860135614a1f816142f2565b809150509295509295909350565b5f8060208385031215614a3e575f80fd5b82356001600160401b0380821115614a54575f80fd5b818501915085601f830112614a67575f80fd5b813581811115614a75575f80fd5b866020606083028501011115614a89575f80fd5b60209290920196919550909350505050565b5f60608284031215614aab575f80fd5b61407a8383614464565b6020808252600c908201526b15539055551213d49256915160a21b604082015260600190565b6020808252600a90820152695245454e5452414e435960b01b604082015260600190565b5f60208284031215614b0f575f80fd5b5051919050565b6001600160a01b039586168152938516602085015260408401929092529092166060820152608081019190915260a00190565b634e487b7160e01b5f52601160045260245ffd5b81810381811115611fcb57611fcb614b49565b6001600160a01b0393841681529190921660208201526001600160e01b0319909116604082015260600190565b5f60208284031215614bad575f80fd5b815161407a816145c9565b604051606081016001600160401b0381118282101715614be657634e487b7160e01b5f52604160045260245ffd5b60405290565b5f60608284031215614bfc575f80fd5b614c04614bb8565b614c0d83614512565b815260208301356020820152604083013560408201528091505092915050565b61ffff828116828216039080821115614c4857614c48614b49565b5092915050565b5f6001600160601b03808316818103614c6a57614c6a614b49565b6001019392505050565b80820180821115611fcb57611fcb614b49565b8082028115828204841417611fcb57611fcb614b49565b5f82614cb857634e487b7160e01b5f52601260045260245ffd5b500490565b634e487b7160e01b5f52603260045260245ffd5b602080825282518282018190525f919060409081850190868401855b82811015614d22578151805163ffffffff16855286810151878601528501518585015260609093019290850190600101614ced565b5091979650505050505050565b5f5b83811015614d49578181015183820152602001614d31565b50505f910152565b5f8151808452614d68816020860160208601614d2f565b601f01601f19169290920160200192915050565b6040815263ffffffff8351166040820152602083015160608201525f604084015160a06080840152614db160e0840182614d51565b90506060850151603f198483030160a0850152614dce8282614d51565b60809690960151151560c08501525050506001600160a01b039190911660209091015290565b5f60408284031215614e04575f80fd5b604051604081018181106001600160401b0382111715614e3257634e487b7160e01b5f52604160045260245ffd5b604052825181526020928301519281019290925250919050565b5f60408284031215614e5c575f80fd5b61407a8383614df4565b5f60808284031215614e76575f80fd5b614e7e614bb8565b825181526020830151614e9081614435565b6020820152614ea28460408501614df4565b60408201529392505050565b61ffff818116838216019080821115614c4857614c48614b49565b5f8651614eda818460208b01614d2f565b6001600160f81b031960f888811b82169285019283526001600160f01b031960f089901b16600184015286901b1660038201528351614f20816004840160208801614d2f565b01600401979650505050505050565b5f60208284031215614f3f575f80fd5b815161407a816142f256fea26469706673582212200216655861d29097518938c81858a539139f28246f820f0e447622517a4ed44164736f6c63430008150033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000f8553c8552f906c19286f21711721e206ee4909e00000000000000000000000008c6f91e2b681faf5e17227f2a44c307b3c1364c000000000000000000000000c315d6e14ddcdc7407784e2caf815d131bc1d3e700000000000000000000000053000000000000000000000000000000000000040000000000000000000000001a44076050125825900e736c501f859c50fe728c000000000000000000000000f8553c8552f906c19286f21711721e206ee4909e0000000000000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : _owner (address): 0xf8553c8552f906C19286F21711721E206EE4909E
Arg [1] : _vault (address): 0x08c6F91e2B681FaF5e17227F2a44C307b3C1364C
Arg [2] : _accountant (address): 0xc315D6e14DDCDC7407784e2Caf815d131Bc1D3E7
Arg [3] : _weth (address): 0x5300000000000000000000000000000000000004
Arg [4] : _lzEndPoint (address): 0x1a44076050125825900e736c501f859c50fE728c
Arg [5] : _delegate (address): 0xf8553c8552f906C19286F21711721E206EE4909E
Arg [6] : _lzToken (address): 0x0000000000000000000000000000000000000000
-----Encoded View---------------
7 Constructor Arguments found :
Arg [0] : 000000000000000000000000f8553c8552f906c19286f21711721e206ee4909e
Arg [1] : 00000000000000000000000008c6f91e2b681faf5e17227f2a44c307b3c1364c
Arg [2] : 000000000000000000000000c315d6e14ddcdc7407784e2caf815d131bc1d3e7
Arg [3] : 0000000000000000000000005300000000000000000000000000000000000004
Arg [4] : 0000000000000000000000001a44076050125825900e736c501f859c50fe728c
Arg [5] : 000000000000000000000000f8553c8552f906c19286f21711721e206ee4909e
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000000
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
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.