Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00| Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 9150536 | 96 days ago | Contract Creation | 0 ETH |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
LayerZeroTeller
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: SEL-1.0
// Copyright © 2025 Veda Tech Labs
// Derived from Boring Vault Software © 2025 Veda Tech Labs (TEST ONLY – NO COMMERCIAL USE)
// Licensed under Software Evaluation License, Version 1.0
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";
contract LayerZeroTeller is CrossChainTellerWithGenericBridge, OAppAuth {
using SafeTransferLib for ERC20;
using AddressToBytes32Lib for address;
using AddressToBytes32Lib for bytes32;
using OptionsBuilder for bytes;
// ========================================= 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 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));
_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));
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: SEL-1.0
// Copyright © 2025 Veda Tech Labs
// Derived from Boring Vault Software © 2025 Veda Tech Labs (TEST ONLY – NO COMMERCIAL USE)
// Licensed under Software Evaluation License, Version 1.0
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: SEL-1.0
// Copyright © 2025 Veda Tech Labs
// Derived from Boring Vault Software © 2025 Veda Tech Labs (TEST ONLY – NO COMMERCIAL USE)
// Licensed under Software Evaluation License, Version 1.0
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: SEL-1.0
// Copyright © 2025 Veda Tech Labs
// Derived from Boring Vault Software © 2025 Veda Tech Labs (TEST ONLY – NO COMMERCIAL USE)
// Licensed under Software Evaluation License, Version 1.0
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;
}
/**
* @param denyFrom bool indicating whether or not the user is on the deny from list.
* @param denyTo bool indicating whether or not the user is on the deny to list.
* @param denyOperator bool indicating whether or not the user is on the deny operator list.
* @param permissionedOperator bool indicating whether or not the user is a permissioned operator, only applies when permissionedTransfers is true.
* @param shareUnlockTime uint256 indicating the time at which the shares will be unlocked.
*/
struct BeforeTransferData {
bool denyFrom;
bool denyTo;
bool denyOperator;
bool permissionedOperator;
uint256 shareUnlockTime;
}
// ========================================= 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.
*/
uint64 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;
/**
* @notice If true, only permissioned operators can transfer shares.
*/
bool public permissionedTransfers;
/**
* @notice The global deposit cap of the vault.
* @dev If the cap is reached, no new deposits are accepted. No partial fills.
*/
uint112 public depositCap = type(uint112).max;
/**
* @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 address to BeforeTransferData struct to check if shares are locked and if the address is on any allow or deny list.
*/
mapping(address => BeforeTransferData) public beforeTransferData;
//============================== 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();
error TellerWithMultiAssetSupport__DepositExceedsCap();
//============================== 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);
event PermissionedTransfersSet(bool permissionedTransfers);
event AllowPermissionedOperator(address indexed operator);
event DenyPermissionedOperator(address indexed operator);
event DepositCapSet(uint112 cap);
// =============================== 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));
permissionedTransfers = false;
}
// ========================================= 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 {
beforeTransferData[user].denyFrom = true;
beforeTransferData[user].denyTo = true;
beforeTransferData[user].denyOperator = 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 {
beforeTransferData[user].denyFrom = false;
beforeTransferData[user].denyTo = false;
beforeTransferData[user].denyOperator = 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 {
beforeTransferData[user].denyFrom = 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 {
beforeTransferData[user].denyFrom = 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 {
beforeTransferData[user].denyTo = 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 {
beforeTransferData[user].denyTo = 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 {
beforeTransferData[user].denyOperator = 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 {
beforeTransferData[user].denyOperator = false;
emit AllowOperator(user);
}
/**
* @notice Set the permissioned transfers flag.
* @dev Callable by OWNER_ROLE.
*/
function setPermissionedTransfers(bool _permissionedTransfers) external requiresAuth {
permissionedTransfers = _permissionedTransfers;
emit PermissionedTransfersSet(_permissionedTransfers);
}
/**
* @notice Give permission to an operator to transfer shares when permissioned transfers flag is true.
* @dev Callable by OWNER_ROLE.
*/
function allowPermissionedOperator(address operator) external requiresAuth {
beforeTransferData[operator].permissionedOperator = true;
emit AllowPermissionedOperator(operator);
}
/**
* @notice Revoke permission from an operator to transfer shares when permissioned transfers flag is true.
* @dev Callable by OWNER_ROLE, and DENIER_.
*/
function denyPermissionedOperator(address operator) external requiresAuth {
beforeTransferData[operator].permissionedOperator = false;
emit DenyPermissionedOperator(operator);
}
/**
* @notice Set the deposit cap of the vault.
* @dev Callable by OWNER_ROLE
*/
function setDepositCap(uint112 cap) external requiresAuth {
depositCap = cap;
emit DepositCapSet(cap);
}
// ========================================= BeforeTransferHook FUNCTIONS =========================================
/**
* @notice Implement beforeTransfer hook to check if shares are locked, or if `from`, `to`, or `operator` are denied in beforeTransferData.
* @notice If permissionedTransfers is true, then only operators on the allow list can transfer shares.
* @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 (
beforeTransferData[from].denyFrom || beforeTransferData[to].denyTo
|| beforeTransferData[operator].denyOperator
|| (permissionedTransfers && !beforeTransferData[operator].permissionedOperator)
) {
revert TellerWithMultiAssetSupport__TransferDenied(from, to, operator);
}
if (beforeTransferData[from].shareUnlockTime > 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 (beforeTransferData[from].denyFrom) {
revert TellerWithMultiAssetSupport__TransferDenied(from, address(0), address(0));
}
if (beforeTransferData[from].shareUnlockTime > 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) {
uint112 cap = depositCap;
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();
if (cap != type(uint112).max) {
if (shares + vault.totalSupply() > cap) revert TellerWithMultiAssetSupport__DepositExceedsCap();
}
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) {
beforeTransferData[user].shareUnlockTime = 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: SEL-1.0
// Copyright © 2025 Veda Tech Labs
// Derived from Boring Vault Software © 2025 Veda Tech Labs (TEST ONLY – NO COMMERCIAL USE)
// Licensed under Software Evaluation License, Version 1.0
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: 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: SEL-1.0
// Copyright © 2025 Veda Tech Labs
// Derived from Boring Vault Software © 2025 Veda Tech Labs (TEST ONLY – NO COMMERCIAL USE)
// Licensed under Software Evaluation License, Version 1.0
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: SEL-1.0
// Copyright © 2025 Veda Tech Labs
// Derived from Boring Vault Software © 2025 Veda Tech Labs (TEST ONLY – NO COMMERCIAL USE)
// Licensed under Software Evaluation License, Version 1.0
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: SEL-1.0
// Copyright © 2025 Veda Tech Labs
// Derived from Boring Vault Software © 2025 Veda Tech Labs (TEST ONLY – NO COMMERCIAL USE)
// Licensed under Software Evaluation License, Version 1.0
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: SEL-1.0
// Copyright © 2025 Veda Tech Labs
// Derived from Boring Vault Software © 2025 Veda Tech Labs (TEST ONLY – NO COMMERCIAL USE)
// Licensed under Software Evaluation License, Version 1.0
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: SEL-1.0
// Copyright © 2025 Veda Tech Labs
// Derived from Boring Vault Software © 2025 Veda Tech Labs (TEST ONLY – NO COMMERCIAL USE)
// Licensed under Software Evaluation License, Version 1.0
// 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/",
"@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
}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":"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":[{"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__DepositExceedsCap","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":"operator","type":"address"}],"name":"AllowPermissionedOperator","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":"operator","type":"address"}],"name":"DenyPermissionedOperator","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":false,"internalType":"uint112","name":"cap","type":"uint112"}],"name":"DepositCapSet","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":[{"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":[{"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":[{"indexed":false,"internalType":"bool","name":"permissionedTransfers","type":"bool"}],"name":"PermissionedTransfersSet","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":"operator","type":"address"}],"name":"allowPermissionedOperator","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":"address","name":"","type":"address"}],"name":"beforeTransferData","outputs":[{"internalType":"bool","name":"denyFrom","type":"bool"},{"internalType":"bool","name":"denyTo","type":"bool"},{"internalType":"bool","name":"denyOperator","type":"bool"},{"internalType":"bool","name":"permissionedOperator","type":"bool"},{"internalType":"uint256","name":"shareUnlockTime","type":"uint256"}],"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":"operator","type":"address"}],"name":"denyPermissionedOperator","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":"depositCap","outputs":[{"internalType":"uint112","name":"","type":"uint112"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"depositNonce","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"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":"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":[],"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":[],"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":[],"name":"permissionedTransfers","outputs":[{"internalType":"bool","name":"","type":"bool"}],"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":[{"internalType":"uint112","name":"cap","type":"uint112"}],"name":"setDepositCap","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":"bool","name":"_permissionedTransfers","type":"bool"}],"name":"setPermissionedTransfers","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":"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":"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
6101406040526001600255600480546001600160901b03166001600160901b03191790553480156200002f575f80fd5b506040516200505f3803806200505f83398101604081905262000052916200025d565b5f80546001600160a01b0389166001600160a01b0319918216811783556001805490921690915560405185928592849284928d928d928d928d9286928692869286928692919033907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908490a36040516001600160a01b0382169033907fa3396fd7f6e0a21b50e5089d2da70d5ac0a3bbbd1f617a93f134b76389980198905f90a350506001600160a01b03831660808190526040805163313ce56760e01b8152905163313ce567916004808201926020929091908290030181865afa1580156200013f573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190620001659190620002ed565b6200017290600a62000425565b60c0526001600160a01b0391821660a052811660e0526004805460ff60881b191690558881166101005287169550620001c494505050505057604051632d618d8160e21b815260040160405180910390fd5b6101005160405163ca5eb5e160e01b81526001600160a01b0383811660048301529091169063ca5eb5e1906024015f604051808303815f87803b1580156200020a575f80fd5b505af11580156200021d573d5f803e3d5ffd5b5050506001600160a01b039095166101205250620004359950505050505050505050565b80516001600160a01b038116811462000258575f80fd5b919050565b5f805f805f805f60e0888a03121562000274575f80fd5b6200027f8862000241565b96506200028f6020890162000241565b95506200029f6040890162000241565b9450620002af6060890162000241565b9350620002bf6080890162000241565b9250620002cf60a0890162000241565b9150620002df60c0890162000241565b905092959891949750929550565b5f60208284031215620002fe575f80fd5b815160ff811681146200030f575f80fd5b9392505050565b634e487b7160e01b5f52601160045260245ffd5b600181815b808511156200036a57815f19048211156200034e576200034e62000316565b808516156200035c57918102915b93841c93908002906200032f565b509250929050565b5f8262000382575060016200041f565b816200039057505f6200041f565b8160018114620003a95760028114620003b457620003d4565b60019150506200041f565b60ff841115620003c857620003c862000316565b50506001821b6200041f565b5060208310610133831016604e8410600b8410161715620003f9575081810a6200041f565b6200040583836200032a565b805f19048211156200041b576200041b62000316565b0290505b92915050565b5f6200030f60ff84168362000372565b60805160a05160c05160e0516101005161012051614b416200051e5f395f818161359201526138a901525f818161077c01528181610f68015281816127f801528181613abf01528181613bb901528181613df60152613ead01525f81816103db01528181610d7901528181610df601528181610e440152611b9f01525f81816118820152612ef701525f81816106a5015281816118130152612f1901525f8181610be601528181610e1a015281816118e001528181611bd901528181612c6b01528181613003015281816130c1015281816133ca0152818161346a015261398c0152614b415ff3fe60806040526004361061037c575f3560e01c80637d25a05e116101d3578063bb0b6a53116100fd578063d555f3681161009d578063e83931af1161006d578063e83931af14610b97578063f2fde38b14610bb6578063fbfa77cf14610bd5578063ff7bd03d14610c08575f80fd5b8063d555f36814610afc578063d7424e3314610b1b578063dbd5edc714610b3a578063de35f5cb14610b78575f80fd5b8063c29d2f10116100d8578063c29d2f1014610a3c578063ca5eb5e114610a5b578063cab716e814610a7a578063d182221614610a8d575f80fd5b8063bb0b6a53146109d3578063bf671384146109fe578063bf7e214f14610a1d575f80fd5b80639ac4f42d11610173578063abd626b011610143578063abd626b014610963578063b187bd2614610982578063b5ba6182146109a2578063b92d0eff146109c1575f80fd5b80639ac4f42d146108e05780639d574420146108ff5780639fdb11b61461091e578063a924bf6114610944575f80fd5b80638da5cb5b116101ae5780638da5cb5b146108655780638dfd8ba11461088357806394f51289146108a25780639a94d3d0146108b5575f80fd5b80637d25a05e146107fb5780638456cb59146108325780638a6733f914610846575f80fd5b806334dafd6b116102b457806346b563f4116102545780635e280f11116102245780635e280f111461076b5780635f45bac81461079e5780637a9e5e4b146107bd5780637bd876b6146107dc575f80fd5b806346b563f4146106755780634fb3ccc51461069457806355a2d64d146106c75780635c465430146106e6575f80fd5b80633e64ce991161028f5780633e64ce99146105be5780633f4ba83a146105dd57806341fee44a146105f157806345ad606314610656575f80fd5b806334dafd6b146105615780633b575407146105805780633d935d9e1461059f575f80fd5b806317442b701161031f5780631ba9a458116102fa5780631ba9a458146104e5578063202eac57146105045780632c524c42146105235780633400288b14610542575f80fd5b806317442b701461048757806318aed921146104a75780631b62636c146104c6575f80fd5b80630efe6a8b1161035a5780630efe6a8b1461041557806312056e2d1461043657806313137d65146104555780631568fc5814610468575f80fd5b80630511ef431461038057806305921740146103b55780630b48a8b8146103ca575b5f80fd5b34801561038b575f80fd5b506004546103a090600160881b900460ff1681565b60405190151581526020015b60405180910390f35b6103c86103c336600461404d565b610c27565b005b3480156103d5575f80fd5b506103fd7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016103ac565b6104286104233660046140ca565b610ccd565b6040519081526020016103ac565b348015610441575f80fd5b506103c8610450366004614110565b610ed6565b6103c8610463366004614141565b610f66565b348015610473575f80fd5b506103c8610482366004614202565b611021565b348015610492575f80fd5b506040805160018082526020820152016103ac565b3480156104b2575f80fd5b506103c86104c1366004614233565b6110f6565b3480156104d1575f80fd5b506103c86104e0366004614233565b6111dc565b3480156104f0575f80fd5b506103c86104ff366004614233565b61125c565b34801561050f575f80fd5b506103c861051e36600461424e565b6112d7565b34801561052e575f80fd5b506103c861053d366004614233565b61137e565b34801561054d575f80fd5b506103c861055c366004614283565b6113fa565b34801561056c575f80fd5b506103c861057b3660046142b8565b611439565b34801561058b575f80fd5b506103c861059a366004614233565b61158d565b3480156105aa575f80fd5b506104286105b936600461432f565b61160b565b3480156105c9575f80fd5b506104286105d836600461438f565b611709565b3480156105e8575f80fd5b506103c8611996565b3480156105fc575f80fd5b5061063561060b366004614233565b60036020525f908152604090205460ff8082169161010081049091169062010000900461ffff1683565b604080519315158452911515602084015261ffff16908201526060016103ac565b348015610661575f80fd5b506103c86106703660046143d6565b6119fe565b348015610680575f80fd5b506103c861068f3660046143ef565b611a87565b34801561069f575f80fd5b506103fd7f000000000000000000000000000000000000000000000000000000000000000081565b3480156106d2575f80fd5b506103c86106e13660046143d6565b611c91565b3480156106f1575f80fd5b5061073b610700366004614233565b60066020525f90815260409020805460019091015460ff80831692610100810482169262010000820483169263010000009092049091169085565b6040805195151586529315156020860152911515928401929092529015156060830152608082015260a0016103ac565b348015610776575f80fd5b506103fd7f000000000000000000000000000000000000000000000000000000000000000081565b3480156107a9575f80fd5b506103c86107b8366004614233565b611d37565b3480156107c8575f80fd5b506103c86107d7366004614233565b611db1565b3480156107e7575f80fd5b506103c86107f636600461444f565b611e95565b348015610806575f80fd5b5061081a610815366004614283565b611f27565b6040516001600160401b0390911681526020016103ac565b34801561083d575f80fd5b506103c8611f2f565b348015610851575f80fd5b506103c8610860366004614475565b611f9d565b348015610870575f80fd5b505f546103fd906001600160a01b031681565b34801561088e575f80fd5b506103c861089d366004614490565b61201b565b6104286108b03660046144e4565b612134565b3480156108c0575f80fd5b506104286108cf3660046145a8565b60056020525f908152604090205481565b3480156108eb575f80fd5b506103c86108fa366004614233565b61226d565b34801561090a575f80fd5b5061042861091936600461438f565b6122ef565b348015610929575f80fd5b5060045461081a90600160401b90046001600160401b031681565b34801561094f575f80fd5b506103c861095e366004614233565b6123b4565b34801561096e575f80fd5b506103c861097d3660046145bf565b61242d565b34801561098d575f80fd5b506004546103a090600160801b900460ff1681565b3480156109ad575f80fd5b506103c86109bc366004614607565b61254e565b3480156109cc575f80fd5b50306103fd565b3480156109de575f80fd5b506104286109ed3660046143d6565b60076020525f908152604090205481565b348015610a09575f80fd5b506103c8610a18366004614233565b61264b565b348015610a28575f80fd5b506001546103fd906001600160a01b031681565b348015610a47575f80fd5b506103c8610a56366004614233565b6126c7565b348015610a66575f80fd5b506103c8610a75366004614233565b6127a8565b610428610a88366004614649565b612852565b348015610a98575f80fd5b50610ad6610aa73660046143d6565b60086020525f908152604090205460ff808216916101008104909116906201000090046001600160801b031683565b60408051931515845291151560208401526001600160801b0316908201526060016103ac565b348015610b07575f80fd5b506103c8610b163660046143d6565b612979565b348015610b26575f80fd5b50610428610b353660046146db565b6129f9565b348015610b45575f80fd5b50600454610b6090600160901b90046001600160701b031681565b6040516001600160701b0390911681526020016103ac565b348015610b83575f80fd5b5060045461081a906001600160401b031681565b348015610ba2575f80fd5b506103c8610bb1366004614233565b612a44565b348015610bc1575f80fd5b506103c8610bd0366004614233565b612ad3565b348015610be0575f80fd5b506103fd7f000000000000000000000000000000000000000000000000000000000000000081565b348015610c13575f80fd5b506103a0610c22366004614750565b612b4e565b610c3c335f356001600160e01b031916612b82565b610c615760405162461bcd60e51b8152600401610c589061476a565b60405180910390fd5b600254600114610c835760405162461bcd60e51b8152600401610c5890614790565b60028055600454600160801b900460ff1615610cb25760405163e0f9e71d60e01b815260040160405180910390fd5b610cc0868686868686612c28565b5050600160025550505050565b5f610ce3335f356001600160e01b031916612b82565b610cff5760405162461bcd60e51b8152600401610c589061476a565b600254600114610d215760405162461bcd60e51b8152600401610c5890614790565b600280555f610d2f85612d62565b90505f73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03871601610e6b57345f03610d775760405163259be69560e11b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004015f604051808303818588803b158015610dd0575f80fd5b505af1158015610de2573d5f803e3d5ffd5b50349850610e419350506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691507f0000000000000000000000000000000000000000000000000000000000000000905087612e1d565b507f0000000000000000000000000000000000000000000000000000000000000000945030610e8d565b3415610e8a57604051631cf02cf960e21b815260040160405180910390fd5b50335b610e9b868686843387612e9f565b9250610ec833878786600460089054906101000a90046001600160401b03166001600160401b0316613136565b505060016002559392505050565b610eeb335f356001600160e01b031916612b82565b610f075760405162461bcd60e51b8152600401610c589061476a565b6203f480816001600160401b03161115610f3457604051631fac010160e21b815260040160405180910390fd5b600480546001600160401b03909216600160401b026fffffffffffffffff000000000000000019909216919091179055565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163314610fb1576040516391ac5e4f60e01b8152336004820152602401610c58565b60208701803590610fcb90610fc6908a6143d6565b613268565b1461100957610fdd60208801886143d6565b60405163309afaf360e21b815263ffffffff909116600482015260208801356024820152604401610c58565b611018878787878787876132a3565b50505050505050565b611036335f356001600160e01b031916612b82565b6110525760405162461bcd60e51b8152600401610c589061476a565b806001600160801b03165f0361107b5760405163c80ed59560e01b815260040160405180910390fd5b63ffffffff82165f81815260086020908152604091829020805462010000600160901b031916620100006001600160801b038716908102919091178255835194855291840191909152917f0aa48359f83e8464fda3f4ea4bd3f2d6af01e90b46ab9464aa7d538e1772947a91015b60405180910390a1505050565b61110b335f356001600160e01b031916612b82565b6111275760405162461bcd60e51b8152600401610c589061476a565b6001600160a01b0381165f81815260066020526040808220805462ffffff191662010101179055517fd658022b1a3aaf6ad3b3c615253712807f21a8f7bc3e4996e10618175d4afb2b9190a26040516001600160a01b038216907f79fc685a7dbabb75a67df5e69a90602cef1f19bc465b060eab1ac56685e04a13905f90a26040516001600160a01b038216907f3afb02134e37f7205acf470adc2fc4ebb70614b1599a602d069790915380e2aa905f90a250565b6111f1335f356001600160e01b031916612b82565b61120d5760405162461bcd60e51b8152600401610c589061476a565b6001600160a01b0381165f81815260066020526040808220805462ff0000191662010000179055517f3afb02134e37f7205acf470adc2fc4ebb70614b1599a602d069790915380e2aa9190a250565b611271335f356001600160e01b031916612b82565b61128d5760405162461bcd60e51b8152600401610c589061476a565b6001600160a01b0381165f81815260066020526040808220805462ff000019169055517f77cb944c14da76928795279d1519ce9150085a06e0a53c61d5a86fc4e0fd57c69190a250565b6112ec335f356001600160e01b031916612b82565b6113085760405162461bcd60e51b8152600401610c589061476a565b63ffffffff82165f908152600860205260409020805460ff1916600117815561133a836001600160a01b038416613360565b6040805163ffffffff851681526001600160a01b03841660208201527fe925de263dcdbdc20307c9ab92758ed8cc0edf3d173dad4a3aa54c070f27a54391016110e9565b611393335f356001600160e01b031916612b82565b6113af5760405162461bcd60e51b8152600401610c589061476a565b6001600160a01b0381165f81815260066020526040808220805460ff19166001179055517fd658022b1a3aaf6ad3b3c615253712807f21a8f7bc3e4996e10618175d4afb2b9190a250565b61140f335f356001600160e01b031916612b82565b61142b5760405162461bcd60e51b8152600401610c589061476a565b6114358282613360565b5050565b61144e335f356001600160e01b031916612b82565b61146a5760405162461bcd60e51b8152600401610c589061476a565b82801561147e57506001600160801b038116155b1561149c5760405163c80ed59560e01b815260040160405180910390fd5b60408051606081018252851515815284151560208083019182526001600160801b0385811684860190815263ffffffff8b165f908152600890935294909120925183549251945161ffff1990931690151561ff00191617610100941515949094029390931762010000600160901b03191662010000919093160291909117905561152f856001600160a01b038416613360565b6040805163ffffffff871681528515156020820152841515818301526001600160a01b038416606082015290517f5dbe727bffd24a6d61a5aeef919510389c66c0deeaa82634862cf4f098961fb89181900360800190a15050505050565b6115a2335f356001600160e01b031916612b82565b6115be5760405162461bcd60e51b8152600401610c589061476a565b6001600160a01b0381165f81815260066020526040808220805461ff001916610100179055517f79fc685a7dbabb75a67df5e69a90602cef1f19bc465b060eab1ac56685e04a139190a250565b5f611621335f356001600160e01b031916612b82565b61163d5760405162461bcd60e51b8152600401610c589061476a565b60025460011461165f5760405162461bcd60e51b8152600401610c5890614790565b600280558773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b038216016116a2576040516316df5df960e31b815260040160405180910390fd5b5f6116ac8a612d62565b90506116bc8a8a898989896133ad565b6116ca8a8a8a333386612e9f565b92506116f7338b8b86600460089054906101000a90046001600160401b03166001600160401b0316613136565b50506001600255979650505050505050565b5f61171f335f356001600160e01b031916612b82565b61173b5760405162461bcd60e51b8152600401610c589061476a565b600454600160801b900460ff16156117665760405163e0f9e71d60e01b815260040160405180910390fd5b6001600160a01b0385165f908152600360209081526040918290208251606081018452905460ff80821615158352610100820416151592820183905262010000900461ffff16928101929092526117d05760405163645fd19f60e11b815260040160405180910390fd5b845f036117f057604051630ea3153160e21b815260040160405180910390fd5b604051634104b9ed60e11b81526001600160a01b0387811660048301526118a6917f00000000000000000000000000000000000000000000000000000000000000009091169063820973da90602401602060405180830381865afa15801561185a573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061187e91906147b4565b86907f0000000000000000000000000000000000000000000000000000000000000000613505565b9150838210156118c9576040516302620f6160e61b815260040160405180910390fd5b6040516318457e6160e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906318457e619061191d9086908a90879033908c906004016147cb565b5f604051808303815f87803b158015611934575f80fd5b505af1158015611946573d5f803e3d5ffd5b50505050856001600160a01b03167fdcc60b41ff1c604459e6aa4a7299817416b19fc586a392f111646e26597c4af98660405161198591815260200190565b60405180910390a250949350505050565b6119ab335f356001600160e01b031916612b82565b6119c75760405162461bcd60e51b8152600401610c589061476a565b6004805460ff60801b191690556040517fa45f47fdea8a1efdd9029a5691c7f759c32b7c698632b563573e155625d16933905f90a1565b611a13335f356001600160e01b031916612b82565b611a2f5760405162461bcd60e51b8152600401610c589061476a565b63ffffffff81165f81815260086020908152604091829020805461ff0019168155915192835290917fc45af64a13a09ef916a1114c59589294ec9c3095f2bfbbb093a7a96656858ded91015b60405180910390a15050565b611a9c335f356001600160e01b031916612b82565b611ab85760405162461bcd60e51b8152600401610c589061476a565b80611ac38342614812565b10611ae157604051634c1eef1760e11b815260040160405180910390fd5b604080516001600160a01b038089166020830152871691810191909152606081018590526080810184905260a0810183905260c081018290525f9060e00160408051601f1981840301815291815281516020928301205f8b815260059093529120549091508114611b655760405163fa174ecb60e01b815260040160405180910390fd5b5f888152600560205260408120556001600160a01b03861673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14611b9d5785611bbf565b7f00000000000000000000000000000000000000000000000000000000000000005b6040516318457e6160e01b81529096506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906318457e6190611c16908a908a908a9083908b906004016147cb565b5f604051808303815f87803b158015611c2d575f80fd5b505af1158015611c3f573d5f803e3d5ffd5b50505050866001600160a01b0316887faf98ea774275cadfa3e477a7b52cba03e01197445a76bd5d0d561608708c362483604051611c7f91815260200190565b60405180910390a35050505050505050565b611ca6335f356001600160e01b031916612b82565b611cc25760405162461bcd60e51b8152600401610c589061476a565b63ffffffff81165f908152600860205260408120805471ffffffffffffffffffffffffffffffffffff19169055611cfa908290613360565b60405163ffffffff821681527f11a9d1a77f76361ed131c19b1dc5758504c51dbde2e49fc973a0ef9577ad13d5906020015b60405180910390a150565b611d4c335f356001600160e01b031916612b82565b611d685760405162461bcd60e51b8152600401610c589061476a565b6001600160a01b0381165f81815260066020526040808220805461ff0019169055517f039bcf51833310242b8b7c6aa0fbabf1bf2b5e5270807ee020f1920ef200666b9190a250565b5f546001600160a01b0316331480611e42575060015460405163b700961360e01b81526001600160a01b039091169063b700961390611e0390339030906001600160e01b03195f351690600401614825565b602060405180830381865afa158015611e1e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e429190614852565b611e4a575f80fd5b600180546001600160a01b0319166001600160a01b03831690811790915560405133907fa3396fd7f6e0a21b50e5089d2da70d5ac0a3bbbd1f617a93f134b76389980198905f90a350565b611eaa335f356001600160e01b031916612b82565b611ec65760405162461bcd60e51b8152600401610c589061476a565b6004805471ffffffffffffffffffffffffffffffffffff16600160901b6001600160701b038416908102919091179091556040519081527f752cd3d8df6864142257fa3a2e02aedf2dc09f1875c2a25b4f117d45c7334d5d90602001611d2c565b5f5b92915050565b611f44335f356001600160e01b031916612b82565b611f605760405162461bcd60e51b8152600401610c589061476a565b6004805460ff60801b1916600160801b1790556040517f9e87fac88ff661f02d44f95383c817fece4bce600a3dab7a54406878b965e752905f90a1565b611fb2335f356001600160e01b031916612b82565b611fce5760405162461bcd60e51b8152600401610c589061476a565b60048054821515600160881b0260ff60881b199091161790556040517fa3fe47e2502292ca20854524008d366d3cad5da2426cfb2484099f06f328e4a090611d2c90831515815260200190565b612030335f356001600160e01b031916612b82565b61204c5760405162461bcd60e51b8152600401610c589061476a565b6103e861ffff8216111561207357604051636c5cde8760e01b815260040160405180910390fd5b6040805160608082018352851515808352851515602080850182815261ffff8881168789018181526001600160a01b038e165f818152600387528b902099518a549551925161ffff1990961690151561ff00191617610100921515929092029190911763ffff0000191662010000949093169390930291909117909655865193845290830191909152938101929092527fe08301321781ac43935a2099b2c3fd42de0a0ee87a519cac00e8c9cecd26ff12910160405180910390a250505050565b5f61214a335f356001600160e01b031916612b82565b6121665760405162461bcd60e51b8152600401610c589061476a565b6002546001146121885760405162461bcd60e51b8152600401610c5890614790565b600280558c73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b038216016121cb576040516316df5df960e31b815260040160405180910390fd5b5f6121d58f612d62565b90506121e58f8f8e8e8e8e6133ad565b6121f38f8f8f333386612e9f565b925050612221338f8f85600460089054906101000a90046001600160401b03166001600160401b0316613136565b6001600160601b03821115612249576040516389588ab360e01b815260040160405180910390fd5b612257828888888888612c28565b5060016002559c9b505050505050505050505050565b612282335f356001600160e01b031916612b82565b61229e5760405162461bcd60e51b8152600401610c589061476a565b6001600160a01b0381165f81815260066020526040808220805463ff00000019166301000000179055517f5e92c085dffcb69d025c31c9ed03d1869e4737ba81e8649c623398caa1b72f159190a250565b5f612305335f356001600160e01b031916612b82565b6123215760405162461bcd60e51b8152600401610c589061476a565b6002546001146123435760405162461bcd60e51b8152600401610c5890614790565b600280555f61235186612d62565b9050612361868686338786612e9f565b9150856001600160a01b03167f6f9b974223f85a1ae805c33b8b519039e2435481d949db1110de151a94d587af8660405161239e91815260200190565b60405180910390a2506001600255949350505050565b6123c9335f356001600160e01b031916612b82565b6123e55760405162461bcd60e51b8152600401610c589061476a565b6001600160a01b0381165f81815260066020526040808220805460ff19169055517fae893dda71e2eee548f8291f458cceae4bd22b56a79906928591e4420444c0e99190a250565b6001600160a01b0383165f9081526006602052604090205460ff168061246f57506001600160a01b0382165f90815260066020526040902054610100900460ff165b8061249757506001600160a01b0381165f9081526006602052604090205462010000900460ff165b806124d55750600454600160881b900460ff1680156124d557506001600160a01b0381165f908152600660205260409020546301000000900460ff16155b1561250e57604051632821264f60e01b81526001600160a01b038085166004830152808416602483015282166044820152606401610c58565b6001600160a01b0383165f908152600660205260409020600101544210156125495760405163f64059db60e01b815260040160405180910390fd5b505050565b612563335f356001600160e01b031916612b82565b61257f5760405162461bcd60e51b8152600401610c589061476a565b806001600160801b03165f036125a85760405163c80ed59560e01b815260040160405180910390fd5b63ffffffff83165f908152600860205260409020805461010071ffffffffffffffffffffffffffffffffff0019909116620100006001600160801b03851602171781556125fe846001600160a01b038516613360565b6040805163ffffffff861681526001600160a01b03851660208201527f34fe916485e02ec88e487b0e611e5c9bacabba9e3eaae7a900aa08be8197d419910160405180910390a150505050565b612660335f356001600160e01b031916612b82565b61267c5760405162461bcd60e51b8152600401610c589061476a565b6001600160a01b0381165f81815260066020526040808220805463ff00000019169055517f1c2a701d65e1c6e2860263c884eae0b10db82e3ddd60640d53c7d53c6c998e799190a250565b6126dc335f356001600160e01b031916612b82565b6126f85760405162461bcd60e51b8152600401610c589061476a565b6001600160a01b0381165f81815260066020526040808220805462ffffff19169055517fae893dda71e2eee548f8291f458cceae4bd22b56a79906928591e4420444c0e99190a26040516001600160a01b038216907f039bcf51833310242b8b7c6aa0fbabf1bf2b5e5270807ee020f1920ef200666b905f90a26040516001600160a01b038216907f77cb944c14da76928795279d1519ce9150085a06e0a53c61d5a86fc4e0fd57c6905f90a250565b6127bd335f356001600160e01b031916612b82565b6127d95760405162461bcd60e51b8152600401610c589061476a565b60405163ca5eb5e160e01b81526001600160a01b0382811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063ca5eb5e1906024015f604051808303815f87803b158015612839575f80fd5b505af115801561284b573d5f803e3d5ffd5b5050505050565b5f612868335f356001600160e01b031916612b82565b6128845760405162461bcd60e51b8152600401610c589061476a565b6002546001146128a65760405162461bcd60e51b8152600401610c5890614790565b600280558873eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b038216016128e9576040516316df5df960e31b815260040160405180910390fd5b5f6128f38b612d62565b90506129038b8b8b333386612e9f565b9250612930338c8c86600460089054906101000a90046001600160401b03166001600160401b0316613136565b6001600160601b03831115612958576040516389588ab360e01b815260040160405180910390fd5b612966838989898989612c28565b5050600160025598975050505050505050565b61298e335f356001600160e01b031916612b82565b6129aa5760405162461bcd60e51b8152600401610c589061476a565b63ffffffff81165f81815260086020908152604091829020805460ff19168155915192835290917f1cb867ed6a020e020ea220d4f48bb8e36552abf9095e093e377d33933f2b31e49101611a7b565b604080518082019091526001600160601b03861681526001600160a01b03851660208201525f9081612a2a82613520565b9050612a3881878787613567565b98975050505050505050565b6001600160a01b0381165f9081526006602052604090205460ff1615612a9557604051632821264f60e01b81526001600160a01b03821660048201525f602482018190526044820152606401610c58565b6001600160a01b0381165f90815260066020526040902060010154421015612ad05760405163f64059db60e01b815260040160405180910390fd5b50565b612ae8335f356001600160e01b031916612b82565b612b045760405162461bcd60e51b8152600401610c589061476a565b5f80546001600160a01b0319166001600160a01b0383169081178255604051909133917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a350565b5f602082018035906007908390612b6590866143d6565b63ffffffff16815260208101919091526040015f20541492915050565b6001545f906001600160a01b03168015801590612c09575060405163b700961360e01b81526001600160a01b0382169063b700961390612bca90879030908890600401614825565b602060405180830381865afa158015612be5573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612c099190614852565b80612c2057505f546001600160a01b038581169116145b949350505050565b612c33335f3361242d565b6040516318457e6160e01b81525f600482018190526024820181905260448201523360648201526001600160601b03871660848201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906318457e619060a4015f604051808303815f87803b158015612cb4575f80fd5b505af1158015612cc6573d5f803e3d5ffd5b5050604080518082019091526001600160601b03891681526001600160a01b038816602082015291505f9050612cfb82613520565b90505f612d0b8288888888613736565b6040516001600160601b038b1681529091506001600160a01b0389169082907fe0ec62d39b054dc2fd626dbc271483735df6e6fa1ef8389754bf8ab27a75eab29060200160405180910390a3505050505050505050565b604080516060810182525f8082526020820181905291810191909152600454600160801b900460ff1615612da95760405163e0f9e71d60e01b815260040160405180910390fd5b506001600160a01b0381165f908152600360209081526040918290208251606081018452905460ff8082161515808452610100830490911615159383019390935262010000900461ffff1692810192909252612e185760405163645fd19f60e11b815260040160405180910390fd5b919050565b5f60405163095ea7b360e01b81526001600160a01b038416600482015282602482015260205f6044835f895af13d15601f3d1160015f511416171691505080612e995760405162461bcd60e51b815260206004820152600e60248201526d1054141493d59157d1905253115160921b6044820152606401610c58565b50505050565b6004545f90600160901b90046001600160701b0316868203612ed45760405163259be69560e11b815260040160405180910390fd5b604051634104b9ed60e11b81526001600160a01b038981166004830152612f8a917f0000000000000000000000000000000000000000000000000000000000000000917f0000000000000000000000000000000000000000000000000000000000000000169063820973da90602401602060405180830381865afa158015612f5e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612f8291906147b4565b899190613505565b91505f836040015161ffff1611612fa15781612fc4565b612fc48360400151612710612fb6919061486d565b839061ffff16612710613505565b915085821015612fe75760405163097b2ad560e31b815260040160405180910390fd5b6001600160701b03818116146130aa57806001600160701b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561305d573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061308191906147b4565b61308b908461488f565b11156130aa5760405163ed32f3bb60e01b815260040160405180910390fd5b604051631ceb5d1960e11b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906339d6ba32906130fe9088908c908c908a9089906004016147cb565b5f604051808303815f87803b158015613115575f80fd5b505af1158015613127573d5f803e3d5ffd5b50505050509695505050505050565b600480545f91908290613151906001600160401b03166148a2565b82546001600160401b039182166101009390930a8381029202191617909155905081156131f857613182824261488f565b6001600160a01b038781165f81815260066020908152604091829020600101949094558051938401919091529087169082015260608101859052608081018490524260a082015260c0810183905260e00160408051601f1981840301815291815281516020928301205f84815260059093529120555b846001600160a01b0316866001600160a01b0316827fe96d7872363f475d18b2f5390caaa5eaa96b2d38e42c62afe4ac08ebd2b13c3a87874288604051613258949392919093845260208401929092526040830152606082015260800190565b60405180910390a4505050505050565b63ffffffff81165f9081526007602052604081205480611f295760405163f6ff4fb760e01b815263ffffffff84166004820152602401610c58565b5f6008816132b460208b018b6143d6565b63ffffffff16815260208082019290925260409081015f208151606081018352905460ff808216151580845261010083049091161515948301949094526201000090046001600160801b031691810191909152915061333c5761331a60208901896143d6565b6040516315b73a2960e21b815263ffffffff9091166004820152602401610c58565b5f613349868801886145a8565b90506133558882613959565b505050505050505050565b63ffffffff82165f81815260076020908152604091829020849055815192835282018390527f238399d427b947898edb290f5ff0f9109849b1c3ba196a42e35f00c50a54b98b9101611a7b565b60405163d505accf60e01b81523360048201526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166024830152604482018790526064820186905260ff8516608483015260a4820184905260c4820183905287169063d505accf9060e4015f604051808303815f87803b158015613438575f80fd5b505af1925050508015613449575060015b6134fd57604051636eb1769f60e11b81523360048201526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116602483015286919088169063dd62ed3e90604401602060405180830381865afa1580156134ba573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906134de91906147b4565b10156134fd576040516301b8851f60e41b815260040160405180910390fd5b505050505050565b5f825f190484118302158202613519575f80fd5b5091020490565b80515f906001600160601b03101561354b57604051633524486360e01b815260040160405180910390fd5b81516020909201516001600160a01b031660a09290921b171790565b5f6001600160a01b03821673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee148015906135c757507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031614155b156135e557604051637f3cd08160e11b815260040160405180910390fd5b5f6135f2848601866143d6565b63ffffffff81165f908152600860209081526040918290208251606081018452905460ff8082161515835261010082041615159282018390526201000090046001600160801b0316928101929092529192509061366a5760405163420eae3760e01b815263ffffffff83166004820152602401610c58565b5f8760405160200161367e91815260200190565b60405160208183030381529060405290505f6136c683604001515f6136bf60408051600360f01b602082015281516002818303018152602290910190915290565b9190613a45565b90505f6136f58584846001600160a01b038b1673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1415613aaa565b90506001600160a01b03871673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14613725578060200151613728565b80515b9a9950505050505050505050565b5f80613744858701876143d6565b63ffffffff81165f908152600860209081526040918290208251606081018452905460ff8082161515835261010082041615159282018390526201000090046001600160801b031692810192909252919250906137bc5760405163420eae3760e01b815263ffffffff83166004820152602401610c58565b5f886040516020016137d091815260200190565b60405160208183030381529060405290505f61381183604001515f6136bf60408051600360f01b602082015281516002818303018152602290910190915290565b90505f6138408584846001600160a01b038c1673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1415613aaa565b905073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b038916016138a75780518710156138a257805160405163f5ac3fa760e01b815263ffffffff87166004820152602481019190915260448101889052606401610c58565b61393a565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316886001600160a01b0316036139215786816020015111156138a257602081015160405163f5ac3fa760e01b815263ffffffff87166004820152602481019190915260448101889052606401610c58565b604051637f3cd08160e11b815260040160405180910390fd5b5f6139488685858533613b88565b519c9b505050505050505050505050565b60408051808201825260a083901c8082526001600160a01b03808516602084018190529351631ceb5d1960e11b815292937f0000000000000000000000000000000000000000000000000000000000000000909116926339d6ba32926139c8925f9283928392916004016147cb565b5f604051808303815f87803b1580156139df575f80fd5b505af11580156139f1573d5f803e3d5ffd5b5050505080602001516001600160a01b0316837fb944fddc61d7fedb8b736790454ba972000703b0d21c7481d6dbf95b7c2cc2f1835f0151604051613a3891815260200190565b60405180910390a3505050565b6060836003613a54825f613c8e565b61ffff1614613a8757613a67815f613c8e565b604051633a51740d60e01b815261ffff9091166004820152602401610c58565b5f613a928585613cea565b9050613aa086600183613d63565b9695505050505050565b604080518082019091525f80825260208201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663ddc28c586040518060a001604052808863ffffffff168152602001613b0c89613268565b8152602001878152602001868152602001851515815250306040518363ffffffff1660e01b8152600401613b41929190614914565b6040805180830381865afa158015613b5b573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613b7f91906149e4565b95945050505050565b613b90613f91565b5f613b9d845f0151613dcc565b602085015190915015613bb757613bb78460200151613df3565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316632637a450826040518060a001604052808b63ffffffff168152602001613c078c613268565b81526020018a81526020018981526020015f8960200151111515815250866040518463ffffffff1660e01b8152600401613c42929190614914565b60806040518083038185885af1158015613c5e573d5f803e3d5ffd5b50505050506040513d601f19601f82011682018060405250810190613c8391906149fe565b979650505050505050565b5f613c9a82600261488f565b83511015613ce15760405162461bcd60e51b8152602060048201526014602482015273746f55696e7431365f6f75744f66426f756e647360601b6044820152606401610c58565b50016002015190565b60606001600160801b03821615613d3257604080516001600160801b0319608086811b8216602084015285901b16603082015201604051602081830303815290604052613d5c565b6040516001600160801b0319608085901b1660208201526030016040516020818303038152906040525b9392505050565b6060836003613d72825f613c8e565b61ffff1614613d8557613a67815f613c8e565b846001613d928551613ed2565b613d9d906001614a6f565b8686604051602001613db3959493929190614a8a565b6040516020818303038152906040529150509392505050565b5f813414613def576040516304fb820960e51b8152346004820152602401610c58565b5090565b5f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e4fe1d946040518163ffffffff1660e01b8152600401602060405180830381865afa158015613e50573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613e749190614af0565b90506001600160a01b038116613e9d576040516329b99a9560e11b815260040160405180910390fd5b6114356001600160a01b038216337f000000000000000000000000000000000000000000000000000000000000000085613f00565b5f61ffff821115613def576040516306dfcc6560e41b81526010600482015260248101839052604401610c58565b5f6040516323b872dd60e01b81526001600160a01b03851660048201526001600160a01b038416602482015282604482015260205f6064835f8a5af13d15601f3d1160015f51141617169150508061284b5760405162461bcd60e51b81526020600482015260146024820152731514905394d1915497d19493d357d1905253115160621b6044820152606401610c58565b60405180606001604052805f80191681526020015f6001600160401b03168152602001613fcf60405180604001604052805f81526020015f81525090565b905290565b80356001600160601b0381168114612e18575f80fd5b6001600160a01b0381168114612ad0575f80fd5b8035612e1881613fea565b5f8083601f840112614019575f80fd5b5081356001600160401b0381111561402f575f80fd5b602083019150836020828501011115614046575f80fd5b9250929050565b5f805f805f8060a08789031215614062575f80fd5b61406b87613fd4565b9550602087013561407b81613fea565b945060408701356001600160401b03811115614095575f80fd5b6140a189828a01614009565b90955093505060608701356140b581613fea565b80925050608087013590509295509295509295565b5f805f606084860312156140dc575f80fd5b83356140e781613fea565b95602085013595506040909401359392505050565b6001600160401b0381168114612ad0575f80fd5b5f60208284031215614120575f80fd5b8135613d5c816140fc565b5f6060828403121561413b575f80fd5b50919050565b5f805f805f805f60e0888a031215614157575f80fd5b614161898961412b565b96506060880135955060808801356001600160401b0380821115614183575f80fd5b61418f8b838c01614009565b909750955060a08a013591506141a482613fea565b90935060c089013590808211156141b9575f80fd5b506141c68a828b01614009565b989b979a50959850939692959293505050565b803563ffffffff81168114612e18575f80fd5b80356001600160801b0381168114612e18575f80fd5b5f8060408385031215614213575f80fd5b61421c836141d9565b915061422a602084016141ec565b90509250929050565b5f60208284031215614243575f80fd5b8135613d5c81613fea565b5f806040838503121561425f575f80fd5b614268836141d9565b9150602083013561427881613fea565b809150509250929050565b5f8060408385031215614294575f80fd5b61429d836141d9565b946020939093013593505050565b8015158114612ad0575f80fd5b5f805f805f60a086880312156142cc575f80fd5b6142d5866141d9565b945060208601356142e5816142ab565b935060408601356142f5816142ab565b9250606086013561430581613fea565b9150614313608087016141ec565b90509295509295909350565b803560ff81168114612e18575f80fd5b5f805f805f805f60e0888a031215614345575f80fd5b873561435081613fea565b96506020880135955060408801359450606088013593506143736080890161431f565b925060a0880135915060c0880135905092959891949750929550565b5f805f80608085870312156143a2575f80fd5b84356143ad81613fea565b9350602085013592506040850135915060608501356143cb81613fea565b939692955090935050565b5f602082840312156143e6575f80fd5b613d5c826141d9565b5f805f805f805f60e0888a031215614405575f80fd5b87359650602088013561441781613fea565b9550604088013561442781613fea565b969995985095966060810135965060808101359560a0820135955060c0909101359350915050565b5f6020828403121561445f575f80fd5b81356001600160701b0381168114613d5c575f80fd5b5f60208284031215614485575f80fd5b8135613d5c816142ab565b5f805f80608085870312156144a3575f80fd5b84356144ae81613fea565b935060208501356144be816142ab565b925060408501356144ce816142ab565b9150606085013561ffff811681146143cb575f80fd5b5f805f805f805f805f805f806101608d8f031215614500575f80fd5b61450a8d35613fea565b8c359b5060208d01359a5060408d0135995060608d0135985061452f60808e0161431f565b975060a08d0135965060c08d0135955061454c60e08e0135613fea565b60e08d013594506001600160401b036101008e0135111561456b575f80fd5b61457c8e6101008f01358f01614009565b909450925061458e6101208e01613ffe565b91506101408d013590509295989b509295989b509295989b565b5f602082840312156145b8575f80fd5b5035919050565b5f805f606084860312156145d1575f80fd5b83356145dc81613fea565b925060208401356145ec81613fea565b915060408401356145fc81613fea565b809150509250925092565b5f805f60608486031215614619575f80fd5b614622846141d9565b9250602084013561463281613fea565b9150614640604085016141ec565b90509250925092565b5f805f805f805f8060e0898b031215614660575f80fd5b883561466b81613fea565b97506020890135965060408901359550606089013561468981613fea565b945060808901356001600160401b038111156146a3575f80fd5b6146af8b828c01614009565b90955093505060a08901356146c381613fea565b8092505060c089013590509295985092959890939650565b5f805f805f608086880312156146ef575f80fd5b6146f886613fd4565b9450602086013561470881613fea565b935060408601356001600160401b03811115614722575f80fd5b61472e88828901614009565b909450925050606086013561474281613fea565b809150509295509295909350565b5f60608284031215614760575f80fd5b613d5c838361412b565b6020808252600c908201526b15539055551213d49256915160a21b604082015260600190565b6020808252600a90820152695245454e5452414e435960b01b604082015260600190565b5f602082840312156147c4575f80fd5b5051919050565b6001600160a01b039586168152938516602085015260408401929092529092166060820152608081019190915260a00190565b634e487b7160e01b5f52601160045260245ffd5b81810381811115611f2957611f296147fe565b6001600160a01b0393841681529190921660208201526001600160e01b0319909116604082015260600190565b5f60208284031215614862575f80fd5b8151613d5c816142ab565b61ffff828116828216039080821115614888576148886147fe565b5092915050565b80820180821115611f2957611f296147fe565b5f6001600160401b038083168181036148bd576148bd6147fe565b6001019392505050565b5f5b838110156148e15781810151838201526020016148c9565b50505f910152565b5f81518084526149008160208601602086016148c7565b601f01601f19169290920160200192915050565b6040815263ffffffff8351166040820152602083015160608201525f604084015160a0608084015261494960e08401826148e9565b90506060850151603f198483030160a085015261496682826148e9565b60809690960151151560c08501525050506001600160a01b039190911660209091015290565b5f6040828403121561499c575f80fd5b604051604081018181106001600160401b03821117156149ca57634e487b7160e01b5f52604160045260245ffd5b604052825181526020928301519281019290925250919050565b5f604082840312156149f4575f80fd5b613d5c838361498c565b5f60808284031215614a0e575f80fd5b604051606081018181106001600160401b0382111715614a3c57634e487b7160e01b5f52604160045260245ffd5b604052825181526020830151614a51816140fc565b6020820152614a63846040850161498c565b60408201529392505050565b61ffff818116838216019080821115614888576148886147fe565b5f8651614a9b818460208b016148c7565b6001600160f81b031960f888811b82169285019283526001600160f01b031960f089901b16600184015286901b1660038201528351614ae18160048401602088016148c7565b01600401979650505050505050565b5f60208284031215614b00575f80fd5b8151613d5c81613fea56fea2646970667358221220f5570434782225bc2c1529ea0f26bf6133d284dc6630e0b39289269f853cb6fd64736f6c634300081500330000000000000000000000005f2f11ad8656439d5c14d9b351f8b09cdac2a02d000000000000000000000000ef417fce1883c6653e7dc6af7c6f85ccde84aa09000000000000000000000000c873f2b7b3ba0a7faa2b56e210e3b965f2b618f5000000000000000000000000ee7d8bcfb72bc1880d0cf19822eb0a2e6577ab620000000000000000000000006f475642a6e85809b1c36fa62763669b1b48dd5b0000000000000000000000005f2f11ad8656439d5c14d9b351f8b09cdac2a02d0000000000000000000000000000000000000000000000000000000000000001
Deployed Bytecode
0x60806040526004361061037c575f3560e01c80637d25a05e116101d3578063bb0b6a53116100fd578063d555f3681161009d578063e83931af1161006d578063e83931af14610b97578063f2fde38b14610bb6578063fbfa77cf14610bd5578063ff7bd03d14610c08575f80fd5b8063d555f36814610afc578063d7424e3314610b1b578063dbd5edc714610b3a578063de35f5cb14610b78575f80fd5b8063c29d2f10116100d8578063c29d2f1014610a3c578063ca5eb5e114610a5b578063cab716e814610a7a578063d182221614610a8d575f80fd5b8063bb0b6a53146109d3578063bf671384146109fe578063bf7e214f14610a1d575f80fd5b80639ac4f42d11610173578063abd626b011610143578063abd626b014610963578063b187bd2614610982578063b5ba6182146109a2578063b92d0eff146109c1575f80fd5b80639ac4f42d146108e05780639d574420146108ff5780639fdb11b61461091e578063a924bf6114610944575f80fd5b80638da5cb5b116101ae5780638da5cb5b146108655780638dfd8ba11461088357806394f51289146108a25780639a94d3d0146108b5575f80fd5b80637d25a05e146107fb5780638456cb59146108325780638a6733f914610846575f80fd5b806334dafd6b116102b457806346b563f4116102545780635e280f11116102245780635e280f111461076b5780635f45bac81461079e5780637a9e5e4b146107bd5780637bd876b6146107dc575f80fd5b806346b563f4146106755780634fb3ccc51461069457806355a2d64d146106c75780635c465430146106e6575f80fd5b80633e64ce991161028f5780633e64ce99146105be5780633f4ba83a146105dd57806341fee44a146105f157806345ad606314610656575f80fd5b806334dafd6b146105615780633b575407146105805780633d935d9e1461059f575f80fd5b806317442b701161031f5780631ba9a458116102fa5780631ba9a458146104e5578063202eac57146105045780632c524c42146105235780633400288b14610542575f80fd5b806317442b701461048757806318aed921146104a75780631b62636c146104c6575f80fd5b80630efe6a8b1161035a5780630efe6a8b1461041557806312056e2d1461043657806313137d65146104555780631568fc5814610468575f80fd5b80630511ef431461038057806305921740146103b55780630b48a8b8146103ca575b5f80fd5b34801561038b575f80fd5b506004546103a090600160881b900460ff1681565b60405190151581526020015b60405180910390f35b6103c86103c336600461404d565b610c27565b005b3480156103d5575f80fd5b506103fd7f000000000000000000000000ee7d8bcfb72bc1880d0cf19822eb0a2e6577ab6281565b6040516001600160a01b0390911681526020016103ac565b6104286104233660046140ca565b610ccd565b6040519081526020016103ac565b348015610441575f80fd5b506103c8610450366004614110565b610ed6565b6103c8610463366004614141565b610f66565b348015610473575f80fd5b506103c8610482366004614202565b611021565b348015610492575f80fd5b506040805160018082526020820152016103ac565b3480156104b2575f80fd5b506103c86104c1366004614233565b6110f6565b3480156104d1575f80fd5b506103c86104e0366004614233565b6111dc565b3480156104f0575f80fd5b506103c86104ff366004614233565b61125c565b34801561050f575f80fd5b506103c861051e36600461424e565b6112d7565b34801561052e575f80fd5b506103c861053d366004614233565b61137e565b34801561054d575f80fd5b506103c861055c366004614283565b6113fa565b34801561056c575f80fd5b506103c861057b3660046142b8565b611439565b34801561058b575f80fd5b506103c861059a366004614233565b61158d565b3480156105aa575f80fd5b506104286105b936600461432f565b61160b565b3480156105c9575f80fd5b506104286105d836600461438f565b611709565b3480156105e8575f80fd5b506103c8611996565b3480156105fc575f80fd5b5061063561060b366004614233565b60036020525f908152604090205460ff8082169161010081049091169062010000900461ffff1683565b604080519315158452911515602084015261ffff16908201526060016103ac565b348015610661575f80fd5b506103c86106703660046143d6565b6119fe565b348015610680575f80fd5b506103c861068f3660046143ef565b611a87565b34801561069f575f80fd5b506103fd7f000000000000000000000000c873f2b7b3ba0a7faa2b56e210e3b965f2b618f581565b3480156106d2575f80fd5b506103c86106e13660046143d6565b611c91565b3480156106f1575f80fd5b5061073b610700366004614233565b60066020525f90815260409020805460019091015460ff80831692610100810482169262010000820483169263010000009092049091169085565b6040805195151586529315156020860152911515928401929092529015156060830152608082015260a0016103ac565b348015610776575f80fd5b506103fd7f0000000000000000000000006f475642a6e85809b1c36fa62763669b1b48dd5b81565b3480156107a9575f80fd5b506103c86107b8366004614233565b611d37565b3480156107c8575f80fd5b506103c86107d7366004614233565b611db1565b3480156107e7575f80fd5b506103c86107f636600461444f565b611e95565b348015610806575f80fd5b5061081a610815366004614283565b611f27565b6040516001600160401b0390911681526020016103ac565b34801561083d575f80fd5b506103c8611f2f565b348015610851575f80fd5b506103c8610860366004614475565b611f9d565b348015610870575f80fd5b505f546103fd906001600160a01b031681565b34801561088e575f80fd5b506103c861089d366004614490565b61201b565b6104286108b03660046144e4565b612134565b3480156108c0575f80fd5b506104286108cf3660046145a8565b60056020525f908152604090205481565b3480156108eb575f80fd5b506103c86108fa366004614233565b61226d565b34801561090a575f80fd5b5061042861091936600461438f565b6122ef565b348015610929575f80fd5b5060045461081a90600160401b90046001600160401b031681565b34801561094f575f80fd5b506103c861095e366004614233565b6123b4565b34801561096e575f80fd5b506103c861097d3660046145bf565b61242d565b34801561098d575f80fd5b506004546103a090600160801b900460ff1681565b3480156109ad575f80fd5b506103c86109bc366004614607565b61254e565b3480156109cc575f80fd5b50306103fd565b3480156109de575f80fd5b506104286109ed3660046143d6565b60076020525f908152604090205481565b348015610a09575f80fd5b506103c8610a18366004614233565b61264b565b348015610a28575f80fd5b506001546103fd906001600160a01b031681565b348015610a47575f80fd5b506103c8610a56366004614233565b6126c7565b348015610a66575f80fd5b506103c8610a75366004614233565b6127a8565b610428610a88366004614649565b612852565b348015610a98575f80fd5b50610ad6610aa73660046143d6565b60086020525f908152604090205460ff808216916101008104909116906201000090046001600160801b031683565b60408051931515845291151560208401526001600160801b0316908201526060016103ac565b348015610b07575f80fd5b506103c8610b163660046143d6565b612979565b348015610b26575f80fd5b50610428610b353660046146db565b6129f9565b348015610b45575f80fd5b50600454610b6090600160901b90046001600160701b031681565b6040516001600160701b0390911681526020016103ac565b348015610b83575f80fd5b5060045461081a906001600160401b031681565b348015610ba2575f80fd5b506103c8610bb1366004614233565b612a44565b348015610bc1575f80fd5b506103c8610bd0366004614233565b612ad3565b348015610be0575f80fd5b506103fd7f000000000000000000000000ef417fce1883c6653e7dc6af7c6f85ccde84aa0981565b348015610c13575f80fd5b506103a0610c22366004614750565b612b4e565b610c3c335f356001600160e01b031916612b82565b610c615760405162461bcd60e51b8152600401610c589061476a565b60405180910390fd5b600254600114610c835760405162461bcd60e51b8152600401610c5890614790565b60028055600454600160801b900460ff1615610cb25760405163e0f9e71d60e01b815260040160405180910390fd5b610cc0868686868686612c28565b5050600160025550505050565b5f610ce3335f356001600160e01b031916612b82565b610cff5760405162461bcd60e51b8152600401610c589061476a565b600254600114610d215760405162461bcd60e51b8152600401610c5890614790565b600280555f610d2f85612d62565b90505f73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03871601610e6b57345f03610d775760405163259be69560e11b815260040160405180910390fd5b7f000000000000000000000000ee7d8bcfb72bc1880d0cf19822eb0a2e6577ab626001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004015f604051808303818588803b158015610dd0575f80fd5b505af1158015610de2573d5f803e3d5ffd5b50349850610e419350506001600160a01b037f000000000000000000000000ee7d8bcfb72bc1880d0cf19822eb0a2e6577ab621691507f000000000000000000000000ef417fce1883c6653e7dc6af7c6f85ccde84aa09905087612e1d565b507f000000000000000000000000ee7d8bcfb72bc1880d0cf19822eb0a2e6577ab62945030610e8d565b3415610e8a57604051631cf02cf960e21b815260040160405180910390fd5b50335b610e9b868686843387612e9f565b9250610ec833878786600460089054906101000a90046001600160401b03166001600160401b0316613136565b505060016002559392505050565b610eeb335f356001600160e01b031916612b82565b610f075760405162461bcd60e51b8152600401610c589061476a565b6203f480816001600160401b03161115610f3457604051631fac010160e21b815260040160405180910390fd5b600480546001600160401b03909216600160401b026fffffffffffffffff000000000000000019909216919091179055565b7f0000000000000000000000006f475642a6e85809b1c36fa62763669b1b48dd5b6001600160a01b03163314610fb1576040516391ac5e4f60e01b8152336004820152602401610c58565b60208701803590610fcb90610fc6908a6143d6565b613268565b1461100957610fdd60208801886143d6565b60405163309afaf360e21b815263ffffffff909116600482015260208801356024820152604401610c58565b611018878787878787876132a3565b50505050505050565b611036335f356001600160e01b031916612b82565b6110525760405162461bcd60e51b8152600401610c589061476a565b806001600160801b03165f0361107b5760405163c80ed59560e01b815260040160405180910390fd5b63ffffffff82165f81815260086020908152604091829020805462010000600160901b031916620100006001600160801b038716908102919091178255835194855291840191909152917f0aa48359f83e8464fda3f4ea4bd3f2d6af01e90b46ab9464aa7d538e1772947a91015b60405180910390a1505050565b61110b335f356001600160e01b031916612b82565b6111275760405162461bcd60e51b8152600401610c589061476a565b6001600160a01b0381165f81815260066020526040808220805462ffffff191662010101179055517fd658022b1a3aaf6ad3b3c615253712807f21a8f7bc3e4996e10618175d4afb2b9190a26040516001600160a01b038216907f79fc685a7dbabb75a67df5e69a90602cef1f19bc465b060eab1ac56685e04a13905f90a26040516001600160a01b038216907f3afb02134e37f7205acf470adc2fc4ebb70614b1599a602d069790915380e2aa905f90a250565b6111f1335f356001600160e01b031916612b82565b61120d5760405162461bcd60e51b8152600401610c589061476a565b6001600160a01b0381165f81815260066020526040808220805462ff0000191662010000179055517f3afb02134e37f7205acf470adc2fc4ebb70614b1599a602d069790915380e2aa9190a250565b611271335f356001600160e01b031916612b82565b61128d5760405162461bcd60e51b8152600401610c589061476a565b6001600160a01b0381165f81815260066020526040808220805462ff000019169055517f77cb944c14da76928795279d1519ce9150085a06e0a53c61d5a86fc4e0fd57c69190a250565b6112ec335f356001600160e01b031916612b82565b6113085760405162461bcd60e51b8152600401610c589061476a565b63ffffffff82165f908152600860205260409020805460ff1916600117815561133a836001600160a01b038416613360565b6040805163ffffffff851681526001600160a01b03841660208201527fe925de263dcdbdc20307c9ab92758ed8cc0edf3d173dad4a3aa54c070f27a54391016110e9565b611393335f356001600160e01b031916612b82565b6113af5760405162461bcd60e51b8152600401610c589061476a565b6001600160a01b0381165f81815260066020526040808220805460ff19166001179055517fd658022b1a3aaf6ad3b3c615253712807f21a8f7bc3e4996e10618175d4afb2b9190a250565b61140f335f356001600160e01b031916612b82565b61142b5760405162461bcd60e51b8152600401610c589061476a565b6114358282613360565b5050565b61144e335f356001600160e01b031916612b82565b61146a5760405162461bcd60e51b8152600401610c589061476a565b82801561147e57506001600160801b038116155b1561149c5760405163c80ed59560e01b815260040160405180910390fd5b60408051606081018252851515815284151560208083019182526001600160801b0385811684860190815263ffffffff8b165f908152600890935294909120925183549251945161ffff1990931690151561ff00191617610100941515949094029390931762010000600160901b03191662010000919093160291909117905561152f856001600160a01b038416613360565b6040805163ffffffff871681528515156020820152841515818301526001600160a01b038416606082015290517f5dbe727bffd24a6d61a5aeef919510389c66c0deeaa82634862cf4f098961fb89181900360800190a15050505050565b6115a2335f356001600160e01b031916612b82565b6115be5760405162461bcd60e51b8152600401610c589061476a565b6001600160a01b0381165f81815260066020526040808220805461ff001916610100179055517f79fc685a7dbabb75a67df5e69a90602cef1f19bc465b060eab1ac56685e04a139190a250565b5f611621335f356001600160e01b031916612b82565b61163d5760405162461bcd60e51b8152600401610c589061476a565b60025460011461165f5760405162461bcd60e51b8152600401610c5890614790565b600280558773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b038216016116a2576040516316df5df960e31b815260040160405180910390fd5b5f6116ac8a612d62565b90506116bc8a8a898989896133ad565b6116ca8a8a8a333386612e9f565b92506116f7338b8b86600460089054906101000a90046001600160401b03166001600160401b0316613136565b50506001600255979650505050505050565b5f61171f335f356001600160e01b031916612b82565b61173b5760405162461bcd60e51b8152600401610c589061476a565b600454600160801b900460ff16156117665760405163e0f9e71d60e01b815260040160405180910390fd5b6001600160a01b0385165f908152600360209081526040918290208251606081018452905460ff80821615158352610100820416151592820183905262010000900461ffff16928101929092526117d05760405163645fd19f60e11b815260040160405180910390fd5b845f036117f057604051630ea3153160e21b815260040160405180910390fd5b604051634104b9ed60e11b81526001600160a01b0387811660048301526118a6917f000000000000000000000000c873f2b7b3ba0a7faa2b56e210e3b965f2b618f59091169063820973da90602401602060405180830381865afa15801561185a573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061187e91906147b4565b86907f0000000000000000000000000000000000000000000000000de0b6b3a7640000613505565b9150838210156118c9576040516302620f6160e61b815260040160405180910390fd5b6040516318457e6160e01b81526001600160a01b037f000000000000000000000000ef417fce1883c6653e7dc6af7c6f85ccde84aa0916906318457e619061191d9086908a90879033908c906004016147cb565b5f604051808303815f87803b158015611934575f80fd5b505af1158015611946573d5f803e3d5ffd5b50505050856001600160a01b03167fdcc60b41ff1c604459e6aa4a7299817416b19fc586a392f111646e26597c4af98660405161198591815260200190565b60405180910390a250949350505050565b6119ab335f356001600160e01b031916612b82565b6119c75760405162461bcd60e51b8152600401610c589061476a565b6004805460ff60801b191690556040517fa45f47fdea8a1efdd9029a5691c7f759c32b7c698632b563573e155625d16933905f90a1565b611a13335f356001600160e01b031916612b82565b611a2f5760405162461bcd60e51b8152600401610c589061476a565b63ffffffff81165f81815260086020908152604091829020805461ff0019168155915192835290917fc45af64a13a09ef916a1114c59589294ec9c3095f2bfbbb093a7a96656858ded91015b60405180910390a15050565b611a9c335f356001600160e01b031916612b82565b611ab85760405162461bcd60e51b8152600401610c589061476a565b80611ac38342614812565b10611ae157604051634c1eef1760e11b815260040160405180910390fd5b604080516001600160a01b038089166020830152871691810191909152606081018590526080810184905260a0810183905260c081018290525f9060e00160408051601f1981840301815291815281516020928301205f8b815260059093529120549091508114611b655760405163fa174ecb60e01b815260040160405180910390fd5b5f888152600560205260408120556001600160a01b03861673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14611b9d5785611bbf565b7f000000000000000000000000ee7d8bcfb72bc1880d0cf19822eb0a2e6577ab625b6040516318457e6160e01b81529096506001600160a01b037f000000000000000000000000ef417fce1883c6653e7dc6af7c6f85ccde84aa0916906318457e6190611c16908a908a908a9083908b906004016147cb565b5f604051808303815f87803b158015611c2d575f80fd5b505af1158015611c3f573d5f803e3d5ffd5b50505050866001600160a01b0316887faf98ea774275cadfa3e477a7b52cba03e01197445a76bd5d0d561608708c362483604051611c7f91815260200190565b60405180910390a35050505050505050565b611ca6335f356001600160e01b031916612b82565b611cc25760405162461bcd60e51b8152600401610c589061476a565b63ffffffff81165f908152600860205260408120805471ffffffffffffffffffffffffffffffffffff19169055611cfa908290613360565b60405163ffffffff821681527f11a9d1a77f76361ed131c19b1dc5758504c51dbde2e49fc973a0ef9577ad13d5906020015b60405180910390a150565b611d4c335f356001600160e01b031916612b82565b611d685760405162461bcd60e51b8152600401610c589061476a565b6001600160a01b0381165f81815260066020526040808220805461ff0019169055517f039bcf51833310242b8b7c6aa0fbabf1bf2b5e5270807ee020f1920ef200666b9190a250565b5f546001600160a01b0316331480611e42575060015460405163b700961360e01b81526001600160a01b039091169063b700961390611e0390339030906001600160e01b03195f351690600401614825565b602060405180830381865afa158015611e1e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e429190614852565b611e4a575f80fd5b600180546001600160a01b0319166001600160a01b03831690811790915560405133907fa3396fd7f6e0a21b50e5089d2da70d5ac0a3bbbd1f617a93f134b76389980198905f90a350565b611eaa335f356001600160e01b031916612b82565b611ec65760405162461bcd60e51b8152600401610c589061476a565b6004805471ffffffffffffffffffffffffffffffffffff16600160901b6001600160701b038416908102919091179091556040519081527f752cd3d8df6864142257fa3a2e02aedf2dc09f1875c2a25b4f117d45c7334d5d90602001611d2c565b5f5b92915050565b611f44335f356001600160e01b031916612b82565b611f605760405162461bcd60e51b8152600401610c589061476a565b6004805460ff60801b1916600160801b1790556040517f9e87fac88ff661f02d44f95383c817fece4bce600a3dab7a54406878b965e752905f90a1565b611fb2335f356001600160e01b031916612b82565b611fce5760405162461bcd60e51b8152600401610c589061476a565b60048054821515600160881b0260ff60881b199091161790556040517fa3fe47e2502292ca20854524008d366d3cad5da2426cfb2484099f06f328e4a090611d2c90831515815260200190565b612030335f356001600160e01b031916612b82565b61204c5760405162461bcd60e51b8152600401610c589061476a565b6103e861ffff8216111561207357604051636c5cde8760e01b815260040160405180910390fd5b6040805160608082018352851515808352851515602080850182815261ffff8881168789018181526001600160a01b038e165f818152600387528b902099518a549551925161ffff1990961690151561ff00191617610100921515929092029190911763ffff0000191662010000949093169390930291909117909655865193845290830191909152938101929092527fe08301321781ac43935a2099b2c3fd42de0a0ee87a519cac00e8c9cecd26ff12910160405180910390a250505050565b5f61214a335f356001600160e01b031916612b82565b6121665760405162461bcd60e51b8152600401610c589061476a565b6002546001146121885760405162461bcd60e51b8152600401610c5890614790565b600280558c73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b038216016121cb576040516316df5df960e31b815260040160405180910390fd5b5f6121d58f612d62565b90506121e58f8f8e8e8e8e6133ad565b6121f38f8f8f333386612e9f565b925050612221338f8f85600460089054906101000a90046001600160401b03166001600160401b0316613136565b6001600160601b03821115612249576040516389588ab360e01b815260040160405180910390fd5b612257828888888888612c28565b5060016002559c9b505050505050505050505050565b612282335f356001600160e01b031916612b82565b61229e5760405162461bcd60e51b8152600401610c589061476a565b6001600160a01b0381165f81815260066020526040808220805463ff00000019166301000000179055517f5e92c085dffcb69d025c31c9ed03d1869e4737ba81e8649c623398caa1b72f159190a250565b5f612305335f356001600160e01b031916612b82565b6123215760405162461bcd60e51b8152600401610c589061476a565b6002546001146123435760405162461bcd60e51b8152600401610c5890614790565b600280555f61235186612d62565b9050612361868686338786612e9f565b9150856001600160a01b03167f6f9b974223f85a1ae805c33b8b519039e2435481d949db1110de151a94d587af8660405161239e91815260200190565b60405180910390a2506001600255949350505050565b6123c9335f356001600160e01b031916612b82565b6123e55760405162461bcd60e51b8152600401610c589061476a565b6001600160a01b0381165f81815260066020526040808220805460ff19169055517fae893dda71e2eee548f8291f458cceae4bd22b56a79906928591e4420444c0e99190a250565b6001600160a01b0383165f9081526006602052604090205460ff168061246f57506001600160a01b0382165f90815260066020526040902054610100900460ff165b8061249757506001600160a01b0381165f9081526006602052604090205462010000900460ff165b806124d55750600454600160881b900460ff1680156124d557506001600160a01b0381165f908152600660205260409020546301000000900460ff16155b1561250e57604051632821264f60e01b81526001600160a01b038085166004830152808416602483015282166044820152606401610c58565b6001600160a01b0383165f908152600660205260409020600101544210156125495760405163f64059db60e01b815260040160405180910390fd5b505050565b612563335f356001600160e01b031916612b82565b61257f5760405162461bcd60e51b8152600401610c589061476a565b806001600160801b03165f036125a85760405163c80ed59560e01b815260040160405180910390fd5b63ffffffff83165f908152600860205260409020805461010071ffffffffffffffffffffffffffffffffff0019909116620100006001600160801b03851602171781556125fe846001600160a01b038516613360565b6040805163ffffffff861681526001600160a01b03851660208201527f34fe916485e02ec88e487b0e611e5c9bacabba9e3eaae7a900aa08be8197d419910160405180910390a150505050565b612660335f356001600160e01b031916612b82565b61267c5760405162461bcd60e51b8152600401610c589061476a565b6001600160a01b0381165f81815260066020526040808220805463ff00000019169055517f1c2a701d65e1c6e2860263c884eae0b10db82e3ddd60640d53c7d53c6c998e799190a250565b6126dc335f356001600160e01b031916612b82565b6126f85760405162461bcd60e51b8152600401610c589061476a565b6001600160a01b0381165f81815260066020526040808220805462ffffff19169055517fae893dda71e2eee548f8291f458cceae4bd22b56a79906928591e4420444c0e99190a26040516001600160a01b038216907f039bcf51833310242b8b7c6aa0fbabf1bf2b5e5270807ee020f1920ef200666b905f90a26040516001600160a01b038216907f77cb944c14da76928795279d1519ce9150085a06e0a53c61d5a86fc4e0fd57c6905f90a250565b6127bd335f356001600160e01b031916612b82565b6127d95760405162461bcd60e51b8152600401610c589061476a565b60405163ca5eb5e160e01b81526001600160a01b0382811660048301527f0000000000000000000000006f475642a6e85809b1c36fa62763669b1b48dd5b169063ca5eb5e1906024015f604051808303815f87803b158015612839575f80fd5b505af115801561284b573d5f803e3d5ffd5b5050505050565b5f612868335f356001600160e01b031916612b82565b6128845760405162461bcd60e51b8152600401610c589061476a565b6002546001146128a65760405162461bcd60e51b8152600401610c5890614790565b600280558873eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b038216016128e9576040516316df5df960e31b815260040160405180910390fd5b5f6128f38b612d62565b90506129038b8b8b333386612e9f565b9250612930338c8c86600460089054906101000a90046001600160401b03166001600160401b0316613136565b6001600160601b03831115612958576040516389588ab360e01b815260040160405180910390fd5b612966838989898989612c28565b5050600160025598975050505050505050565b61298e335f356001600160e01b031916612b82565b6129aa5760405162461bcd60e51b8152600401610c589061476a565b63ffffffff81165f81815260086020908152604091829020805460ff19168155915192835290917f1cb867ed6a020e020ea220d4f48bb8e36552abf9095e093e377d33933f2b31e49101611a7b565b604080518082019091526001600160601b03861681526001600160a01b03851660208201525f9081612a2a82613520565b9050612a3881878787613567565b98975050505050505050565b6001600160a01b0381165f9081526006602052604090205460ff1615612a9557604051632821264f60e01b81526001600160a01b03821660048201525f602482018190526044820152606401610c58565b6001600160a01b0381165f90815260066020526040902060010154421015612ad05760405163f64059db60e01b815260040160405180910390fd5b50565b612ae8335f356001600160e01b031916612b82565b612b045760405162461bcd60e51b8152600401610c589061476a565b5f80546001600160a01b0319166001600160a01b0383169081178255604051909133917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a350565b5f602082018035906007908390612b6590866143d6565b63ffffffff16815260208101919091526040015f20541492915050565b6001545f906001600160a01b03168015801590612c09575060405163b700961360e01b81526001600160a01b0382169063b700961390612bca90879030908890600401614825565b602060405180830381865afa158015612be5573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612c099190614852565b80612c2057505f546001600160a01b038581169116145b949350505050565b612c33335f3361242d565b6040516318457e6160e01b81525f600482018190526024820181905260448201523360648201526001600160601b03871660848201527f000000000000000000000000ef417fce1883c6653e7dc6af7c6f85ccde84aa096001600160a01b0316906318457e619060a4015f604051808303815f87803b158015612cb4575f80fd5b505af1158015612cc6573d5f803e3d5ffd5b5050604080518082019091526001600160601b03891681526001600160a01b038816602082015291505f9050612cfb82613520565b90505f612d0b8288888888613736565b6040516001600160601b038b1681529091506001600160a01b0389169082907fe0ec62d39b054dc2fd626dbc271483735df6e6fa1ef8389754bf8ab27a75eab29060200160405180910390a3505050505050505050565b604080516060810182525f8082526020820181905291810191909152600454600160801b900460ff1615612da95760405163e0f9e71d60e01b815260040160405180910390fd5b506001600160a01b0381165f908152600360209081526040918290208251606081018452905460ff8082161515808452610100830490911615159383019390935262010000900461ffff1692810192909252612e185760405163645fd19f60e11b815260040160405180910390fd5b919050565b5f60405163095ea7b360e01b81526001600160a01b038416600482015282602482015260205f6044835f895af13d15601f3d1160015f511416171691505080612e995760405162461bcd60e51b815260206004820152600e60248201526d1054141493d59157d1905253115160921b6044820152606401610c58565b50505050565b6004545f90600160901b90046001600160701b0316868203612ed45760405163259be69560e11b815260040160405180910390fd5b604051634104b9ed60e11b81526001600160a01b038981166004830152612f8a917f0000000000000000000000000000000000000000000000000de0b6b3a7640000917f000000000000000000000000c873f2b7b3ba0a7faa2b56e210e3b965f2b618f5169063820973da90602401602060405180830381865afa158015612f5e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612f8291906147b4565b899190613505565b91505f836040015161ffff1611612fa15781612fc4565b612fc48360400151612710612fb6919061486d565b839061ffff16612710613505565b915085821015612fe75760405163097b2ad560e31b815260040160405180910390fd5b6001600160701b03818116146130aa57806001600160701b03167f000000000000000000000000ef417fce1883c6653e7dc6af7c6f85ccde84aa096001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561305d573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061308191906147b4565b61308b908461488f565b11156130aa5760405163ed32f3bb60e01b815260040160405180910390fd5b604051631ceb5d1960e11b81526001600160a01b037f000000000000000000000000ef417fce1883c6653e7dc6af7c6f85ccde84aa0916906339d6ba32906130fe9088908c908c908a9089906004016147cb565b5f604051808303815f87803b158015613115575f80fd5b505af1158015613127573d5f803e3d5ffd5b50505050509695505050505050565b600480545f91908290613151906001600160401b03166148a2565b82546001600160401b039182166101009390930a8381029202191617909155905081156131f857613182824261488f565b6001600160a01b038781165f81815260066020908152604091829020600101949094558051938401919091529087169082015260608101859052608081018490524260a082015260c0810183905260e00160408051601f1981840301815291815281516020928301205f84815260059093529120555b846001600160a01b0316866001600160a01b0316827fe96d7872363f475d18b2f5390caaa5eaa96b2d38e42c62afe4ac08ebd2b13c3a87874288604051613258949392919093845260208401929092526040830152606082015260800190565b60405180910390a4505050505050565b63ffffffff81165f9081526007602052604081205480611f295760405163f6ff4fb760e01b815263ffffffff84166004820152602401610c58565b5f6008816132b460208b018b6143d6565b63ffffffff16815260208082019290925260409081015f208151606081018352905460ff808216151580845261010083049091161515948301949094526201000090046001600160801b031691810191909152915061333c5761331a60208901896143d6565b6040516315b73a2960e21b815263ffffffff9091166004820152602401610c58565b5f613349868801886145a8565b90506133558882613959565b505050505050505050565b63ffffffff82165f81815260076020908152604091829020849055815192835282018390527f238399d427b947898edb290f5ff0f9109849b1c3ba196a42e35f00c50a54b98b9101611a7b565b60405163d505accf60e01b81523360048201526001600160a01b037f000000000000000000000000ef417fce1883c6653e7dc6af7c6f85ccde84aa0981166024830152604482018790526064820186905260ff8516608483015260a4820184905260c4820183905287169063d505accf9060e4015f604051808303815f87803b158015613438575f80fd5b505af1925050508015613449575060015b6134fd57604051636eb1769f60e11b81523360048201526001600160a01b037f000000000000000000000000ef417fce1883c6653e7dc6af7c6f85ccde84aa098116602483015286919088169063dd62ed3e90604401602060405180830381865afa1580156134ba573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906134de91906147b4565b10156134fd576040516301b8851f60e41b815260040160405180910390fd5b505050505050565b5f825f190484118302158202613519575f80fd5b5091020490565b80515f906001600160601b03101561354b57604051633524486360e01b815260040160405180910390fd5b81516020909201516001600160a01b031660a09290921b171790565b5f6001600160a01b03821673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee148015906135c757507f00000000000000000000000000000000000000000000000000000000000000016001600160a01b0316826001600160a01b031614155b156135e557604051637f3cd08160e11b815260040160405180910390fd5b5f6135f2848601866143d6565b63ffffffff81165f908152600860209081526040918290208251606081018452905460ff8082161515835261010082041615159282018390526201000090046001600160801b0316928101929092529192509061366a5760405163420eae3760e01b815263ffffffff83166004820152602401610c58565b5f8760405160200161367e91815260200190565b60405160208183030381529060405290505f6136c683604001515f6136bf60408051600360f01b602082015281516002818303018152602290910190915290565b9190613a45565b90505f6136f58584846001600160a01b038b1673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1415613aaa565b90506001600160a01b03871673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14613725578060200151613728565b80515b9a9950505050505050505050565b5f80613744858701876143d6565b63ffffffff81165f908152600860209081526040918290208251606081018452905460ff8082161515835261010082041615159282018390526201000090046001600160801b031692810192909252919250906137bc5760405163420eae3760e01b815263ffffffff83166004820152602401610c58565b5f886040516020016137d091815260200190565b60405160208183030381529060405290505f61381183604001515f6136bf60408051600360f01b602082015281516002818303018152602290910190915290565b90505f6138408584846001600160a01b038c1673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1415613aaa565b905073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b038916016138a75780518710156138a257805160405163f5ac3fa760e01b815263ffffffff87166004820152602481019190915260448101889052606401610c58565b61393a565b7f00000000000000000000000000000000000000000000000000000000000000016001600160a01b0316886001600160a01b0316036139215786816020015111156138a257602081015160405163f5ac3fa760e01b815263ffffffff87166004820152602481019190915260448101889052606401610c58565b604051637f3cd08160e11b815260040160405180910390fd5b5f6139488685858533613b88565b519c9b505050505050505050505050565b60408051808201825260a083901c8082526001600160a01b03808516602084018190529351631ceb5d1960e11b815292937f000000000000000000000000ef417fce1883c6653e7dc6af7c6f85ccde84aa09909116926339d6ba32926139c8925f9283928392916004016147cb565b5f604051808303815f87803b1580156139df575f80fd5b505af11580156139f1573d5f803e3d5ffd5b5050505080602001516001600160a01b0316837fb944fddc61d7fedb8b736790454ba972000703b0d21c7481d6dbf95b7c2cc2f1835f0151604051613a3891815260200190565b60405180910390a3505050565b6060836003613a54825f613c8e565b61ffff1614613a8757613a67815f613c8e565b604051633a51740d60e01b815261ffff9091166004820152602401610c58565b5f613a928585613cea565b9050613aa086600183613d63565b9695505050505050565b604080518082019091525f80825260208201527f0000000000000000000000006f475642a6e85809b1c36fa62763669b1b48dd5b6001600160a01b031663ddc28c586040518060a001604052808863ffffffff168152602001613b0c89613268565b8152602001878152602001868152602001851515815250306040518363ffffffff1660e01b8152600401613b41929190614914565b6040805180830381865afa158015613b5b573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613b7f91906149e4565b95945050505050565b613b90613f91565b5f613b9d845f0151613dcc565b602085015190915015613bb757613bb78460200151613df3565b7f0000000000000000000000006f475642a6e85809b1c36fa62763669b1b48dd5b6001600160a01b0316632637a450826040518060a001604052808b63ffffffff168152602001613c078c613268565b81526020018a81526020018981526020015f8960200151111515815250866040518463ffffffff1660e01b8152600401613c42929190614914565b60806040518083038185885af1158015613c5e573d5f803e3d5ffd5b50505050506040513d601f19601f82011682018060405250810190613c8391906149fe565b979650505050505050565b5f613c9a82600261488f565b83511015613ce15760405162461bcd60e51b8152602060048201526014602482015273746f55696e7431365f6f75744f66426f756e647360601b6044820152606401610c58565b50016002015190565b60606001600160801b03821615613d3257604080516001600160801b0319608086811b8216602084015285901b16603082015201604051602081830303815290604052613d5c565b6040516001600160801b0319608085901b1660208201526030016040516020818303038152906040525b9392505050565b6060836003613d72825f613c8e565b61ffff1614613d8557613a67815f613c8e565b846001613d928551613ed2565b613d9d906001614a6f565b8686604051602001613db3959493929190614a8a565b6040516020818303038152906040529150509392505050565b5f813414613def576040516304fb820960e51b8152346004820152602401610c58565b5090565b5f7f0000000000000000000000006f475642a6e85809b1c36fa62763669b1b48dd5b6001600160a01b031663e4fe1d946040518163ffffffff1660e01b8152600401602060405180830381865afa158015613e50573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613e749190614af0565b90506001600160a01b038116613e9d576040516329b99a9560e11b815260040160405180910390fd5b6114356001600160a01b038216337f0000000000000000000000006f475642a6e85809b1c36fa62763669b1b48dd5b85613f00565b5f61ffff821115613def576040516306dfcc6560e41b81526010600482015260248101839052604401610c58565b5f6040516323b872dd60e01b81526001600160a01b03851660048201526001600160a01b038416602482015282604482015260205f6064835f8a5af13d15601f3d1160015f51141617169150508061284b5760405162461bcd60e51b81526020600482015260146024820152731514905394d1915497d19493d357d1905253115160621b6044820152606401610c58565b60405180606001604052805f80191681526020015f6001600160401b03168152602001613fcf60405180604001604052805f81526020015f81525090565b905290565b80356001600160601b0381168114612e18575f80fd5b6001600160a01b0381168114612ad0575f80fd5b8035612e1881613fea565b5f8083601f840112614019575f80fd5b5081356001600160401b0381111561402f575f80fd5b602083019150836020828501011115614046575f80fd5b9250929050565b5f805f805f8060a08789031215614062575f80fd5b61406b87613fd4565b9550602087013561407b81613fea565b945060408701356001600160401b03811115614095575f80fd5b6140a189828a01614009565b90955093505060608701356140b581613fea565b80925050608087013590509295509295509295565b5f805f606084860312156140dc575f80fd5b83356140e781613fea565b95602085013595506040909401359392505050565b6001600160401b0381168114612ad0575f80fd5b5f60208284031215614120575f80fd5b8135613d5c816140fc565b5f6060828403121561413b575f80fd5b50919050565b5f805f805f805f60e0888a031215614157575f80fd5b614161898961412b565b96506060880135955060808801356001600160401b0380821115614183575f80fd5b61418f8b838c01614009565b909750955060a08a013591506141a482613fea565b90935060c089013590808211156141b9575f80fd5b506141c68a828b01614009565b989b979a50959850939692959293505050565b803563ffffffff81168114612e18575f80fd5b80356001600160801b0381168114612e18575f80fd5b5f8060408385031215614213575f80fd5b61421c836141d9565b915061422a602084016141ec565b90509250929050565b5f60208284031215614243575f80fd5b8135613d5c81613fea565b5f806040838503121561425f575f80fd5b614268836141d9565b9150602083013561427881613fea565b809150509250929050565b5f8060408385031215614294575f80fd5b61429d836141d9565b946020939093013593505050565b8015158114612ad0575f80fd5b5f805f805f60a086880312156142cc575f80fd5b6142d5866141d9565b945060208601356142e5816142ab565b935060408601356142f5816142ab565b9250606086013561430581613fea565b9150614313608087016141ec565b90509295509295909350565b803560ff81168114612e18575f80fd5b5f805f805f805f60e0888a031215614345575f80fd5b873561435081613fea565b96506020880135955060408801359450606088013593506143736080890161431f565b925060a0880135915060c0880135905092959891949750929550565b5f805f80608085870312156143a2575f80fd5b84356143ad81613fea565b9350602085013592506040850135915060608501356143cb81613fea565b939692955090935050565b5f602082840312156143e6575f80fd5b613d5c826141d9565b5f805f805f805f60e0888a031215614405575f80fd5b87359650602088013561441781613fea565b9550604088013561442781613fea565b969995985095966060810135965060808101359560a0820135955060c0909101359350915050565b5f6020828403121561445f575f80fd5b81356001600160701b0381168114613d5c575f80fd5b5f60208284031215614485575f80fd5b8135613d5c816142ab565b5f805f80608085870312156144a3575f80fd5b84356144ae81613fea565b935060208501356144be816142ab565b925060408501356144ce816142ab565b9150606085013561ffff811681146143cb575f80fd5b5f805f805f805f805f805f806101608d8f031215614500575f80fd5b61450a8d35613fea565b8c359b5060208d01359a5060408d0135995060608d0135985061452f60808e0161431f565b975060a08d0135965060c08d0135955061454c60e08e0135613fea565b60e08d013594506001600160401b036101008e0135111561456b575f80fd5b61457c8e6101008f01358f01614009565b909450925061458e6101208e01613ffe565b91506101408d013590509295989b509295989b509295989b565b5f602082840312156145b8575f80fd5b5035919050565b5f805f606084860312156145d1575f80fd5b83356145dc81613fea565b925060208401356145ec81613fea565b915060408401356145fc81613fea565b809150509250925092565b5f805f60608486031215614619575f80fd5b614622846141d9565b9250602084013561463281613fea565b9150614640604085016141ec565b90509250925092565b5f805f805f805f8060e0898b031215614660575f80fd5b883561466b81613fea565b97506020890135965060408901359550606089013561468981613fea565b945060808901356001600160401b038111156146a3575f80fd5b6146af8b828c01614009565b90955093505060a08901356146c381613fea565b8092505060c089013590509295985092959890939650565b5f805f805f608086880312156146ef575f80fd5b6146f886613fd4565b9450602086013561470881613fea565b935060408601356001600160401b03811115614722575f80fd5b61472e88828901614009565b909450925050606086013561474281613fea565b809150509295509295909350565b5f60608284031215614760575f80fd5b613d5c838361412b565b6020808252600c908201526b15539055551213d49256915160a21b604082015260600190565b6020808252600a90820152695245454e5452414e435960b01b604082015260600190565b5f602082840312156147c4575f80fd5b5051919050565b6001600160a01b039586168152938516602085015260408401929092529092166060820152608081019190915260a00190565b634e487b7160e01b5f52601160045260245ffd5b81810381811115611f2957611f296147fe565b6001600160a01b0393841681529190921660208201526001600160e01b0319909116604082015260600190565b5f60208284031215614862575f80fd5b8151613d5c816142ab565b61ffff828116828216039080821115614888576148886147fe565b5092915050565b80820180821115611f2957611f296147fe565b5f6001600160401b038083168181036148bd576148bd6147fe565b6001019392505050565b5f5b838110156148e15781810151838201526020016148c9565b50505f910152565b5f81518084526149008160208601602086016148c7565b601f01601f19169290920160200192915050565b6040815263ffffffff8351166040820152602083015160608201525f604084015160a0608084015261494960e08401826148e9565b90506060850151603f198483030160a085015261496682826148e9565b60809690960151151560c08501525050506001600160a01b039190911660209091015290565b5f6040828403121561499c575f80fd5b604051604081018181106001600160401b03821117156149ca57634e487b7160e01b5f52604160045260245ffd5b604052825181526020928301519281019290925250919050565b5f604082840312156149f4575f80fd5b613d5c838361498c565b5f60808284031215614a0e575f80fd5b604051606081018181106001600160401b0382111715614a3c57634e487b7160e01b5f52604160045260245ffd5b604052825181526020830151614a51816140fc565b6020820152614a63846040850161498c565b60408201529392505050565b61ffff818116838216019080821115614888576148886147fe565b5f8651614a9b818460208b016148c7565b6001600160f81b031960f888811b82169285019283526001600160f01b031960f089901b16600184015286901b1660038201528351614ae18160048401602088016148c7565b01600401979650505050505050565b5f60208284031215614b00575f80fd5b8151613d5c81613fea56fea2646970667358221220f5570434782225bc2c1529ea0f26bf6133d284dc6630e0b39289269f853cb6fd64736f6c63430008150033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000005f2f11ad8656439d5c14d9b351f8b09cdac2a02d000000000000000000000000ef417fce1883c6653e7dc6af7c6f85ccde84aa09000000000000000000000000c873f2b7b3ba0a7faa2b56e210e3b965f2b618f5000000000000000000000000ee7d8bcfb72bc1880d0cf19822eb0a2e6577ab620000000000000000000000006f475642a6e85809b1c36fa62763669b1b48dd5b0000000000000000000000005f2f11ad8656439d5c14d9b351f8b09cdac2a02d0000000000000000000000000000000000000000000000000000000000000001
-----Decoded View---------------
Arg [0] : _owner (address): 0x5F2F11ad8656439d5C14d9B351f8b09cDaC2A02d
Arg [1] : _vault (address): 0xef417FCE1883c6653E7dC6AF7c6F85CCDE84Aa09
Arg [2] : _accountant (address): 0xc873F2b7b3BA0a7faA2B56e210E3B965f2b618f5
Arg [3] : _weth (address): 0xEE7D8BCFb72bC1880D0Cf19822eB0A2e6577aB62
Arg [4] : _lzEndPoint (address): 0x6F475642a6e85809B1c36Fa62763669b1b48DD5B
Arg [5] : _delegate (address): 0x5F2F11ad8656439d5C14d9B351f8b09cDaC2A02d
Arg [6] : _lzToken (address): 0x0000000000000000000000000000000000000001
-----Encoded View---------------
7 Constructor Arguments found :
Arg [0] : 0000000000000000000000005f2f11ad8656439d5c14d9b351f8b09cdac2a02d
Arg [1] : 000000000000000000000000ef417fce1883c6653e7dc6af7c6f85ccde84aa09
Arg [2] : 000000000000000000000000c873f2b7b3ba0a7faa2b56e210e3b965f2b618f5
Arg [3] : 000000000000000000000000ee7d8bcfb72bc1880d0cf19822eb0a2e6577ab62
Arg [4] : 0000000000000000000000006f475642a6e85809b1c36fa62763669b1b48dd5b
Arg [5] : 0000000000000000000000005f2f11ad8656439d5c14d9b351f8b09cdac2a02d
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000001
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ 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.