Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00| Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
Advanced mode: Intended for advanced users or developers and will display all Internal Transactions including zero value transfers.
Latest 10 internal transactions
Advanced mode:
Cross-Chain Transactions
Loading...
Loading
Contract Name:
LayerZeroTellerWithRateLimiting
Compiler Version
v0.8.21+commit.d9974bed
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.21;
import {
CrossChainTellerWithGenericBridge, ERC20
} from "src/base/Roles/CrossChain/CrossChainTellerWithGenericBridge.sol";
import {SafeTransferLib} from "@solmate/utils/SafeTransferLib.sol";
import {OAppAuth, Origin, MessagingFee, MessagingReceipt} from "@oapp-auth/OAppAuth.sol";
import {AddressToBytes32Lib} from "src/helper/AddressToBytes32Lib.sol";
import {OptionsBuilder} from "@oapp-auth/OptionsBuilder.sol";
import {PairwiseRateLimiter} from "src/base/Roles/CrossChain/PairwiseRateLimiter.sol";
import {MessageLib} from "src/base/Roles/CrossChain/MessageLib.sol";
contract LayerZeroTellerWithRateLimiting is CrossChainTellerWithGenericBridge, OAppAuth, PairwiseRateLimiter {
using SafeTransferLib for ERC20;
using AddressToBytes32Lib for address;
using AddressToBytes32Lib for bytes32;
using OptionsBuilder for bytes;
using MessageLib for uint256;
// ========================================= STRUCTS =========================================
/**
* @notice Stores information about a chain.
* @dev Sender is stored in OAppAuthCore `peers` mapping.
* @param allowMessagesFrom Whether to allow messages from this chain.
* @param allowMessagesTo Whether to allow messages to this chain.
* @param messageGasLimit The gas limit for messages to this chain.
*/
struct Chain {
bool allowMessagesFrom;
bool allowMessagesTo;
uint128 messageGasLimit;
}
// ========================================= STATE =========================================
/**
* @notice Maps chain selector to chain information.
*/
mapping(uint32 => Chain) public idToChains;
//============================== ERRORS ===============================
error LayerZeroTeller__MessagesNotAllowedFrom(uint256 chainSelector);
error LayerZeroTeller__MessagesNotAllowedFromSender(uint256 chainSelector, address sender);
error LayerZeroTeller__MessagesNotAllowedTo(uint256 chainSelector);
error LayerZeroTeller__FeeExceedsMax(uint256 chainSelector, uint256 fee, uint256 maxFee);
error LayerZeroTeller__BadFeeToken();
error LayerZeroTeller__ZeroMessageGasLimit();
//============================== EVENTS ===============================
event ChainAdded(uint256 chainId, bool allowMessagesFrom, bool allowMessagesTo, address targetTeller);
event ChainRemoved(uint256 chainId);
event ChainAllowMessagesFrom(uint256 chainId, address targetTeller);
event ChainAllowMessagesTo(uint256 chainId, address targetTeller);
event ChainStopMessagesFrom(uint256 chainId);
event ChainStopMessagesTo(uint256 chainId);
event ChainSetGasLimit(uint256 chainId, uint128 messageGasLimit);
//============================== IMMUTABLES ===============================
/**
* @notice The LayerZero token.
*/
address internal immutable lzToken;
constructor(
address _owner,
address _vault,
address _accountant,
address _weth,
address _lzEndPoint,
address _delegate,
address _lzToken
) CrossChainTellerWithGenericBridge(_owner, _vault, _accountant, _weth) OAppAuth(_lzEndPoint, _delegate) {
lzToken = _lzToken;
}
// ========================================= ADMIN FUNCTIONS =========================================
/**
* @notice Add a chain to the teller.
* @dev Callable by OWNER_ROLE.
* @param chainId The LayerZero chain id to add.
* @param allowMessagesFrom Whether to allow messages from this chain.
* @param allowMessagesTo Whether to allow messages to this chain.
* @param targetTeller The address of the target teller on the other chain.
* @param messageGasLimit The gas limit for messages to this chain.
*/
function addChain(
uint32 chainId,
bool allowMessagesFrom,
bool allowMessagesTo,
address targetTeller,
uint128 messageGasLimit
) external requiresAuth {
if (allowMessagesTo && messageGasLimit == 0) {
revert LayerZeroTeller__ZeroMessageGasLimit();
}
idToChains[chainId] = Chain(allowMessagesFrom, allowMessagesTo, messageGasLimit);
_setPeer(chainId, targetTeller.toBytes32());
emit ChainAdded(chainId, allowMessagesFrom, allowMessagesTo, targetTeller);
}
/**
* @notice Remove a chain from the teller.
* @dev Callable by MULTISIG_ROLE.
*/
function removeChain(uint32 chainId) external requiresAuth {
delete idToChains[chainId];
_setPeer(chainId, bytes32(0));
emit ChainRemoved(chainId);
}
/**
* @notice Allow messages from a chain.
* @dev Callable by OWNER_ROLE.
*/
function allowMessagesFromChain(uint32 chainId, address targetTeller) external requiresAuth {
Chain storage chain = idToChains[chainId];
chain.allowMessagesFrom = true;
_setPeer(chainId, targetTeller.toBytes32());
emit ChainAllowMessagesFrom(chainId, targetTeller);
}
/**
* @notice Allow messages to a chain.
* @dev Callable by OWNER_ROLE.
*/
function allowMessagesToChain(uint32 chainId, address targetTeller, uint128 messageGasLimit)
external
requiresAuth
{
if (messageGasLimit == 0) {
revert LayerZeroTeller__ZeroMessageGasLimit();
}
Chain storage chain = idToChains[chainId];
chain.allowMessagesTo = true;
chain.messageGasLimit = messageGasLimit;
_setPeer(chainId, targetTeller.toBytes32());
emit ChainAllowMessagesTo(chainId, targetTeller);
}
/**
* @notice Stop messages from a chain.
* @dev Callable by MULTISIG_ROLE.
*/
function stopMessagesFromChain(uint32 chainId) external requiresAuth {
Chain storage chain = idToChains[chainId];
chain.allowMessagesFrom = false;
emit ChainStopMessagesFrom(chainId);
}
/**
* @notice Stop messages to a chain.
* @dev Callable by MULTISIG_ROLE.
*/
function stopMessagesToChain(uint32 chainId) external requiresAuth {
Chain storage chain = idToChains[chainId];
chain.allowMessagesTo = false;
emit ChainStopMessagesTo(chainId);
}
/**
* @notice Set outbound rate limit configurations.
* @dev Callable by MULTISIG_ROLE.
*/
function setOutboundRateLimits(RateLimitConfig[] calldata _rateLimitConfigs) external requiresAuth {
_setOutboundRateLimits(_rateLimitConfigs);
}
/**
* @notice Set inbound rate limit configurations.
* @dev Callable by MULTISIG_ROLE.
*/
function setInboundRateLimits(RateLimitConfig[] calldata _rateLimitConfigs) external requiresAuth {
_setInboundRateLimits(_rateLimitConfigs);
}
/**
* @notice Set the gas limit for messages to a chain.
* @dev Callable by OWNER_ROLE.
*/
function setChainGasLimit(uint32 chainId, uint128 messageGasLimit) external requiresAuth {
if (messageGasLimit == 0) {
revert LayerZeroTeller__ZeroMessageGasLimit();
}
Chain storage chain = idToChains[chainId];
chain.messageGasLimit = messageGasLimit;
emit ChainSetGasLimit(chainId, messageGasLimit);
}
// ========================================= OAppAuthReceiver =========================================
/**
* @notice Receive messages from the LayerZero endpoint.
* @dev `lzReceive` only sanitizes the message sender, but we also need to make sure we are allowing messages
* from the source chain.
*/
function _lzReceive(
Origin calldata _origin,
bytes32 _guid,
bytes calldata _message,
address, /*_executor*/
bytes calldata /*_extraData*/
) internal override {
Chain memory source = idToChains[_origin.srcEid];
if (!source.allowMessagesFrom) revert LayerZeroTeller__MessagesNotAllowedFrom(_origin.srcEid);
uint256 message = abi.decode(_message, (uint256));
_checkAndUpdateInboundRateLimit(_origin.srcEid, message.uint256ToMessage().shareAmount);
_completeMessageReceive(_guid, message);
}
// ========================================= INTERNAL BRIDGE FUNCTIONS =========================================
/**
* @notice Sends messages using Layer Zero end point.
* @dev This function does NOT revert if the `feeToken` is invalid,
* rather the Layer Zero end point will revert.
* @dev This function will revert if maxFee is exceeded.
* @dev This function will revert if destination chain does not allow messages.
* @param message The message to send.
* @param bridgeWildCard An abi encoded uint32 containing the destination chain id.
* @param feeToken The token to pay the bridge fee in.
* @param maxFee The maximum fee to pay the bridge.
*/
function _sendMessage(uint256 message, bytes calldata bridgeWildCard, ERC20 feeToken, uint256 maxFee)
internal
override
returns (bytes32 messageId)
{
uint32 destinationId = abi.decode(bridgeWildCard, (uint32));
_checkAndUpdateOutboundRateLimit(destinationId, message.uint256ToMessage().shareAmount);
Chain memory chain = idToChains[destinationId];
if (!chain.allowMessagesTo) {
revert LayerZeroTeller__MessagesNotAllowedTo(destinationId);
}
bytes memory m = abi.encode(message);
bytes memory options = OptionsBuilder.newOptions().addExecutorLzReceiveOption(chain.messageGasLimit, 0);
MessagingFee memory fee = _quote(destinationId, m, options, address(feeToken) != NATIVE);
if (address(feeToken) == NATIVE) {
if (fee.nativeFee > maxFee) {
revert LayerZeroTeller__FeeExceedsMax(destinationId, fee.nativeFee, maxFee);
}
} else if (address(feeToken) == lzToken) {
if (fee.lzTokenFee > maxFee) {
revert LayerZeroTeller__FeeExceedsMax(destinationId, fee.lzTokenFee, maxFee);
}
} else {
revert LayerZeroTeller__BadFeeToken();
}
MessagingReceipt memory receipt = _lzSend(destinationId, m, options, fee, msg.sender);
messageId = receipt.guid;
}
/**
* @notice Preview fee required to bridge shares in a given feeToken.
* @param message The message to send.
* @param bridgeWildCard An abi encoded uint32 containing the destination chain id.
* @param feeToken The token to pay the bridge fee in.
*/
function _previewFee(uint256 message, bytes calldata bridgeWildCard, ERC20 feeToken)
internal
view
override
returns (uint256 fee)
{
// Make sure feeToken is either NATIVE or lzToken.
if (address(feeToken) != NATIVE && address(feeToken) != lzToken) {
revert LayerZeroTeller__BadFeeToken();
}
uint32 destinationId = abi.decode(bridgeWildCard, (uint32));
Chain memory chain = idToChains[destinationId];
if (!chain.allowMessagesTo) {
revert LayerZeroTeller__MessagesNotAllowedTo(destinationId);
}
bytes memory m = abi.encode(message);
bytes memory options = OptionsBuilder.newOptions().addExecutorLzReceiveOption(chain.messageGasLimit, 0);
MessagingFee memory messageFee = _quote(destinationId, m, options, address(feeToken) != NATIVE);
fee = address(feeToken) == NATIVE ? messageFee.nativeFee : messageFee.lzTokenFee;
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.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: 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: UNLICENSED
pragma solidity >=0.8.0;
library MessageLib {
error MessageLib__ShareAmountOverflow();
uint256 internal constant MAX_SHARE_AMOUNT = type(uint96).max;
/**
* @notice Messages are transferred between chains as uint256
* The first 96 bits are the share amount.
* The remaining 160 bits are the address to send the shares to.
* @dev Using a uint256 was chosen because most bridging protocols charge based off the number of
* bytes sent, and packing a uint256 in this way caps it at 32 bytes.
*/
struct Message {
uint256 shareAmount; // The amount of shares to bridge.
address to;
}
/**
* @notice Extracts a Message from a uint256.
*/
function uint256ToMessage(uint256 b) internal pure returns (Message memory m) {
m.shareAmount = uint96(b >> 160);
m.to = address(uint160(b));
}
/**
* @notice Packs a Message into a uint256.
*/
function messageToUint256(Message memory m) internal pure returns (uint256 b) {
if (m.shareAmount > MAX_SHARE_AMOUNT) revert MessageLib__ShareAmountOverflow();
b |= m.shareAmount << 160;
b |= uint160(m.to);
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.21;
import {ERC20} from "@solmate/tokens/ERC20.sol";
import {WETH} from "@solmate/tokens/WETH.sol";
import {BoringVault} from "src/base/BoringVault.sol";
import {AccountantWithRateProviders} from "src/base/Roles/AccountantWithRateProviders.sol";
import {FixedPointMathLib} from "@solmate/utils/FixedPointMathLib.sol";
import {SafeTransferLib} from "@solmate/utils/SafeTransferLib.sol";
import {BeforeTransferHook} from "src/interfaces/BeforeTransferHook.sol";
import {Auth, Authority} from "@solmate/auth/Auth.sol";
import {ReentrancyGuard} from "@solmate/utils/ReentrancyGuard.sol";
import {IPausable} from "src/interfaces/IPausable.sol";
contract TellerWithMultiAssetSupport is Auth, BeforeTransferHook, ReentrancyGuard, IPausable {
using FixedPointMathLib for uint256;
using SafeTransferLib for ERC20;
using SafeTransferLib for WETH;
// ========================================= STRUCTS =========================================
/**
* @param allowDeposits bool indicating whether or not deposits are allowed for this asset.
* @param allowWithdraws bool indicating whether or not withdraws are allowed for this asset.
* @param sharePremium uint16 indicating the premium to apply to the shares minted.
* where 40 represents a 40bps reduction in shares minted using this asset.
*/
struct Asset {
bool allowDeposits;
bool allowWithdraws;
uint16 sharePremium;
}
/**
* @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: UNLICENSED
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
pragma solidity ^0.8.0;
interface IRateProvider {
function getRate() external view returns (uint256);
}// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.21;
interface BeforeTransferHook {
function beforeTransfer(address from, address to, address operator) external view;
}// 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: 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: UNLICENSED
pragma solidity 0.8.21;
import {FixedPointMathLib} from "@solmate/utils/FixedPointMathLib.sol";
import {IRateProvider} from "src/interfaces/IRateProvider.sol";
import {ERC20} from "@solmate/tokens/ERC20.sol";
import {SafeTransferLib} from "@solmate/utils/SafeTransferLib.sol";
import {BoringVault} from "src/base/BoringVault.sol";
import {Auth, Authority} from "@solmate/auth/Auth.sol";
import {IPausable} from "src/interfaces/IPausable.sol";
contract AccountantWithRateProviders is Auth, IRateProvider, IPausable {
using FixedPointMathLib for uint256;
using SafeTransferLib for ERC20;
// ========================================= STRUCTS =========================================
/**
* @param payoutAddress the address `claimFees` sends fees to
* @param highwaterMark the highest value of the BoringVault's share price
* @param feesOwedInBase total pending fees owed in terms of base
* @param totalSharesLastUpdate total amount of shares the last exchange rate update
* @param exchangeRate the current exchange rate in terms of base
* @param allowedExchangeRateChangeUpper the max allowed change to exchange rate from an update
* @param allowedExchangeRateChangeLower the min allowed change to exchange rate from an update
* @param lastUpdateTimestamp the block timestamp of the last exchange rate update
* @param isPaused whether or not this contract is paused
* @param minimumUpdateDelayInSeconds the minimum amount of time that must pass between
* exchange rate updates, such that the update won't trigger the contract to be paused
* @param platformFee the platform fee
* @param performanceFee the performance fee
*/
struct AccountantState {
address payoutAddress;
uint96 highwaterMark;
uint128 feesOwedInBase;
uint128 totalSharesLastUpdate;
uint96 exchangeRate;
uint16 allowedExchangeRateChangeUpper;
uint16 allowedExchangeRateChangeLower;
uint64 lastUpdateTimestamp;
bool isPaused;
uint24 minimumUpdateDelayInSeconds;
uint16 platformFee;
uint16 performanceFee;
}
/**
* @param isPeggedToBase whether or not the asset is 1:1 with the base asset
* @param rateProvider the rate provider for this asset if `isPeggedToBase` is false
*/
struct RateProviderData {
bool isPeggedToBase;
IRateProvider rateProvider;
}
// ========================================= STATE =========================================
/**
* @notice Store the accountant state in 3 packed slots.
*/
AccountantState public accountantState;
/**
* @notice Maps ERC20s to their RateProviderData.
*/
mapping(ERC20 => RateProviderData) public rateProviderData;
//============================== ERRORS ===============================
error AccountantWithRateProviders__UpperBoundTooSmall();
error AccountantWithRateProviders__LowerBoundTooLarge();
error AccountantWithRateProviders__PlatformFeeTooLarge();
error AccountantWithRateProviders__PerformanceFeeTooLarge();
error AccountantWithRateProviders__Paused();
error AccountantWithRateProviders__ZeroFeesOwed();
error AccountantWithRateProviders__OnlyCallableByBoringVault();
error AccountantWithRateProviders__UpdateDelayTooLarge();
error AccountantWithRateProviders__ExchangeRateAboveHighwaterMark();
//============================== EVENTS ===============================
event Paused();
event Unpaused();
event DelayInSecondsUpdated(uint24 oldDelay, uint24 newDelay);
event UpperBoundUpdated(uint16 oldBound, uint16 newBound);
event LowerBoundUpdated(uint16 oldBound, uint16 newBound);
event PlatformFeeUpdated(uint16 oldFee, uint16 newFee);
event PerformanceFeeUpdated(uint16 oldFee, uint16 newFee);
event PayoutAddressUpdated(address oldPayout, address newPayout);
event RateProviderUpdated(address asset, bool isPegged, address rateProvider);
event ExchangeRateUpdated(uint96 oldRate, uint96 newRate, uint64 currentTime);
event FeesClaimed(address indexed feeAsset, uint256 amount);
event HighwaterMarkReset();
//============================== IMMUTABLES ===============================
/**
* @notice The base asset rates are provided in.
*/
ERC20 public immutable base;
/**
* @notice The decimals rates are provided in.
*/
uint8 public immutable decimals;
/**
* @notice The BoringVault this accountant is working with.
* Used to determine share supply for fee calculation.
*/
BoringVault public immutable vault;
/**
* @notice One share of the BoringVault.
*/
uint256 internal immutable ONE_SHARE;
constructor(
address _owner,
address _vault,
address payoutAddress,
uint96 startingExchangeRate,
address _base,
uint16 allowedExchangeRateChangeUpper,
uint16 allowedExchangeRateChangeLower,
uint24 minimumUpdateDelayInSeconds,
uint16 platformFee,
uint16 performanceFee
) Auth(_owner, Authority(address(0))) {
base = ERC20(_base);
decimals = ERC20(_base).decimals();
vault = BoringVault(payable(_vault));
ONE_SHARE = 10 ** vault.decimals();
accountantState = AccountantState({
payoutAddress: payoutAddress,
highwaterMark: startingExchangeRate,
feesOwedInBase: 0,
totalSharesLastUpdate: uint128(vault.totalSupply()),
exchangeRate: startingExchangeRate,
allowedExchangeRateChangeUpper: allowedExchangeRateChangeUpper,
allowedExchangeRateChangeLower: allowedExchangeRateChangeLower,
lastUpdateTimestamp: uint64(block.timestamp),
isPaused: false,
minimumUpdateDelayInSeconds: minimumUpdateDelayInSeconds,
platformFee: platformFee,
performanceFee: performanceFee
});
}
// ========================================= ADMIN FUNCTIONS =========================================
/**
* @notice Pause this contract, which prevents future calls to `updateExchangeRate`, and any safe rate
* calls will revert.
* @dev Callable by MULTISIG_ROLE.
*/
function pause() external requiresAuth {
accountantState.isPaused = true;
emit Paused();
}
/**
* @notice Unpause this contract, which allows future calls to `updateExchangeRate`, and any safe rate
* calls will stop reverting.
* @dev Callable by MULTISIG_ROLE.
*/
function unpause() external requiresAuth {
accountantState.isPaused = false;
emit Unpaused();
}
/**
* @notice Update the minimum time delay between `updateExchangeRate` calls.
* @dev There are no input requirements, as it is possible the admin would want
* the exchange rate updated as frequently as needed.
* @dev Callable by OWNER_ROLE.
*/
function updateDelay(uint24 minimumUpdateDelayInSeconds) external requiresAuth {
if (minimumUpdateDelayInSeconds > 14 days) revert AccountantWithRateProviders__UpdateDelayTooLarge();
uint24 oldDelay = accountantState.minimumUpdateDelayInSeconds;
accountantState.minimumUpdateDelayInSeconds = minimumUpdateDelayInSeconds;
emit DelayInSecondsUpdated(oldDelay, minimumUpdateDelayInSeconds);
}
/**
* @notice Update the allowed upper bound change of exchange rate between `updateExchangeRateCalls`.
* @dev Callable by OWNER_ROLE.
*/
function updateUpper(uint16 allowedExchangeRateChangeUpper) external requiresAuth {
if (allowedExchangeRateChangeUpper < 1e4) revert AccountantWithRateProviders__UpperBoundTooSmall();
uint16 oldBound = accountantState.allowedExchangeRateChangeUpper;
accountantState.allowedExchangeRateChangeUpper = allowedExchangeRateChangeUpper;
emit UpperBoundUpdated(oldBound, allowedExchangeRateChangeUpper);
}
/**
* @notice Update the allowed lower bound change of exchange rate between `updateExchangeRateCalls`.
* @dev Callable by OWNER_ROLE.
*/
function updateLower(uint16 allowedExchangeRateChangeLower) external requiresAuth {
if (allowedExchangeRateChangeLower > 1e4) revert AccountantWithRateProviders__LowerBoundTooLarge();
uint16 oldBound = accountantState.allowedExchangeRateChangeLower;
accountantState.allowedExchangeRateChangeLower = allowedExchangeRateChangeLower;
emit LowerBoundUpdated(oldBound, allowedExchangeRateChangeLower);
}
/**
* @notice Update the platform fee to a new value.
* @dev Callable by OWNER_ROLE.
*/
function updatePlatformFee(uint16 platformFee) external requiresAuth {
if (platformFee > 0.2e4) revert AccountantWithRateProviders__PlatformFeeTooLarge();
uint16 oldFee = accountantState.platformFee;
accountantState.platformFee = platformFee;
emit PlatformFeeUpdated(oldFee, platformFee);
}
/**
* @notice Update the performance fee to a new value.
* @dev Callable by OWNER_ROLE.
*/
function updatePerformanceFee(uint16 performanceFee) external requiresAuth {
if (performanceFee > 0.5e4) revert AccountantWithRateProviders__PerformanceFeeTooLarge();
uint16 oldFee = accountantState.performanceFee;
accountantState.performanceFee = performanceFee;
emit PerformanceFeeUpdated(oldFee, performanceFee);
}
/**
* @notice Update the payout address fees are sent to.
* @dev Callable by OWNER_ROLE.
*/
function updatePayoutAddress(address payoutAddress) external requiresAuth {
address oldPayout = accountantState.payoutAddress;
accountantState.payoutAddress = payoutAddress;
emit PayoutAddressUpdated(oldPayout, payoutAddress);
}
/**
* @notice Update the rate provider data for a specific `asset`.
* @dev Rate providers must return rates in terms of `base` or
* an asset pegged to base and they must use the same decimals
* as `asset`.
* @dev Callable by OWNER_ROLE.
*/
function setRateProviderData(ERC20 asset, bool isPeggedToBase, address rateProvider) external requiresAuth {
rateProviderData[asset] =
RateProviderData({isPeggedToBase: isPeggedToBase, rateProvider: IRateProvider(rateProvider)});
emit RateProviderUpdated(address(asset), isPeggedToBase, rateProvider);
}
/**
* @notice Reset the highwater mark to the current exchange rate.
* @dev Callable by OWNER_ROLE.
*/
function resetHighwaterMark() external virtual requiresAuth {
AccountantState storage state = accountantState;
if (state.exchangeRate > state.highwaterMark) {
revert AccountantWithRateProviders__ExchangeRateAboveHighwaterMark();
}
uint64 currentTime = uint64(block.timestamp);
uint256 currentTotalShares = vault.totalSupply();
_calculateFeesOwed(state, state.exchangeRate, state.exchangeRate, currentTotalShares, currentTime);
state.totalSharesLastUpdate = uint128(currentTotalShares);
state.highwaterMark = accountantState.exchangeRate;
state.lastUpdateTimestamp = currentTime;
emit HighwaterMarkReset();
}
// ========================================= UPDATE EXCHANGE RATE/FEES FUNCTIONS =========================================
/**
* @notice Updates this contract exchangeRate.
* @dev If new exchange rate is outside of accepted bounds, or if not enough time has passed, this
* will pause the contract, and this function will NOT calculate fees owed.
* @dev Callable by UPDATE_EXCHANGE_RATE_ROLE.
*/
function updateExchangeRate(uint96 newExchangeRate) external virtual requiresAuth {
(
bool shouldPause,
AccountantState storage state,
uint64 currentTime,
uint256 currentExchangeRate,
uint256 currentTotalShares
) = _beforeUpdateExchangeRate(newExchangeRate);
if (shouldPause) {
// Instead of reverting, pause the contract. This way the exchange rate updater is able to update the exchange rate
// to a better value, and pause it.
state.isPaused = true;
} else {
_calculateFeesOwed(state, newExchangeRate, currentExchangeRate, currentTotalShares, currentTime);
}
newExchangeRate = _setExchangeRate(newExchangeRate, state);
state.totalSharesLastUpdate = uint128(currentTotalShares);
state.lastUpdateTimestamp = currentTime;
emit ExchangeRateUpdated(uint96(currentExchangeRate), newExchangeRate, currentTime);
}
/**
* @notice Claim pending fees.
* @dev This function must be called by the BoringVault.
* @dev This function will lose precision if the exchange rate
* decimals is greater than the feeAsset's decimals.
*/
function claimFees(ERC20 feeAsset) external {
if (msg.sender != address(vault)) revert AccountantWithRateProviders__OnlyCallableByBoringVault();
AccountantState storage state = accountantState;
if (state.isPaused) revert AccountantWithRateProviders__Paused();
if (state.feesOwedInBase == 0) revert AccountantWithRateProviders__ZeroFeesOwed();
// Determine amount of fees owed in feeAsset.
uint256 feesOwedInFeeAsset;
RateProviderData memory data = rateProviderData[feeAsset];
if (address(feeAsset) == address(base)) {
feesOwedInFeeAsset = state.feesOwedInBase;
} else {
uint8 feeAssetDecimals = ERC20(feeAsset).decimals();
uint256 feesOwedInBaseUsingFeeAssetDecimals =
_changeDecimals(state.feesOwedInBase, decimals, feeAssetDecimals);
if (data.isPeggedToBase) {
feesOwedInFeeAsset = feesOwedInBaseUsingFeeAssetDecimals;
} else {
uint256 rate = data.rateProvider.getRate();
feesOwedInFeeAsset = feesOwedInBaseUsingFeeAssetDecimals.mulDivDown(10 ** feeAssetDecimals, rate);
}
}
// Zero out fees owed.
state.feesOwedInBase = 0;
// Transfer fee asset to payout address.
feeAsset.safeTransferFrom(msg.sender, state.payoutAddress, feesOwedInFeeAsset);
emit FeesClaimed(address(feeAsset), feesOwedInFeeAsset);
}
// ========================================= VIEW FUNCTIONS =========================================
/**
* @notice Get this BoringVault's current rate in the base.
*/
function getRate() public view returns (uint256 rate) {
rate = accountantState.exchangeRate;
}
/**
* @notice Get this BoringVault's current rate in the base.
* @dev Revert if paused.
*/
function getRateSafe() external view returns (uint256 rate) {
if (accountantState.isPaused) revert AccountantWithRateProviders__Paused();
rate = getRate();
}
/**
* @notice Get this BoringVault's current rate in the provided quote.
* @dev `quote` must have its RateProviderData set, else this will revert.
* @dev This function will lose precision if the exchange rate
* decimals is greater than the quote's decimals.
*/
function getRateInQuote(ERC20 quote) public view returns (uint256 rateInQuote) {
if (address(quote) == address(base)) {
rateInQuote = accountantState.exchangeRate;
} else {
RateProviderData memory data = rateProviderData[quote];
uint8 quoteDecimals = ERC20(quote).decimals();
uint256 exchangeRateInQuoteDecimals = _changeDecimals(accountantState.exchangeRate, decimals, quoteDecimals);
if (data.isPeggedToBase) {
rateInQuote = exchangeRateInQuoteDecimals;
} else {
uint256 quoteRate = data.rateProvider.getRate();
uint256 oneQuote = 10 ** quoteDecimals;
rateInQuote = oneQuote.mulDivDown(exchangeRateInQuoteDecimals, quoteRate);
}
}
}
/**
* @notice Get this BoringVault's current rate in the provided quote.
* @dev `quote` must have its RateProviderData set, else this will revert.
* @dev Revert if paused.
*/
function getRateInQuoteSafe(ERC20 quote) external view returns (uint256 rateInQuote) {
if (accountantState.isPaused) revert AccountantWithRateProviders__Paused();
rateInQuote = getRateInQuote(quote);
}
/**
* @notice Preview the result of an update to the exchange rate.
* @return updateWillPause Whether the update will pause the contract.
* @return newFeesOwedInBase The new fees owed in base.
* @return totalFeesOwedInBase The total fees owed in base.
*/
function previewUpdateExchangeRate(uint96 newExchangeRate)
external
view
virtual
returns (bool updateWillPause, uint256 newFeesOwedInBase, uint256 totalFeesOwedInBase)
{
(
bool shouldPause,
AccountantState storage state,
uint64 currentTime,
uint256 currentExchangeRate,
uint256 currentTotalShares
) = _beforeUpdateExchangeRate(newExchangeRate);
updateWillPause = shouldPause;
totalFeesOwedInBase = state.feesOwedInBase;
if (!shouldPause) {
(uint256 platformFeesOwedInBase, uint256 shareSupplyToUse) = _calculatePlatformFee(
state.totalSharesLastUpdate,
state.lastUpdateTimestamp,
state.platformFee,
newExchangeRate,
currentExchangeRate,
currentTotalShares,
currentTime
);
uint256 performanceFeesOwedInBase;
if (newExchangeRate > state.highwaterMark) {
(performanceFeesOwedInBase,) = _calculatePerformanceFee(
newExchangeRate, shareSupplyToUse, state.highwaterMark, state.performanceFee
);
}
newFeesOwedInBase = platformFeesOwedInBase + performanceFeesOwedInBase;
totalFeesOwedInBase += newFeesOwedInBase;
}
}
// ========================================= INTERNAL HELPER FUNCTIONS =========================================
/**
* @notice Used to change the decimals of precision used for an amount.
*/
function _changeDecimals(uint256 amount, uint8 fromDecimals, uint8 toDecimals) internal pure returns (uint256) {
if (fromDecimals == toDecimals) {
return amount;
} else if (fromDecimals < toDecimals) {
return amount * 10 ** (toDecimals - fromDecimals);
} else {
return amount / 10 ** (fromDecimals - toDecimals);
}
}
/**
* @notice Check if the new exchange rate is outside of the allowed bounds or if not enough time has passed.
*/
function _beforeUpdateExchangeRate(uint96 newExchangeRate)
internal
view
returns (
bool shouldPause,
AccountantState storage state,
uint64 currentTime,
uint256 currentExchangeRate,
uint256 currentTotalShares
)
{
state = accountantState;
if (state.isPaused) revert AccountantWithRateProviders__Paused();
currentTime = uint64(block.timestamp);
currentExchangeRate = state.exchangeRate;
currentTotalShares = vault.totalSupply();
shouldPause = currentTime < state.lastUpdateTimestamp + state.minimumUpdateDelayInSeconds
|| newExchangeRate > currentExchangeRate.mulDivDown(state.allowedExchangeRateChangeUpper, 1e4)
|| newExchangeRate < currentExchangeRate.mulDivDown(state.allowedExchangeRateChangeLower, 1e4);
}
/**
* @notice Set the exchange rate.
*/
function _setExchangeRate(uint96 newExchangeRate, AccountantState storage state)
internal
virtual
returns (uint96)
{
state.exchangeRate = newExchangeRate;
return newExchangeRate;
}
/**
* @notice Calculate platform fees.
*/
function _calculatePlatformFee(
uint128 totalSharesLastUpdate,
uint64 lastUpdateTimestamp,
uint16 platformFee,
uint96 newExchangeRate,
uint256 currentExchangeRate,
uint256 currentTotalShares,
uint64 currentTime
) internal view returns (uint256 platformFeesOwedInBase, uint256 shareSupplyToUse) {
shareSupplyToUse = currentTotalShares;
// Use the minimum between current total supply and total supply for last update.
if (totalSharesLastUpdate < shareSupplyToUse) {
shareSupplyToUse = totalSharesLastUpdate;
}
// Determine platform fees owned.
if (platformFee > 0) {
uint256 timeDelta = currentTime - lastUpdateTimestamp;
uint256 minimumAssets = newExchangeRate > currentExchangeRate
? shareSupplyToUse.mulDivDown(currentExchangeRate, ONE_SHARE)
: shareSupplyToUse.mulDivDown(newExchangeRate, ONE_SHARE);
uint256 platformFeesAnnual = minimumAssets.mulDivDown(platformFee, 1e4);
platformFeesOwedInBase = platformFeesAnnual.mulDivDown(timeDelta, 365 days);
}
}
/**
* @notice Calculate performance fees.
*/
function _calculatePerformanceFee(
uint96 newExchangeRate,
uint256 shareSupplyToUse,
uint96 datum,
uint16 performanceFee
) internal view returns (uint256 performanceFeesOwedInBase, uint256 yieldEarned) {
uint256 changeInExchangeRate = newExchangeRate - datum;
yieldEarned = changeInExchangeRate.mulDivDown(shareSupplyToUse, ONE_SHARE);
if (performanceFee > 0) {
performanceFeesOwedInBase = yieldEarned.mulDivDown(performanceFee, 1e4);
}
}
/**
* @notice Calculate fees owed in base.
* @dev This function will update the highwater mark if the new exchange rate is higher.
*/
function _calculateFeesOwed(
AccountantState storage state,
uint96 newExchangeRate,
uint256 currentExchangeRate,
uint256 currentTotalShares,
uint64 currentTime
) internal virtual {
// Only update fees if we are not paused.
// Update fee accounting.
(uint256 newFeesOwedInBase, uint256 shareSupplyToUse) = _calculatePlatformFee(
state.totalSharesLastUpdate,
state.lastUpdateTimestamp,
state.platformFee,
newExchangeRate,
currentExchangeRate,
currentTotalShares,
currentTime
);
// Account for performance fees.
if (newExchangeRate > state.highwaterMark) {
(uint256 performanceFeesOwedInBase,) =
_calculatePerformanceFee(newExchangeRate, shareSupplyToUse, state.highwaterMark, state.performanceFee);
// Add performance fees to fees owed.
newFeesOwedInBase += performanceFeesOwedInBase;
// Always update the highwater mark if the new exchange rate is higher.
// This way if we are not iniitiall taking performance fees, we can start taking them
// without back charging them on past performance.
state.highwaterMark = newExchangeRate;
}
state.feesOwedInBase += uint128(newFeesOwedInBase);
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
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: 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);
}// 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: UNLICENSED
pragma solidity 0.8.21;
import {Address} from "@openzeppelin/contracts/utils/Address.sol";
import {ERC721Holder} from "@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol";
import {ERC1155Holder} from "@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol";
import {FixedPointMathLib} from "@solmate/utils/FixedPointMathLib.sol";
import {SafeTransferLib} from "@solmate/utils/SafeTransferLib.sol";
import {ERC20} from "@solmate/tokens/ERC20.sol";
import {BeforeTransferHook} from "src/interfaces/BeforeTransferHook.sol";
import {Auth, Authority} from "@solmate/auth/Auth.sol";
contract BoringVault is ERC20, Auth, ERC721Holder, ERC1155Holder {
using Address for address;
using SafeTransferLib for ERC20;
using FixedPointMathLib for uint256;
// ========================================= STATE =========================================
/**
* @notice Contract responsbile for implementing `beforeTransfer`.
*/
BeforeTransferHook public hook;
//============================== EVENTS ===============================
event Enter(address indexed from, address indexed asset, uint256 amount, address indexed to, uint256 shares);
event Exit(address indexed to, address indexed asset, uint256 amount, address indexed from, uint256 shares);
//============================== CONSTRUCTOR ===============================
constructor(address _owner, string memory _name, string memory _symbol, uint8 _decimals)
ERC20(_name, _symbol, _decimals)
Auth(_owner, Authority(address(0)))
{}
//============================== MANAGE ===============================
/**
* @notice Allows manager to make an arbitrary function call from this contract.
* @dev Callable by MANAGER_ROLE.
*/
function manage(address target, bytes calldata data, uint256 value)
external
requiresAuth
returns (bytes memory result)
{
result = target.functionCallWithValue(data, value);
}
/**
* @notice Allows manager to make arbitrary function calls from this contract.
* @dev Callable by MANAGER_ROLE.
*/
function manage(address[] calldata targets, bytes[] calldata data, uint256[] calldata values)
external
requiresAuth
returns (bytes[] memory results)
{
uint256 targetsLength = targets.length;
results = new bytes[](targetsLength);
for (uint256 i; i < targetsLength; ++i) {
results[i] = targets[i].functionCallWithValue(data[i], values[i]);
}
}
//============================== ENTER ===============================
/**
* @notice Allows minter to mint shares, in exchange for assets.
* @dev If assetAmount is zero, no assets are transferred in.
* @dev Callable by MINTER_ROLE.
*/
function enter(address from, ERC20 asset, uint256 assetAmount, address to, uint256 shareAmount)
external
requiresAuth
{
// Transfer assets in
if (assetAmount > 0) asset.safeTransferFrom(from, address(this), assetAmount);
// Mint shares.
_mint(to, shareAmount);
emit Enter(from, address(asset), assetAmount, to, shareAmount);
}
//============================== EXIT ===============================
/**
* @notice Allows burner to burn shares, in exchange for assets.
* @dev If assetAmount is zero, no assets are transferred out.
* @dev Callable by BURNER_ROLE.
*/
function exit(address to, ERC20 asset, uint256 assetAmount, address from, uint256 shareAmount)
external
requiresAuth
{
// Burn shares.
_burn(from, shareAmount);
// Transfer assets out.
if (assetAmount > 0) asset.safeTransfer(to, assetAmount);
emit Exit(to, address(asset), assetAmount, from, shareAmount);
}
//============================== BEFORE TRANSFER HOOK ===============================
/**
* @notice Sets the share locker.
* @notice If set to zero address, the share locker logic is disabled.
* @dev Callable by OWNER_ROLE.
*/
function setBeforeTransferHook(address _hook) external requiresAuth {
hook = BeforeTransferHook(_hook);
}
/**
* @notice Call `beforeTransferHook` passing in `from` `to`, and `msg.sender`.
*/
function _callBeforeTransfer(address from, address to) internal view {
if (address(hook) != address(0)) hook.beforeTransfer(from, to, msg.sender);
}
function transfer(address to, uint256 amount) public override returns (bool) {
_callBeforeTransfer(msg.sender, to);
return super.transfer(to, amount);
}
function transferFrom(address from, address to, uint256 amount) public override returns (bool) {
_callBeforeTransfer(from, to);
return super.transferFrom(from, to, amount);
}
//============================== RECEIVE ===============================
receive() external payable {}
}// SPDX-License-Identifier: 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: 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: Unlicense /* * @title Solidity Bytes Arrays Utils * @author Gonçalo Sá <[email protected]> * * @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity. * The library lets you concatenate, slice and type cast bytes arrays both in memory and storage. */ pragma solidity >=0.8.0 <0.9.0; library BytesLib { function concat( bytes memory _preBytes, bytes memory _postBytes ) internal pure returns (bytes memory) { bytes memory tempBytes; assembly { // Get a location of some free memory and store it in tempBytes as // Solidity does for memory variables. tempBytes := mload(0x40) // Store the length of the first bytes array at the beginning of // the memory for tempBytes. let length := mload(_preBytes) mstore(tempBytes, length) // Maintain a memory counter for the current write location in the // temp bytes array by adding the 32 bytes for the array length to // the starting location. let mc := add(tempBytes, 0x20) // Stop copying when the memory counter reaches the length of the // first bytes array. let end := add(mc, length) for { // Initialize a copy counter to the start of the _preBytes data, // 32 bytes into its memory. let cc := add(_preBytes, 0x20) } lt(mc, end) { // Increase both counters by 32 bytes each iteration. mc := add(mc, 0x20) cc := add(cc, 0x20) } { // Write the _preBytes data into the tempBytes memory 32 bytes // at a time. mstore(mc, mload(cc)) } // Add the length of _postBytes to the current length of tempBytes // and store it as the new length in the first 32 bytes of the // tempBytes memory. length := mload(_postBytes) mstore(tempBytes, add(length, mload(tempBytes))) // Move the memory counter back from a multiple of 0x20 to the // actual end of the _preBytes data. mc := end // Stop copying when the memory counter reaches the new combined // length of the arrays. end := add(mc, length) for { let cc := add(_postBytes, 0x20) } lt(mc, end) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { mstore(mc, mload(cc)) } // Update the free-memory pointer by padding our last write location // to 32 bytes: add 31 bytes to the end of tempBytes to move to the // next 32 byte block, then round down to the nearest multiple of // 32. If the sum of the length of the two arrays is zero then add // one before rounding down to leave a blank 32 bytes (the length block with 0). mstore(0x40, and( add(add(end, iszero(add(length, mload(_preBytes)))), 31), not(31) // Round down to the nearest 32 bytes. )) } return tempBytes; } function concatStorage(bytes storage _preBytes, bytes memory _postBytes) internal { assembly { // Read the first 32 bytes of _preBytes storage, which is the length // of the array. (We don't need to use the offset into the slot // because arrays use the entire slot.) let fslot := sload(_preBytes.slot) // Arrays of 31 bytes or less have an even value in their slot, // while longer arrays have an odd value. The actual length is // the slot divided by two for odd values, and the lowest order // byte divided by two for even values. // If the slot is even, bitwise and the slot with 255 and divide by // two to get the length. If the slot is odd, bitwise and the slot // with -1 and divide by two. let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2) let mlength := mload(_postBytes) let newlength := add(slength, mlength) // slength can contain both the length and contents of the array // if length < 32 bytes so let's prepare for that // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage switch add(lt(slength, 32), lt(newlength, 32)) case 2 { // Since the new array still fits in the slot, we just need to // update the contents of the slot. // uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length sstore( _preBytes.slot, // all the modifications to the slot are inside this // next block add( // we can just add to the slot contents because the // bytes we want to change are the LSBs fslot, add( mul( div( // load the bytes from memory mload(add(_postBytes, 0x20)), // zero all bytes to the right exp(0x100, sub(32, mlength)) ), // and now shift left the number of bytes to // leave space for the length in the slot exp(0x100, sub(32, newlength)) ), // increase length by the double of the memory // bytes length mul(mlength, 2) ) ) ) } case 1 { // The stored value fits in the slot, but the combined value // will exceed it. // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) let sc := add(keccak256(0x0, 0x20), div(slength, 32)) // save new length sstore(_preBytes.slot, add(mul(newlength, 2), 1)) // The contents of the _postBytes array start 32 bytes into // the structure. Our first read should obtain the `submod` // bytes that can fit into the unused space in the last word // of the stored array. To get this, we read 32 bytes starting // from `submod`, so the data we read overlaps with the array // contents by `submod` bytes. Masking the lowest-order // `submod` bytes allows us to add that value directly to the // stored value. let submod := sub(32, slength) let mc := add(_postBytes, submod) let end := add(_postBytes, mlength) let mask := sub(exp(0x100, submod), 1) sstore( sc, add( and( fslot, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00 ), and(mload(mc), mask) ) ) for { mc := add(mc, 0x20) sc := add(sc, 1) } lt(mc, end) { sc := add(sc, 1) mc := add(mc, 0x20) } { sstore(sc, mload(mc)) } mask := exp(0x100, sub(mc, end)) sstore(sc, mul(div(mload(mc), mask), mask)) } default { // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) // Start copying to the last used word of the stored array. let sc := add(keccak256(0x0, 0x20), div(slength, 32)) // save new length sstore(_preBytes.slot, add(mul(newlength, 2), 1)) // Copy over the first `submod` bytes of the new data as in // case 1 above. let slengthmod := mod(slength, 32) let mlengthmod := mod(mlength, 32) let submod := sub(32, slengthmod) let mc := add(_postBytes, submod) let end := add(_postBytes, mlength) let mask := sub(exp(0x100, submod), 1) sstore(sc, add(sload(sc), and(mload(mc), mask))) for { sc := add(sc, 1) mc := add(mc, 0x20) } lt(mc, end) { sc := add(sc, 1) mc := add(mc, 0x20) } { sstore(sc, mload(mc)) } mask := exp(0x100, sub(mc, end)) sstore(sc, mul(div(mload(mc), mask), mask)) } } } function slice( bytes memory _bytes, uint256 _start, uint256 _length ) internal pure returns (bytes memory) { require(_length + 31 >= _length, "slice_overflow"); require(_bytes.length >= _start + _length, "slice_outOfBounds"); bytes memory tempBytes; assembly { switch iszero(_length) case 0 { // Get a location of some free memory and store it in tempBytes as // Solidity does for memory variables. tempBytes := mload(0x40) // The first word of the slice result is potentially a partial // word read from the original array. To read it, we calculate // the length of that partial word and start copying that many // bytes into the array. The first word we copy will start with // data we don't care about, but the last `lengthmod` bytes will // land at the beginning of the contents of the new array. When // we're done copying, we overwrite the full first word with // the actual length of the slice. let lengthmod := and(_length, 31) // The multiplication in the next line is necessary // because when slicing multiples of 32 bytes (lengthmod == 0) // the following copy loop was copying the origin's length // and then ending prematurely not copying everything it should. let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod))) let end := add(mc, _length) for { // The multiplication in the next line has the same exact purpose // as the one above. let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start) } lt(mc, end) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { mstore(mc, mload(cc)) } mstore(tempBytes, _length) //update free-memory pointer //allocating the array padded to 32 bytes like the compiler does now mstore(0x40, and(add(mc, 31), not(31))) } //if we want a zero-length slice let's just return a zero-length array default { tempBytes := mload(0x40) //zero out the 32 bytes slice we are about to return //we need to do it because Solidity does not garbage collect mstore(tempBytes, 0) mstore(0x40, add(tempBytes, 0x20)) } } return tempBytes; } function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) { require(_bytes.length >= _start + 20, "toAddress_outOfBounds"); address tempAddress; assembly { tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000) } return tempAddress; } function toUint8(bytes memory _bytes, uint256 _start) internal pure returns (uint8) { require(_bytes.length >= _start + 1 , "toUint8_outOfBounds"); uint8 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x1), _start)) } return tempUint; } function toUint16(bytes memory _bytes, uint256 _start) internal pure returns (uint16) { require(_bytes.length >= _start + 2, "toUint16_outOfBounds"); uint16 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x2), _start)) } return tempUint; } function toUint32(bytes memory _bytes, uint256 _start) internal pure returns (uint32) { require(_bytes.length >= _start + 4, "toUint32_outOfBounds"); uint32 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x4), _start)) } return tempUint; } function toUint64(bytes memory _bytes, uint256 _start) internal pure returns (uint64) { require(_bytes.length >= _start + 8, "toUint64_outOfBounds"); uint64 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x8), _start)) } return tempUint; } function toUint96(bytes memory _bytes, uint256 _start) internal pure returns (uint96) { require(_bytes.length >= _start + 12, "toUint96_outOfBounds"); uint96 tempUint; assembly { tempUint := mload(add(add(_bytes, 0xc), _start)) } return tempUint; } function toUint128(bytes memory _bytes, uint256 _start) internal pure returns (uint128) { require(_bytes.length >= _start + 16, "toUint128_outOfBounds"); uint128 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x10), _start)) } return tempUint; } function toUint256(bytes memory _bytes, uint256 _start) internal pure returns (uint256) { require(_bytes.length >= _start + 32, "toUint256_outOfBounds"); uint256 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x20), _start)) } return tempUint; } function toBytes32(bytes memory _bytes, uint256 _start) internal pure returns (bytes32) { require(_bytes.length >= _start + 32, "toBytes32_outOfBounds"); bytes32 tempBytes32; assembly { tempBytes32 := mload(add(add(_bytes, 0x20), _start)) } return tempBytes32; } function equal(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bool) { bool success = true; assembly { let length := mload(_preBytes) // if lengths don't match the arrays are not equal switch eq(length, mload(_postBytes)) case 1 { // cb is a circuit breaker in the for loop since there's // no said feature for inline assembly loops // cb = 1 - don't breaker // cb = 0 - break let cb := 1 let mc := add(_preBytes, 0x20) let end := add(mc, length) for { let cc := add(_postBytes, 0x20) // the next line is the loop condition: // while(uint256(mc < end) + cb == 2) } eq(add(lt(mc, end), cb), 2) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { // if any of these checks fails then arrays are not equal if iszero(eq(mload(mc), mload(cc))) { // unsuccess: success := 0 cb := 0 } } } default { // unsuccess: success := 0 } } return success; } function equal_nonAligned(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bool) { bool success = true; assembly { let length := mload(_preBytes) // if lengths don't match the arrays are not equal switch eq(length, mload(_postBytes)) case 1 { // cb is a circuit breaker in the for loop since there's // no said feature for inline assembly loops // cb = 1 - don't breaker // cb = 0 - break let cb := 1 let endMinusWord := add(_preBytes, length) let mc := add(_preBytes, 0x20) let cc := add(_postBytes, 0x20) for { // the next line is the loop condition: // while(uint256(mc < endWord) + cb == 2) } eq(add(lt(mc, endMinusWord), cb), 2) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { // if any of these checks fails then arrays are not equal if iszero(eq(mload(mc), mload(cc))) { // unsuccess: success := 0 cb := 0 } } // Only if still successful // For <1 word tail bytes if gt(success, 0) { // Get the remainder of length/32 // length % 32 = AND(length, 32 - 1) let numTailBytes := and(length, 0x1f) let mcRem := mload(mc) let ccRem := mload(cc) for { let i := 0 // the next line is the loop condition: // while(uint256(i < numTailBytes) + cb == 2) } eq(add(lt(i, numTailBytes), cb), 2) { i := add(i, 1) } { if iszero(eq(byte(i, mcRem), byte(i, ccRem))) { // unsuccess: success := 0 cb := 0 } } } } default { // unsuccess: success := 0 } } return success; } function equalStorage( bytes storage _preBytes, bytes memory _postBytes ) internal view returns (bool) { bool success = true; assembly { // we know _preBytes_offset is 0 let fslot := sload(_preBytes.slot) // Decode the length of the stored array like in concatStorage(). let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2) let mlength := mload(_postBytes) // if lengths don't match the arrays are not equal switch eq(slength, mlength) case 1 { // slength can contain both the length and contents of the array // if length < 32 bytes so let's prepare for that // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage if iszero(iszero(slength)) { switch lt(slength, 32) case 1 { // blank the last byte which is the length fslot := mul(div(fslot, 0x100), 0x100) if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) { // unsuccess: success := 0 } } default { // cb is a circuit breaker in the for loop since there's // no said feature for inline assembly loops // cb = 1 - don't breaker // cb = 0 - break let cb := 1 // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) let sc := keccak256(0x0, 0x20) let mc := add(_postBytes, 0x20) let end := add(mc, mlength) // the next line is the loop condition: // while(uint256(mc < end) + cb == 2) for {} eq(add(lt(mc, end), cb), 2) { sc := add(sc, 1) mc := add(mc, 0x20) } { if iszero(eq(sload(sc), mload(mc))) { // unsuccess: success := 0 cb := 0 } } } } } default { // unsuccess: success := 0 } } return success; } }
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (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
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: UNLICENSED
pragma solidity 0.8.21;
import {TellerWithMultiAssetSupport, ERC20} from "src/base/Roles/TellerWithMultiAssetSupport.sol";
import {MessageLib} from "src/base/Roles/CrossChain/MessageLib.sol";
abstract contract CrossChainTellerWithGenericBridge is TellerWithMultiAssetSupport {
using MessageLib for uint256;
using MessageLib for MessageLib.Message;
//============================== ERRORS ===============================
error CrossChainTellerWithGenericBridge__UnsafeCastToUint96();
//============================== EVENTS ===============================
event MessageSent(bytes32 indexed messageId, uint256 shareAmount, address indexed to);
event MessageReceived(bytes32 indexed messageId, uint256 shareAmount, address indexed to);
//============================== IMMUTABLES ===============================
constructor(address _owner, address _vault, address _accountant, address _weth)
TellerWithMultiAssetSupport(_owner, _vault, _accountant, _weth)
{}
// ========================================= PUBLIC FUNCTIONS =========================================
/**
* @notice Deposit an asset and bridge the shares to another chain.
* @dev This function will REVERT if `beforeTransfer` hook reverts from:
* - shares being locked
* - allow list
* @dev Since call to `bridge` is public, msg.sig is not updated which means any role capabilities regarding this function
* are also granted to the `bridge` function.
*/
function depositAndBridge(
ERC20 depositAsset,
uint256 depositAmount,
uint256 minimumMint,
address to,
bytes calldata bridgeWildCard,
ERC20 feeToken,
uint256 maxFee
)
external
payable
requiresAuth
nonReentrant
revertOnNativeDeposit(address(depositAsset))
returns (uint256 sharesBridged)
{
// Deposit
Asset memory asset = _beforeDeposit(depositAsset);
sharesBridged = _erc20Deposit(depositAsset, depositAmount, minimumMint, msg.sender, msg.sender, asset);
_afterPublicDeposit(msg.sender, depositAsset, depositAmount, sharesBridged, shareLockPeriod);
// Bridge shares
if (sharesBridged > type(uint96).max) revert CrossChainTellerWithGenericBridge__UnsafeCastToUint96();
_bridge(uint96(sharesBridged), to, bridgeWildCard, feeToken, maxFee);
}
/**
* @notice Deposit an asset and bridge the shares to another chain using a permit.
* @dev This function will REVERT if `beforeTransfer` hook reverts from:
* - shares being locked
* - allow list
* @dev Since calls to `depositWithPermit` and `bridge` are public, msg.sig is not updated which means any role capabilities regarding this function
* are also granted to the `depositWithPermit` and `bridge` function.
*/
function depositAndBridgeWithPermit(
ERC20 depositAsset,
uint256 depositAmount,
uint256 minimumMint,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s,
address to,
bytes calldata bridgeWildCard,
ERC20 feeToken,
uint256 maxFee
)
external
payable
requiresAuth
nonReentrant
revertOnNativeDeposit(address(depositAsset))
returns (uint256 sharesBridged)
{
// Permit deposit
{
Asset memory asset = _beforeDeposit(depositAsset);
_handlePermit(depositAsset, depositAmount, deadline, v, r, s);
sharesBridged = _erc20Deposit(depositAsset, depositAmount, minimumMint, msg.sender, msg.sender, asset);
}
_afterPublicDeposit(msg.sender, depositAsset, depositAmount, sharesBridged, shareLockPeriod);
// Bridge shares
if (sharesBridged > type(uint96).max) revert CrossChainTellerWithGenericBridge__UnsafeCastToUint96();
_bridge(uint96(sharesBridged), to, bridgeWildCard, feeToken, maxFee);
}
/**
* @notice Bridge shares to another chain.
* @param shareAmount The amount of shares to bridge.
* @param to The address to send the shares to on the other chain.
* @param bridgeWildCard The bridge specific data to configure message.
* @param feeToken The token to pay the bridge fee in.
* @param maxFee The maximum fee to pay the bridge.
*/
function bridge(uint96 shareAmount, address to, bytes calldata bridgeWildCard, ERC20 feeToken, uint256 maxFee)
external
payable
requiresAuth
nonReentrant
{
if (isPaused) revert TellerWithMultiAssetSupport__Paused();
_bridge(shareAmount, to, bridgeWildCard, feeToken, maxFee);
}
/**
* @notice Preview fee required to bridge shares in a given feeToken.
*/
function previewFee(uint96 shareAmount, address to, bytes calldata bridgeWildCard, ERC20 feeToken)
external
view
returns (uint256 fee)
{
MessageLib.Message memory m = MessageLib.Message(shareAmount, to);
uint256 message = m.messageToUint256();
return _previewFee(message, bridgeWildCard, feeToken);
}
// ========================================= INTERNAL BRIDGE FUNCTIONS =========================================
/**
* @notice Implement the bridge logic.
*/
function _bridge(uint96 shareAmount, address to, bytes calldata bridgeWildCard, ERC20 feeToken, uint256 maxFee)
internal
{
// Since shares are directly burned, call `beforeTransfer` to enforce before transfer hooks.
beforeTransfer(msg.sender, address(0), msg.sender);
// Burn shares from sender
vault.exit(address(0), ERC20(address(0)), 0, msg.sender, shareAmount);
// Send the message.
MessageLib.Message memory m = MessageLib.Message(shareAmount, to);
// `messageToUnit256` reverts on overflow, eventhough it is not possible to overflow.
// This was done for future proofing.
uint256 message = m.messageToUint256();
bytes32 messageId = _sendMessage(message, bridgeWildCard, feeToken, maxFee);
emit MessageSent(messageId, shareAmount, to);
}
/**
* @notice Complete the message receive process, should be called in child contract once
* message has been confirmed as legit.`
*/
function _completeMessageReceive(bytes32 messageId, uint256 message) internal {
MessageLib.Message memory m = message.uint256ToMessage();
// Mint shares to message.to
vault.enter(address(0), ERC20(address(0)), 0, m.to, m.shareAmount);
emit MessageReceived(messageId, m.shareAmount, m.to);
}
/**
* @notice Send the message to the bridge implementation.
* @dev This function should handle reverting if maxFee exceeds the fee required to send the message.
* @dev This function should handle collecting the fee.
* @param message The message to send.
* @param bridgeWildCard The bridge specific data to configure message.
* @param feeToken The token to pay the bridge fee in.
* @param maxFee The maximum fee to pay the bridge.
*/
function _sendMessage(uint256 message, bytes calldata bridgeWildCard, ERC20 feeToken, uint256 maxFee)
internal
virtual
returns (bytes32 messageId);
/**
* @notice Preview fee required to bridge shares in a given token.
*/
function _previewFee(uint256 message, bytes calldata bridgeWildCard, ERC20 feeToken)
internal
view
virtual
returns (uint256 fee);
}// SPDX-License-Identifier: 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: 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: 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: 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
pragma solidity ^0.8.0;
/**
* @title Rate Limiter
* @dev Extends LayerZero's evm-oapp v2 RateLimiter contract. The original contract only supports rate limiting for outbound messages.
* This contract adds support for rate limiting inbound messages.
*/
abstract contract PairwiseRateLimiter {
/**
* @notice Rate Limit struct.
* @param amountInFlight The amount in the current window.
* @param lastUpdated Timestamp representing the last time the rate limit was checked or updated.
* @param limit This represents the maximum allowed amount within a given window.
* @param window Defines the duration of the rate limiting window.
*/
struct RateLimit {
uint256 amountInFlight;
uint256 lastUpdated;
uint256 limit;
uint256 window;
}
/**
* @notice Rate Limit Configuration struct.
* @param dstEid The peer endpoint id.
* @param limit This represents the maximum allowed amount within a given window.
* @param window Defines the duration of the rate limiting window.
*/
struct RateLimitConfig {
uint32 peerEid;
uint256 limit;
uint256 window;
}
/**
* @dev Mapping from peer endpoint id to RateLimit Configurations.
*/
mapping(uint32 dstEid => RateLimit limit) public outboundRateLimits;
mapping(uint32 srcEid => RateLimit limit) public inboundRateLimits;
/**
* @notice Emitted when _setRateLimits occurs.
* @param rateLimitConfigs An array of `RateLimitConfig` structs representing the rate limit configurations set.
* - `peerEid`: The peer endpoint id.
* - `limit`: This represents the maximum allowed amount within a given window.
* - `window`: Defines the duration of the rate limiting window.
*/
event OutboundRateLimitsChanged(RateLimitConfig[] rateLimitConfigs);
event InboundRateLimitsChanged(RateLimitConfig[] rateLimitConfigs);
/**
* @notice Error that is thrown when an amount exceeds the rate_limit.
*/
error OutboundRateLimitExceeded();
error InboundRateLimitExceeded();
/**
* @notice Get the current amount that can be sent to this peer endpoint id for the given rate limit window.
* @param _dstEid The destination endpoint id.
* @return outboundAmountInFlight The current amount that was sent.
* @return amountCanBeSent The amount that can be sent.
*/
function getAmountCanBeSent(uint32 _dstEid)
external
view
virtual
returns (uint256 outboundAmountInFlight, uint256 amountCanBeSent)
{
RateLimit memory rl = outboundRateLimits[_dstEid];
return _amountCanBeSent(rl.amountInFlight, rl.lastUpdated, rl.limit, rl.window);
}
/**
* @notice Get the current amount that can received from this peer endpoint for the given rate limit window.
* @param _srcEid The source endpoint id.
* @return inboundAmountInFlight The current amount has been received.
* @return amountCanBeReceived The amount that be received.
*/
function getAmountCanBeReceived(uint32 _srcEid)
external
view
virtual
returns (uint256 inboundAmountInFlight, uint256 amountCanBeReceived)
{
RateLimit memory rl = inboundRateLimits[_srcEid];
return _amountCanBeSent(rl.amountInFlight, rl.lastUpdated, rl.limit, rl.window);
}
/**
* @notice Sets the Rate Limit.
* @param _rateLimitConfigs A `RateLimitConfig` struct representing the rate limit configuration.
* - `dstEid`: The destination endpoint id.
* - `limit`: This represents the maximum allowed amount within a given window.
* - `window`: Defines the duration of the rate limiting window.
*/
function _setOutboundRateLimits(RateLimitConfig[] memory _rateLimitConfigs) internal virtual {
unchecked {
for (uint256 i = 0; i < _rateLimitConfigs.length; i++) {
RateLimit storage rl = outboundRateLimits[_rateLimitConfigs[i].peerEid];
// @dev Ensure we checkpoint the existing rate limit as to not retroactively apply the new decay rate.
_checkAndUpdateOutboundRateLimit(_rateLimitConfigs[i].peerEid, 0);
// @dev Does NOT reset the amountInFlight/lastUpdated of an existing rate limit.
rl.limit = _rateLimitConfigs[i].limit;
rl.window = _rateLimitConfigs[i].window;
}
}
emit OutboundRateLimitsChanged(_rateLimitConfigs);
}
/**
* @notice Sets the Rate Limit.
* @param _rateLimitConfigs A `RateLimitConfig` struct representing the rate limit configuration.
* - `srcEid`: The source endpoint id.
* - `limit`: This represents the maximum allowed amount within a given window.
* - `window`: Defines the duration of the rate limiting window.
*/
function _setInboundRateLimits(RateLimitConfig[] memory _rateLimitConfigs) internal virtual {
unchecked {
for (uint256 i = 0; i < _rateLimitConfigs.length; i++) {
RateLimit storage rl = inboundRateLimits[_rateLimitConfigs[i].peerEid];
// @dev Ensure we checkpoint the existing rate limit as to not retroactively apply the new decay rate.
_checkAndUpdateInboundRateLimit(_rateLimitConfigs[i].peerEid, 0);
// @dev Does NOT reset the amountInFlight/lastUpdated of an existing rate limit.
rl.limit = _rateLimitConfigs[i].limit;
rl.window = _rateLimitConfigs[i].window;
}
}
emit InboundRateLimitsChanged(_rateLimitConfigs);
}
/**
* @notice Checks current amount in flight and amount that can be sent for a given rate limit window.
* @param _amountInFlight The amount in the current window.
* @param _lastUpdated Timestamp representing the last time the rate limit was checked or updated.
* @param _limit This represents the maximum allowed amount within a given window.
* @param _window Defines the duration of the rate limiting window.
* @return currentAmountInFlight The amount in the current window.
* @return amountCanBeSent The amount that can be sent.
*/
function _amountCanBeSent(uint256 _amountInFlight, uint256 _lastUpdated, uint256 _limit, uint256 _window)
internal
view
virtual
returns (uint256 currentAmountInFlight, uint256 amountCanBeSent)
{
uint256 timeSinceLastDeposit = block.timestamp - _lastUpdated;
if (timeSinceLastDeposit >= _window) {
currentAmountInFlight = 0;
amountCanBeSent = _limit;
} else {
// @dev Presumes linear decay.
uint256 decay = (_limit * timeSinceLastDeposit) / _window;
currentAmountInFlight = _amountInFlight <= decay ? 0 : _amountInFlight - decay;
// @dev In the event the _limit is lowered, and the 'in-flight' amount is higher than the _limit, set to 0.
amountCanBeSent = _limit <= currentAmountInFlight ? 0 : _limit - currentAmountInFlight;
}
}
/**
* @notice Verifies whether the specified amount falls within the rate limit constraints for the targeted
* endpoint ID. On successful verification, it updates amountInFlight and lastUpdated. If the amount exceeds
* the rate limit, the operation reverts.
* @param _dstEid The destination endpoint id.
* @param _amount The amount to check for rate limit constraints.
*/
function _checkAndUpdateOutboundRateLimit(uint32 _dstEid, uint256 _amount) internal virtual {
// @dev By default dstEid that have not been explicitly set will return amountCanBeSent == 0.
RateLimit storage rl = outboundRateLimits[_dstEid];
(uint256 currentAmountInFlight, uint256 amountCanBeSent) =
_amountCanBeSent(rl.amountInFlight, rl.lastUpdated, rl.limit, rl.window);
if (_amount > amountCanBeSent) revert OutboundRateLimitExceeded();
// @dev Update the storage to contain the new amount and current timestamp.
rl.amountInFlight = currentAmountInFlight + _amount;
rl.lastUpdated = block.timestamp;
}
/**
* @notice Verifies whether the specified amount falls within the rate limit constraints for the targeted
* endpoint ID. On successful verification, it updates amountInFlight and lastUpdated. If the amount exceeds
* the rate limit, the operation reverts.
* @param _srcEid The source endpoint id.
* @param _amount The amount to check for rate limit constraints.
*/
function _checkAndUpdateInboundRateLimit(uint32 _srcEid, uint256 _amount) internal virtual {
// @dev By default dstEid that have not been explicitly set will return amountCanBeSent == 0.
RateLimit storage rl = inboundRateLimits[_srcEid];
(uint256 currentAmountInFlight, uint256 amountCanBeSent) =
_amountCanBeSent(rl.amountInFlight, rl.lastUpdated, rl.limit, rl.window);
if (_amount > amountCanBeSent) revert InboundRateLimitExceeded();
// @dev Update the storage to contain the new amount and current timestamp.
rl.amountInFlight = currentAmountInFlight + _amount;
rl.lastUpdated = block.timestamp;
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.21;
interface IPausable {
function pause() external;
function unpause() external;
}// 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: 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;
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.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.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
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 {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
// 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: 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;
// @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: 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
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
// 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);
}{
"evmVersion": "shanghai",
"metadata": {
"appendCBOR": true,
"bytecodeHash": "ipfs",
"useLiteralContent": false
},
"optimizer": {
"enabled": true,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"abi"
]
}
},
"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/"
],
"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":"InboundRateLimitExceeded","type":"error"},{"inputs":[],"name":"InvalidDelegate","type":"error"},{"inputs":[],"name":"InvalidEndpointCall","type":"error"},{"inputs":[{"internalType":"uint16","name":"optionType","type":"uint16"}],"name":"InvalidOptionType","type":"error"},{"inputs":[],"name":"LayerZeroTeller__BadFeeToken","type":"error"},{"inputs":[{"internalType":"uint256","name":"chainSelector","type":"uint256"},{"internalType":"uint256","name":"fee","type":"uint256"},{"internalType":"uint256","name":"maxFee","type":"uint256"}],"name":"LayerZeroTeller__FeeExceedsMax","type":"error"},{"inputs":[{"internalType":"uint256","name":"chainSelector","type":"uint256"}],"name":"LayerZeroTeller__MessagesNotAllowedFrom","type":"error"},{"inputs":[{"internalType":"uint256","name":"chainSelector","type":"uint256"},{"internalType":"address","name":"sender","type":"address"}],"name":"LayerZeroTeller__MessagesNotAllowedFromSender","type":"error"},{"inputs":[{"internalType":"uint256","name":"chainSelector","type":"uint256"}],"name":"LayerZeroTeller__MessagesNotAllowedTo","type":"error"},{"inputs":[],"name":"LayerZeroTeller__ZeroMessageGasLimit","type":"error"},{"inputs":[],"name":"LzTokenUnavailable","type":"error"},{"inputs":[],"name":"MessageLib__ShareAmountOverflow","type":"error"},{"inputs":[{"internalType":"uint32","name":"eid","type":"uint32"}],"name":"NoPeer","type":"error"},{"inputs":[{"internalType":"uint256","name":"msgValue","type":"uint256"}],"name":"NotEnoughNative","type":"error"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"OnlyEndpoint","type":"error"},{"inputs":[{"internalType":"uint32","name":"eid","type":"uint32"},{"internalType":"bytes32","name":"sender","type":"bytes32"}],"name":"OnlyPeer","type":"error"},{"inputs":[],"name":"OutboundRateLimitExceeded","type":"error"},{"inputs":[{"internalType":"uint8","name":"bits","type":"uint8"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"SafeCastOverflowedUintDowncast","type":"error"},{"inputs":[],"name":"TellerWithMultiAssetSupport__AssetNotSupported","type":"error"},{"inputs":[],"name":"TellerWithMultiAssetSupport__BadDepositHash","type":"error"},{"inputs":[],"name":"TellerWithMultiAssetSupport__CannotDepositNative","type":"error"},{"inputs":[],"name":"TellerWithMultiAssetSupport__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":[{"components":[{"internalType":"uint32","name":"peerEid","type":"uint32"},{"internalType":"uint256","name":"limit","type":"uint256"},{"internalType":"uint256","name":"window","type":"uint256"}],"indexed":false,"internalType":"struct PairwiseRateLimiter.RateLimitConfig[]","name":"rateLimitConfigs","type":"tuple[]"}],"name":"InboundRateLimitsChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"messageId","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"shareAmount","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"MessageReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"messageId","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"shareAmount","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"MessageSent","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"uint32","name":"peerEid","type":"uint32"},{"internalType":"uint256","name":"limit","type":"uint256"},{"internalType":"uint256","name":"window","type":"uint256"}],"indexed":false,"internalType":"struct PairwiseRateLimiter.RateLimitConfig[]","name":"rateLimitConfigs","type":"tuple[]"}],"name":"OutboundRateLimitsChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"eid","type":"uint32"},{"indexed":false,"internalType":"bytes32","name":"peer","type":"bytes32"}],"name":"PeerSet","type":"event"},{"anonymous":false,"inputs":[{"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":"_srcEid","type":"uint32"}],"name":"getAmountCanBeReceived","outputs":[{"internalType":"uint256","name":"inboundAmountInFlight","type":"uint256"},{"internalType":"uint256","name":"amountCanBeReceived","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"_dstEid","type":"uint32"}],"name":"getAmountCanBeSent","outputs":[{"internalType":"uint256","name":"outboundAmountInFlight","type":"uint256"},{"internalType":"uint256","name":"amountCanBeSent","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"","type":"uint32"}],"name":"idToChains","outputs":[{"internalType":"bool","name":"allowMessagesFrom","type":"bool"},{"internalType":"bool","name":"allowMessagesTo","type":"bool"},{"internalType":"uint128","name":"messageGasLimit","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"srcEid","type":"uint32"}],"name":"inboundRateLimits","outputs":[{"internalType":"uint256","name":"amountInFlight","type":"uint256"},{"internalType":"uint256","name":"lastUpdated","type":"uint256"},{"internalType":"uint256","name":"limit","type":"uint256"},{"internalType":"uint256","name":"window","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"srcEid","type":"uint32"},{"internalType":"bytes32","name":"sender","type":"bytes32"},{"internalType":"uint64","name":"nonce","type":"uint64"}],"internalType":"struct Origin","name":"_origin","type":"tuple"},{"internalType":"bytes32","name":"_guid","type":"bytes32"},{"internalType":"bytes","name":"_message","type":"bytes"},{"internalType":"address","name":"_executor","type":"address"},{"internalType":"bytes","name":"_extraData","type":"bytes"}],"name":"lzReceive","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"nativeWrapper","outputs":[{"internalType":"contract WETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"","type":"uint32"},{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"nextNonce","outputs":[{"internalType":"uint64","name":"nonce","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"oAppVersion","outputs":[{"internalType":"uint64","name":"senderVersion","type":"uint64"},{"internalType":"uint64","name":"receiverVersion","type":"uint64"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint32","name":"dstEid","type":"uint32"}],"name":"outboundRateLimits","outputs":[{"internalType":"uint256","name":"amountInFlight","type":"uint256"},{"internalType":"uint256","name":"lastUpdated","type":"uint256"},{"internalType":"uint256","name":"limit","type":"uint256"},{"internalType":"uint256","name":"window","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"eid","type":"uint32"}],"name":"peers","outputs":[{"internalType":"bytes32","name":"peer","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"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":[{"components":[{"internalType":"uint32","name":"peerEid","type":"uint32"},{"internalType":"uint256","name":"limit","type":"uint256"},{"internalType":"uint256","name":"window","type":"uint256"}],"internalType":"struct PairwiseRateLimiter.RateLimitConfig[]","name":"_rateLimitConfigs","type":"tuple[]"}],"name":"setInboundRateLimits","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"peerEid","type":"uint32"},{"internalType":"uint256","name":"limit","type":"uint256"},{"internalType":"uint256","name":"window","type":"uint256"}],"internalType":"struct PairwiseRateLimiter.RateLimitConfig[]","name":"_rateLimitConfigs","type":"tuple[]"}],"name":"setOutboundRateLimits","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_eid","type":"uint32"},{"internalType":"bytes32","name":"_peer","type":"bytes32"}],"name":"setPeer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"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
6101406040526001600255600480546001600160901b03166001600160901b03191790553480156200002f575f80fd5b50604051620058963803806200589683398101604081905262000052916200025d565b5f80546001600160a01b0389166001600160a01b0319918216811783556001805490921690915560405185928592849284928d928d928d928d9286928692869286928692919033907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908490a36040516001600160a01b0382169033907fa3396fd7f6e0a21b50e5089d2da70d5ac0a3bbbd1f617a93f134b76389980198905f90a350506001600160a01b03831660808190526040805163313ce56760e01b8152905163313ce567916004808201926020929091908290030181865afa1580156200013f573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190620001659190620002ed565b6200017290600a62000425565b60c0526001600160a01b0391821660a052811660e0526004805460ff60881b191690558881166101005287169550620001c494505050505057604051632d618d8160e21b815260040160405180910390fd5b6101005160405163ca5eb5e160e01b81526001600160a01b0383811660048301529091169063ca5eb5e1906024015f604051808303815f87803b1580156200020a575f80fd5b505af11580156200021d573d5f803e3d5ffd5b5050506001600160a01b039095166101205250620004359950505050505050505050565b80516001600160a01b038116811462000258575f80fd5b919050565b5f805f805f805f60e0888a03121562000274575f80fd5b6200027f8862000241565b96506200028f6020890162000241565b95506200029f6040890162000241565b9450620002af6060890162000241565b9350620002bf6080890162000241565b9250620002cf60a0890162000241565b9150620002df60c0890162000241565b905092959891949750929550565b5f60208284031215620002fe575f80fd5b815160ff811681146200030f575f80fd5b9392505050565b634e487b7160e01b5f52601160045260245ffd5b600181815b808511156200036a57815f19048211156200034e576200034e62000316565b808516156200035c57918102915b93841c93908002906200032f565b509250929050565b5f8262000382575060016200041f565b816200039057505f6200041f565b8160018114620003a95760028114620003b457620003d4565b60019150506200041f565b60ff841115620003c857620003c862000316565b50506001821b6200041f565b5060208310610133831016604e8410600b8410161715620003f9575081810a6200041f565b6200040583836200032a565b805f19048211156200041b576200041b62000316565b0290505b92915050565b5f6200030f60ff84168362000372565b60805160a05160c05160e05161010051610120516153786200051e5f395f81816139820152613ead01525f818161085e015281816110db01528181612a21015281816141380152818161428e015281816144cb015261458201525f818161041d01528181610eec01528181610f6901528181610fb70152611d1201525f81816119f5015261323601525f81816106e701528181611986015261325801525f8181610d5901528181610f8d01528181611a5301528181611d4c01528181612faa01528181613342015281816134000152818161373f015281816137df015261400501526153785ff3fe6080604052600436106103be575f3560e01c80637d25a05e116101f4578063bf67138411610113578063d7424e33116100a8578063e96e38e211610078578063e96e38e214610ceb578063f2fde38b14610d0a578063f51b1aca14610d29578063fbfa77cf14610d48578063ff7bd03d14610d7b575f80fd5b8063d7424e3314610c50578063dbd5edc714610c6f578063de35f5cb14610cad578063e83931af14610ccc575f80fd5b8063ca5eb5e1116100e3578063ca5eb5e114610b90578063cab716e814610baf578063d182221614610bc2578063d555f36814610c31575f80fd5b8063bf67138414610b14578063bf7e214f14610b33578063c272198d14610b52578063c29d2f1014610b71575f80fd5b80639d57442011610189578063b187bd2611610159578063b187bd2614610a98578063b5ba618214610ab8578063b92d0eff14610ad7578063bb0b6a5314610ae9575f80fd5b80639d57442014610a155780639fdb11b614610a34578063a924bf6114610a5a578063abd626b014610a79575f80fd5b80638dfd8ba1116101c45780638dfd8ba11461099957806394f51289146109b85780639a94d3d0146109cb5780639ac4f42d146109f6575f80fd5b80637d25a05e146109115780638456cb59146109485780638a6733f91461095c5780638da5cb5b1461097b575f80fd5b80633d935d9e116102e057806355a2d64d116102755780635f45bac8116102455780635f45bac814610880578063703d37681461089f5780637a9e5e4b146108d35780637bd876b6146108f2575f80fd5b806355a2d64d1461076957806355b56c0c146107885780635c465430146107c85780635e280f111461084d575f80fd5b806345ad6063116102b057806345ad60631461069857806346b563f4146106b75780634fb3ccc5146106d657806351c32a8814610709575f80fd5b80633d935d9e146105e15780633e64ce99146106005780633f4ba83a1461061f57806341fee44a14610633575f80fd5b806318aed921116103565780632c524c42116103265780632c524c42146105655780633400288b1461058457806334dafd6b146105a35780633b575407146105c2575f80fd5b806318aed921146104e95780631b62636c146105085780631ba9a45814610527578063202eac5714610546575f80fd5b806312056e2d1161039157806312056e2d1461047857806313137d65146104975780631568fc58146104aa57806317442b70146104c9575f80fd5b80630511ef43146103c257806305921740146103f75780630b48a8b81461040c5780630efe6a8b14610457575b5f80fd5b3480156103cd575f80fd5b506004546103e290600160881b900460ff1681565b60405190151581526020015b60405180910390f35b61040a610405366004614722565b610d9a565b005b348015610417575f80fd5b5061043f7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016103ee565b61046a61046536600461479f565b610e40565b6040519081526020016103ee565b348015610483575f80fd5b5061040a6104923660046147e5565b611049565b61040a6104a5366004614816565b6110d9565b3480156104b5575f80fd5b5061040a6104c43660046148d7565b611194565b3480156104d4575f80fd5b506040805160018082526020820152016103ee565b3480156104f4575f80fd5b5061040a610503366004614908565b611269565b348015610513575f80fd5b5061040a610522366004614908565b61134f565b348015610532575f80fd5b5061040a610541366004614908565b6113cf565b348015610551575f80fd5b5061040a610560366004614923565b61144a565b348015610570575f80fd5b5061040a61057f366004614908565b6114f1565b34801561058f575f80fd5b5061040a61059e366004614958565b61156d565b3480156105ae575f80fd5b5061040a6105bd36600461498d565b6115ac565b3480156105cd575f80fd5b5061040a6105dc366004614908565b611700565b3480156105ec575f80fd5b5061046a6105fb366004614a04565b61177e565b34801561060b575f80fd5b5061046a61061a366004614a64565b61187c565b34801561062a575f80fd5b5061040a611b09565b34801561063e575f80fd5b5061067761064d366004614908565b60036020525f908152604090205460ff8082169161010081049091169062010000900461ffff1683565b604080519315158452911515602084015261ffff16908201526060016103ee565b3480156106a3575f80fd5b5061040a6106b2366004614aab565b611b71565b3480156106c2575f80fd5b5061040a6106d1366004614ac4565b611bfa565b3480156106e1575f80fd5b5061043f7f000000000000000000000000000000000000000000000000000000000000000081565b348015610714575f80fd5b50610749610723366004614aab565b60086020525f908152604090208054600182015460028301546003909301549192909184565b6040805194855260208501939093529183015260608201526080016103ee565b348015610774575f80fd5b5061040a610783366004614aab565b611e04565b348015610793575f80fd5b506107496107a2366004614aab565b60096020525f908152604090208054600182015460028301546003909301549192909184565b3480156107d3575f80fd5b5061081d6107e2366004614908565b60066020525f90815260409020805460019091015460ff80831692610100810482169262010000820483169263010000009092049091169085565b6040805195151586529315156020860152911515928401929092529015156060830152608082015260a0016103ee565b348015610858575f80fd5b5061043f7f000000000000000000000000000000000000000000000000000000000000000081565b34801561088b575f80fd5b5061040a61089a366004614908565b611eaa565b3480156108aa575f80fd5b506108be6108b9366004614aab565b611f24565b604080519283526020830191909152016103ee565b3480156108de575f80fd5b5061040a6108ed366004614908565b611f84565b3480156108fd575f80fd5b5061040a61090c366004614b24565b612068565b34801561091c575f80fd5b5061093061092b366004614958565b6120fa565b6040516001600160401b0390911681526020016103ee565b348015610953575f80fd5b5061040a612102565b348015610967575f80fd5b5061040a610976366004614b4a565b612170565b348015610986575f80fd5b505f5461043f906001600160a01b031681565b3480156109a4575f80fd5b5061040a6109b3366004614b65565b6121ee565b61046a6109c6366004614bb9565b612307565b3480156109d6575f80fd5b5061046a6109e5366004614c7d565b60056020525f908152604090205481565b348015610a01575f80fd5b5061040a610a10366004614908565b612440565b348015610a20575f80fd5b5061046a610a2f366004614a64565b6124c2565b348015610a3f575f80fd5b5060045461093090600160401b90046001600160401b031681565b348015610a65575f80fd5b5061040a610a74366004614908565b612587565b348015610a84575f80fd5b5061040a610a93366004614c94565b612600565b348015610aa3575f80fd5b506004546103e290600160801b900460ff1681565b348015610ac3575f80fd5b5061040a610ad2366004614cdc565b612721565b348015610ae2575f80fd5b503061043f565b348015610af4575f80fd5b5061046a610b03366004614aab565b60076020525f908152604090205481565b348015610b1f575f80fd5b5061040a610b2e366004614908565b61281e565b348015610b3e575f80fd5b5060015461043f906001600160a01b031681565b348015610b5d575f80fd5b506108be610b6c366004614aab565b61289a565b348015610b7c575f80fd5b5061040a610b8b366004614908565b6128f0565b348015610b9b575f80fd5b5061040a610baa366004614908565b6129d1565b61046a610bbd366004614d1e565b612a7b565b348015610bcd575f80fd5b50610c0b610bdc366004614aab565b600a6020525f908152604090205460ff808216916101008104909116906201000090046001600160801b031683565b60408051931515845291151560208401526001600160801b0316908201526060016103ee565b348015610c3c575f80fd5b5061040a610c4b366004614aab565b612ba2565b348015610c5b575f80fd5b5061046a610c6a366004614db0565b612c22565b348015610c7a575f80fd5b50600454610c9590600160901b90046001600160701b031681565b6040516001600160701b0390911681526020016103ee565b348015610cb8575f80fd5b50600454610930906001600160401b031681565b348015610cd7575f80fd5b5061040a610ce6366004614908565b612c6d565b348015610cf6575f80fd5b5061040a610d05366004614e25565b612cfc565b348015610d15575f80fd5b5061040a610d24366004614908565b612d87565b348015610d34575f80fd5b5061040a610d43366004614e25565b612e02565b348015610d53575f80fd5b5061043f7f000000000000000000000000000000000000000000000000000000000000000081565b348015610d86575f80fd5b506103e2610d95366004614e93565b612e8d565b610daf335f356001600160e01b031916612ec1565b610dd45760405162461bcd60e51b8152600401610dcb90614ead565b60405180910390fd5b600254600114610df65760405162461bcd60e51b8152600401610dcb90614ed3565b60028055600454600160801b900460ff1615610e255760405163e0f9e71d60e01b815260040160405180910390fd5b610e33868686868686612f67565b5050600160025550505050565b5f610e56335f356001600160e01b031916612ec1565b610e725760405162461bcd60e51b8152600401610dcb90614ead565b600254600114610e945760405162461bcd60e51b8152600401610dcb90614ed3565b600280555f610ea2856130a1565b90505f73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03871601610fde57345f03610eea5760405163259be69560e11b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004015f604051808303818588803b158015610f43575f80fd5b505af1158015610f55573d5f803e3d5ffd5b50349850610fb49350506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691507f000000000000000000000000000000000000000000000000000000000000000090508761315c565b507f0000000000000000000000000000000000000000000000000000000000000000945030611000565b3415610ffd57604051631cf02cf960e21b815260040160405180910390fd5b50335b61100e8686868433876131de565b925061103b33878786600460089054906101000a90046001600160401b03166001600160401b0316613475565b505060016002559392505050565b61105e335f356001600160e01b031916612ec1565b61107a5760405162461bcd60e51b8152600401610dcb90614ead565b6203f480816001600160401b031611156110a757604051631fac010160e21b815260040160405180910390fd5b600480546001600160401b03909216600160401b026fffffffffffffffff000000000000000019909216919091179055565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163314611124576040516391ac5e4f60e01b8152336004820152602401610dcb565b6020870180359061113e90611139908a614aab565b6135a7565b1461117c576111506020880188614aab565b60405163309afaf360e21b815263ffffffff909116600482015260208801356024820152604401610dcb565b61118b878787878787876135e2565b50505050505050565b6111a9335f356001600160e01b031916612ec1565b6111c55760405162461bcd60e51b8152600401610dcb90614ead565b806001600160801b03165f036111ee5760405163c80ed59560e01b815260040160405180910390fd5b63ffffffff82165f818152600a6020908152604091829020805462010000600160901b031916620100006001600160801b038716908102919091178255835194855291840191909152917f0aa48359f83e8464fda3f4ea4bd3f2d6af01e90b46ab9464aa7d538e1772947a91015b60405180910390a1505050565b61127e335f356001600160e01b031916612ec1565b61129a5760405162461bcd60e51b8152600401610dcb90614ead565b6001600160a01b0381165f81815260066020526040808220805462ffffff191662010101179055517fd658022b1a3aaf6ad3b3c615253712807f21a8f7bc3e4996e10618175d4afb2b9190a26040516001600160a01b038216907f79fc685a7dbabb75a67df5e69a90602cef1f19bc465b060eab1ac56685e04a13905f90a26040516001600160a01b038216907f3afb02134e37f7205acf470adc2fc4ebb70614b1599a602d069790915380e2aa905f90a250565b611364335f356001600160e01b031916612ec1565b6113805760405162461bcd60e51b8152600401610dcb90614ead565b6001600160a01b0381165f81815260066020526040808220805462ff0000191662010000179055517f3afb02134e37f7205acf470adc2fc4ebb70614b1599a602d069790915380e2aa9190a250565b6113e4335f356001600160e01b031916612ec1565b6114005760405162461bcd60e51b8152600401610dcb90614ead565b6001600160a01b0381165f81815260066020526040808220805462ff000019169055517f77cb944c14da76928795279d1519ce9150085a06e0a53c61d5a86fc4e0fd57c69190a250565b61145f335f356001600160e01b031916612ec1565b61147b5760405162461bcd60e51b8152600401610dcb90614ead565b63ffffffff82165f908152600a60205260409020805460ff191660011781556114ad836001600160a01b0384166136d5565b6040805163ffffffff851681526001600160a01b03841660208201527fe925de263dcdbdc20307c9ab92758ed8cc0edf3d173dad4a3aa54c070f27a543910161125c565b611506335f356001600160e01b031916612ec1565b6115225760405162461bcd60e51b8152600401610dcb90614ead565b6001600160a01b0381165f81815260066020526040808220805460ff19166001179055517fd658022b1a3aaf6ad3b3c615253712807f21a8f7bc3e4996e10618175d4afb2b9190a250565b611582335f356001600160e01b031916612ec1565b61159e5760405162461bcd60e51b8152600401610dcb90614ead565b6115a882826136d5565b5050565b6115c1335f356001600160e01b031916612ec1565b6115dd5760405162461bcd60e51b8152600401610dcb90614ead565b8280156115f157506001600160801b038116155b1561160f5760405163c80ed59560e01b815260040160405180910390fd5b60408051606081018252851515815284151560208083019182526001600160801b0385811684860190815263ffffffff8b165f908152600a90935294909120925183549251945161ffff1990931690151561ff00191617610100941515949094029390931762010000600160901b0319166201000091909316029190911790556116a2856001600160a01b0384166136d5565b6040805163ffffffff871681528515156020820152841515818301526001600160a01b038416606082015290517f5dbe727bffd24a6d61a5aeef919510389c66c0deeaa82634862cf4f098961fb89181900360800190a15050505050565b611715335f356001600160e01b031916612ec1565b6117315760405162461bcd60e51b8152600401610dcb90614ead565b6001600160a01b0381165f81815260066020526040808220805461ff001916610100179055517f79fc685a7dbabb75a67df5e69a90602cef1f19bc465b060eab1ac56685e04a139190a250565b5f611794335f356001600160e01b031916612ec1565b6117b05760405162461bcd60e51b8152600401610dcb90614ead565b6002546001146117d25760405162461bcd60e51b8152600401610dcb90614ed3565b600280558773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03821601611815576040516316df5df960e31b815260040160405180910390fd5b5f61181f8a6130a1565b905061182f8a8a89898989613722565b61183d8a8a8a3333866131de565b925061186a338b8b86600460089054906101000a90046001600160401b03166001600160401b0316613475565b50506001600255979650505050505050565b5f611892335f356001600160e01b031916612ec1565b6118ae5760405162461bcd60e51b8152600401610dcb90614ead565b600454600160801b900460ff16156118d95760405163e0f9e71d60e01b815260040160405180910390fd5b6001600160a01b0385165f908152600360209081526040918290208251606081018452905460ff80821615158352610100820416151592820183905262010000900461ffff16928101929092526119435760405163645fd19f60e11b815260040160405180910390fd5b845f0361196357604051630ea3153160e21b815260040160405180910390fd5b604051634104b9ed60e11b81526001600160a01b038781166004830152611a19917f00000000000000000000000000000000000000000000000000000000000000009091169063820973da90602401602060405180830381865afa1580156119cd573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119f19190614ef7565b86907f000000000000000000000000000000000000000000000000000000000000000061387a565b915083821015611a3c576040516302620f6160e61b815260040160405180910390fd5b6040516318457e6160e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906318457e6190611a909086908a90879033908c90600401614f0e565b5f604051808303815f87803b158015611aa7575f80fd5b505af1158015611ab9573d5f803e3d5ffd5b50505050856001600160a01b03167fdcc60b41ff1c604459e6aa4a7299817416b19fc586a392f111646e26597c4af986604051611af891815260200190565b60405180910390a250949350505050565b611b1e335f356001600160e01b031916612ec1565b611b3a5760405162461bcd60e51b8152600401610dcb90614ead565b6004805460ff60801b191690556040517fa45f47fdea8a1efdd9029a5691c7f759c32b7c698632b563573e155625d16933905f90a1565b611b86335f356001600160e01b031916612ec1565b611ba25760405162461bcd60e51b8152600401610dcb90614ead565b63ffffffff81165f818152600a6020908152604091829020805461ff0019168155915192835290917fc45af64a13a09ef916a1114c59589294ec9c3095f2bfbbb093a7a96656858ded91015b60405180910390a15050565b611c0f335f356001600160e01b031916612ec1565b611c2b5760405162461bcd60e51b8152600401610dcb90614ead565b80611c368342614f55565b10611c5457604051634c1eef1760e11b815260040160405180910390fd5b604080516001600160a01b038089166020830152871691810191909152606081018590526080810184905260a0810183905260c081018290525f9060e00160408051601f1981840301815291815281516020928301205f8b815260059093529120549091508114611cd85760405163fa174ecb60e01b815260040160405180910390fd5b5f888152600560205260408120556001600160a01b03861673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14611d105785611d32565b7f00000000000000000000000000000000000000000000000000000000000000005b6040516318457e6160e01b81529096506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906318457e6190611d89908a908a908a9083908b90600401614f0e565b5f604051808303815f87803b158015611da0575f80fd5b505af1158015611db2573d5f803e3d5ffd5b50505050866001600160a01b0316887faf98ea774275cadfa3e477a7b52cba03e01197445a76bd5d0d561608708c362483604051611df291815260200190565b60405180910390a35050505050505050565b611e19335f356001600160e01b031916612ec1565b611e355760405162461bcd60e51b8152600401610dcb90614ead565b63ffffffff81165f908152600a60205260408120805471ffffffffffffffffffffffffffffffffffff19169055611e6d9082906136d5565b60405163ffffffff821681527f11a9d1a77f76361ed131c19b1dc5758504c51dbde2e49fc973a0ef9577ad13d5906020015b60405180910390a150565b611ebf335f356001600160e01b031916612ec1565b611edb5760405162461bcd60e51b8152600401610dcb90614ead565b6001600160a01b0381165f81815260066020526040808220805461ff0019169055517f039bcf51833310242b8b7c6aa0fbabf1bf2b5e5270807ee020f1920ef200666b9190a250565b63ffffffff81165f90815260096020908152604080832081516080810183528154808252600183015494820185905260028301549382018490526003909201546060820181905285949193611f7a939291613895565b9250925050915091565b5f546001600160a01b0316331480612015575060015460405163b700961360e01b81526001600160a01b039091169063b700961390611fd690339030906001600160e01b03195f351690600401614f68565b602060405180830381865afa158015611ff1573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906120159190614f95565b61201d575f80fd5b600180546001600160a01b0319166001600160a01b03831690811790915560405133907fa3396fd7f6e0a21b50e5089d2da70d5ac0a3bbbd1f617a93f134b76389980198905f90a350565b61207d335f356001600160e01b031916612ec1565b6120995760405162461bcd60e51b8152600401610dcb90614ead565b6004805471ffffffffffffffffffffffffffffffffffff16600160901b6001600160701b038416908102919091179091556040519081527f752cd3d8df6864142257fa3a2e02aedf2dc09f1875c2a25b4f117d45c7334d5d90602001611e9f565b5f5b92915050565b612117335f356001600160e01b031916612ec1565b6121335760405162461bcd60e51b8152600401610dcb90614ead565b6004805460ff60801b1916600160801b1790556040517f9e87fac88ff661f02d44f95383c817fece4bce600a3dab7a54406878b965e752905f90a1565b612185335f356001600160e01b031916612ec1565b6121a15760405162461bcd60e51b8152600401610dcb90614ead565b60048054821515600160881b0260ff60881b199091161790556040517fa3fe47e2502292ca20854524008d366d3cad5da2426cfb2484099f06f328e4a090611e9f90831515815260200190565b612203335f356001600160e01b031916612ec1565b61221f5760405162461bcd60e51b8152600401610dcb90614ead565b6103e861ffff8216111561224657604051636c5cde8760e01b815260040160405180910390fd5b6040805160608082018352851515808352851515602080850182815261ffff8881168789018181526001600160a01b038e165f818152600387528b902099518a549551925161ffff1990961690151561ff00191617610100921515929092029190911763ffff0000191662010000949093169390930291909117909655865193845290830191909152938101929092527fe08301321781ac43935a2099b2c3fd42de0a0ee87a519cac00e8c9cecd26ff12910160405180910390a250505050565b5f61231d335f356001600160e01b031916612ec1565b6123395760405162461bcd60e51b8152600401610dcb90614ead565b60025460011461235b5760405162461bcd60e51b8152600401610dcb90614ed3565b600280558c73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b0382160161239e576040516316df5df960e31b815260040160405180910390fd5b5f6123a88f6130a1565b90506123b88f8f8e8e8e8e613722565b6123c68f8f8f3333866131de565b9250506123f4338f8f85600460089054906101000a90046001600160401b03166001600160401b0316613475565b6001600160601b0382111561241c576040516389588ab360e01b815260040160405180910390fd5b61242a828888888888612f67565b5060016002559c9b505050505050505050505050565b612455335f356001600160e01b031916612ec1565b6124715760405162461bcd60e51b8152600401610dcb90614ead565b6001600160a01b0381165f81815260066020526040808220805463ff00000019166301000000179055517f5e92c085dffcb69d025c31c9ed03d1869e4737ba81e8649c623398caa1b72f159190a250565b5f6124d8335f356001600160e01b031916612ec1565b6124f45760405162461bcd60e51b8152600401610dcb90614ead565b6002546001146125165760405162461bcd60e51b8152600401610dcb90614ed3565b600280555f612524866130a1565b90506125348686863387866131de565b9150856001600160a01b03167f6f9b974223f85a1ae805c33b8b519039e2435481d949db1110de151a94d587af8660405161257191815260200190565b60405180910390a2506001600255949350505050565b61259c335f356001600160e01b031916612ec1565b6125b85760405162461bcd60e51b8152600401610dcb90614ead565b6001600160a01b0381165f81815260066020526040808220805460ff19169055517fae893dda71e2eee548f8291f458cceae4bd22b56a79906928591e4420444c0e99190a250565b6001600160a01b0383165f9081526006602052604090205460ff168061264257506001600160a01b0382165f90815260066020526040902054610100900460ff165b8061266a57506001600160a01b0381165f9081526006602052604090205462010000900460ff165b806126a85750600454600160881b900460ff1680156126a857506001600160a01b0381165f908152600660205260409020546301000000900460ff16155b156126e157604051632821264f60e01b81526001600160a01b038085166004830152808416602483015282166044820152606401610dcb565b6001600160a01b0383165f9081526006602052604090206001015442101561271c5760405163f64059db60e01b815260040160405180910390fd5b505050565b612736335f356001600160e01b031916612ec1565b6127525760405162461bcd60e51b8152600401610dcb90614ead565b806001600160801b03165f0361277b5760405163c80ed59560e01b815260040160405180910390fd5b63ffffffff83165f908152600a60205260409020805461010071ffffffffffffffffffffffffffffffffff0019909116620100006001600160801b03851602171781556127d1846001600160a01b0385166136d5565b6040805163ffffffff861681526001600160a01b03851660208201527f34fe916485e02ec88e487b0e611e5c9bacabba9e3eaae7a900aa08be8197d419910160405180910390a150505050565b612833335f356001600160e01b031916612ec1565b61284f5760405162461bcd60e51b8152600401610dcb90614ead565b6001600160a01b0381165f81815260066020526040808220805463ff00000019169055517f1c2a701d65e1c6e2860263c884eae0b10db82e3ddd60640d53c7d53c6c998e799190a250565b63ffffffff81165f90815260086020908152604080832081516080810183528154808252600183015494820185905260028301549382018490526003909201546060820181905285949193611f7a939291613895565b612905335f356001600160e01b031916612ec1565b6129215760405162461bcd60e51b8152600401610dcb90614ead565b6001600160a01b0381165f81815260066020526040808220805462ffffff19169055517fae893dda71e2eee548f8291f458cceae4bd22b56a79906928591e4420444c0e99190a26040516001600160a01b038216907f039bcf51833310242b8b7c6aa0fbabf1bf2b5e5270807ee020f1920ef200666b905f90a26040516001600160a01b038216907f77cb944c14da76928795279d1519ce9150085a06e0a53c61d5a86fc4e0fd57c6905f90a250565b6129e6335f356001600160e01b031916612ec1565b612a025760405162461bcd60e51b8152600401610dcb90614ead565b60405163ca5eb5e160e01b81526001600160a01b0382811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063ca5eb5e1906024015f604051808303815f87803b158015612a62575f80fd5b505af1158015612a74573d5f803e3d5ffd5b5050505050565b5f612a91335f356001600160e01b031916612ec1565b612aad5760405162461bcd60e51b8152600401610dcb90614ead565b600254600114612acf5760405162461bcd60e51b8152600401610dcb90614ed3565b600280558873eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03821601612b12576040516316df5df960e31b815260040160405180910390fd5b5f612b1c8b6130a1565b9050612b2c8b8b8b3333866131de565b9250612b59338c8c86600460089054906101000a90046001600160401b03166001600160401b0316613475565b6001600160601b03831115612b81576040516389588ab360e01b815260040160405180910390fd5b612b8f838989898989612f67565b5050600160025598975050505050505050565b612bb7335f356001600160e01b031916612ec1565b612bd35760405162461bcd60e51b8152600401610dcb90614ead565b63ffffffff81165f818152600a6020908152604091829020805460ff19168155915192835290917f1cb867ed6a020e020ea220d4f48bb8e36552abf9095e093e377d33933f2b31e49101611bee565b604080518082019091526001600160601b03861681526001600160a01b03851660208201525f9081612c5382613910565b9050612c6181878787613957565b98975050505050505050565b6001600160a01b0381165f9081526006602052604090205460ff1615612cbe57604051632821264f60e01b81526001600160a01b03821660048201525f602482018190526044820152606401610dcb565b6001600160a01b0381165f90815260066020526040902060010154421015612cf95760405163f64059db60e01b815260040160405180910390fd5b50565b612d11335f356001600160e01b031916612ec1565b612d2d5760405162461bcd60e51b8152600401610dcb90614ead565b6115a88282808060200260200160405190810160405280939291908181526020015f905b82821015612d7d57612d6e60608302860136819003810190614fe4565b81526020019060010190612d51565b5050505050613b26565b612d9c335f356001600160e01b031916612ec1565b612db85760405162461bcd60e51b8152600401610dcb90614ead565b5f80546001600160a01b0319166001600160a01b0383169081178255604051909133917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a350565b612e17335f356001600160e01b031916612ec1565b612e335760405162461bcd60e51b8152600401610dcb90614ead565b6115a88282808060200260200160405190810160405280939291908181526020015f905b82821015612e8357612e7460608302860136819003810190614fe4565b81526020019060010190612e57565b5050505050613c18565b5f602082018035906007908390612ea49086614aab565b63ffffffff16815260208101919091526040015f20541492915050565b6001545f906001600160a01b03168015801590612f48575060405163b700961360e01b81526001600160a01b0382169063b700961390612f0990879030908890600401614f68565b602060405180830381865afa158015612f24573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612f489190614f95565b80612f5f57505f546001600160a01b038581169116145b949350505050565b612f72335f33612600565b6040516318457e6160e01b81525f600482018190526024820181905260448201523360648201526001600160601b03871660848201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906318457e619060a4015f604051808303815f87803b158015612ff3575f80fd5b505af1158015613005573d5f803e3d5ffd5b5050604080518082019091526001600160601b03891681526001600160a01b038816602082015291505f905061303a82613910565b90505f61304a8288888888613d0a565b6040516001600160601b038b1681529091506001600160a01b0389169082907fe0ec62d39b054dc2fd626dbc271483735df6e6fa1ef8389754bf8ab27a75eab29060200160405180910390a3505050505050505050565b604080516060810182525f8082526020820181905291810191909152600454600160801b900460ff16156130e85760405163e0f9e71d60e01b815260040160405180910390fd5b506001600160a01b0381165f908152600360209081526040918290208251606081018452905460ff8082161515808452610100830490911615159383019390935262010000900461ffff16928101929092526131575760405163645fd19f60e11b815260040160405180910390fd5b919050565b5f60405163095ea7b360e01b81526001600160a01b038416600482015282602482015260205f6044835f895af13d15601f3d1160015f5114161716915050806131d85760405162461bcd60e51b815260206004820152600e60248201526d1054141493d59157d1905253115160921b6044820152606401610dcb565b50505050565b6004545f90600160901b90046001600160701b03168682036132135760405163259be69560e11b815260040160405180910390fd5b604051634104b9ed60e11b81526001600160a01b0389811660048301526132c9917f0000000000000000000000000000000000000000000000000000000000000000917f0000000000000000000000000000000000000000000000000000000000000000169063820973da90602401602060405180830381865afa15801561329d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906132c19190614ef7565b89919061387a565b91505f836040015161ffff16116132e05781613303565b61330383604001516127106132f59190615025565b839061ffff1661271061387a565b9150858210156133265760405163097b2ad560e31b815260040160405180910390fd5b6001600160701b03818116146133e957806001600160701b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561339c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906133c09190614ef7565b6133ca9084615047565b11156133e95760405163ed32f3bb60e01b815260040160405180910390fd5b604051631ceb5d1960e11b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906339d6ba329061343d9088908c908c908a908990600401614f0e565b5f604051808303815f87803b158015613454575f80fd5b505af1158015613466573d5f803e3d5ffd5b50505050509695505050505050565b600480545f91908290613490906001600160401b031661505a565b82546001600160401b039182166101009390930a838102920219161790915590508115613537576134c18242615047565b6001600160a01b038781165f81815260066020908152604091829020600101949094558051938401919091529087169082015260608101859052608081018490524260a082015260c0810183905260e00160408051601f1981840301815291815281516020928301205f84815260059093529120555b846001600160a01b0316866001600160a01b0316827fe96d7872363f475d18b2f5390caaa5eaa96b2d38e42c62afe4ac08ebd2b13c3a87874288604051613597949392919093845260208401929092526040830152606082015260800190565b60405180910390a4505050505050565b63ffffffff81165f90815260076020526040812054806120fc5760405163f6ff4fb760e01b815263ffffffff84166004820152602401610dcb565b5f600a816135f360208b018b614aab565b63ffffffff16815260208082019290925260409081015f208151606081018352905460ff808216151580845261010083049091161515948301949094526201000090046001600160801b031691810191909152915061367b576136596020890189614aab565b6040516315b73a2960e21b815263ffffffff9091166004820152602401610dcb565b5f61368886880188614c7d565b90506136c061369a60208b018b614aab565b6040805180820190915260a084901c81526001600160a01b038416602082015251613f5d565b6136ca8882613fd2565b505050505050505050565b63ffffffff82165f81815260076020908152604091829020849055815192835282018390527f238399d427b947898edb290f5ff0f9109849b1c3ba196a42e35f00c50a54b98b9101611bee565b60405163d505accf60e01b81523360048201526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166024830152604482018790526064820186905260ff8516608483015260a4820184905260c4820183905287169063d505accf9060e4015f604051808303815f87803b1580156137ad575f80fd5b505af19250505080156137be575060015b61387257604051636eb1769f60e11b81523360048201526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116602483015286919088169063dd62ed3e90604401602060405180830381865afa15801561382f573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906138539190614ef7565b1015613872576040516301b8851f60e41b815260040160405180910390fd5b505050505050565b5f825f19048411830215820261388e575f80fd5b5091020490565b5f80806138a28642614f55565b90508381106138b6575f9250849150613906565b5f846138c2838861507f565b6138cc9190615096565b9050808811156138e5576138e08189614f55565b6138e7565b5f5b935083861115613900576138fb8487614f55565b613902565b5f5b9250505b5094509492505050565b80515f906001600160601b03101561393b57604051633524486360e01b815260040160405180910390fd5b81516020909201516001600160a01b031660a09290921b171790565b5f6001600160a01b03821673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee148015906139b757507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031614155b156139d557604051637f3cd08160e11b815260040160405180910390fd5b5f6139e284860186614aab565b63ffffffff81165f908152600a60209081526040918290208251606081018452905460ff8082161515835261010082041615159282018390526201000090046001600160801b03169281019290925291925090613a5a5760405163420eae3760e01b815263ffffffff83166004820152602401610dcb565b5f87604051602001613a6e91815260200190565b60405160208183030381529060405290505f613ab683604001515f613aaf60408051600360f01b602082015281516002818303018152602290910190915290565b91906140be565b90505f613ae58584846001600160a01b038b1673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1415614123565b90506001600160a01b03871673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14613b15578060200151613b18565b80515b9a9950505050505050505050565b5f5b8151811015613be8575f60085f848481518110613b4757613b476150b5565b60200260200101515f015163ffffffff1663ffffffff1681526020019081526020015f209050613b93838381518110613b8257613b826150b5565b60200260200101515f01515f614201565b828281518110613ba557613ba56150b5565b6020026020010151602001518160020181905550828281518110613bcb57613bcb6150b5565b602090810291909101015160400151600390910155600101613b28565b507f55254e344b7fc8e2e038c1f7f20a1c7afe659c1a3bbfc4e35dd1ca9bba0ca0a081604051611e9f91906150c9565b5f5b8151811015613cda575f60095f848481518110613c3957613c396150b5565b60200260200101515f015163ffffffff1663ffffffff1681526020019081526020015f209050613c85838381518110613c7457613c746150b5565b60200260200101515f01515f613f5d565b828281518110613c9757613c976150b5565b6020026020010151602001518160020181905550828281518110613cbd57613cbd6150b5565b602090810291909101015160400151600390910155600101613c1a565b507f983af742b0b5ca79aa5c0be76cea126e1baf3139ecd04624deac13853c4bebde81604051611e9f91906150c9565b5f80613d1885870187614aab565b9050613d4c81613d46896040805180820190915260a082901c81526001600160a01b03909116602082015290565b51614201565b63ffffffff81165f908152600a60209081526040918290208251606081018452905460ff8082161515835261010082041615159282018390526201000090046001600160801b031692810192909252613dc05760405163420eae3760e01b815263ffffffff83166004820152602401610dcb565b5f88604051602001613dd491815260200190565b60405160208183030381529060405290505f613e1583604001515f613aaf60408051600360f01b602082015281516002818303018152602290910190915290565b90505f613e448584846001600160a01b038c1673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1415614123565b905073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03891601613eab578051871015613ea657805160405163f5ac3fa760e01b815263ffffffff87166004820152602481019190915260448101889052606401610dcb565b613f3e565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316886001600160a01b031603613f25578681602001511115613ea657602081015160405163f5ac3fa760e01b815263ffffffff87166004820152602481019190915260448101889052606401610dcb565b604051637f3cd08160e11b815260040160405180910390fd5b5f613f4c868585853361425d565b519c9b505050505050505050505050565b63ffffffff82165f90815260096020526040812080546001820154600283015460038401549394938493613f949390929091613895565b9150915080841115613fb957604051636a526abb60e01b815260040160405180910390fd5b613fc38483615047565b83555050426001909101555050565b60408051808201825260a083901c8082526001600160a01b03808516602084018190529351631ceb5d1960e11b815292937f0000000000000000000000000000000000000000000000000000000000000000909116926339d6ba3292614041925f928392839291600401614f0e565b5f604051808303815f87803b158015614058575f80fd5b505af115801561406a573d5f803e3d5ffd5b5050505080602001516001600160a01b0316837fb944fddc61d7fedb8b736790454ba972000703b0d21c7481d6dbf95b7c2cc2f1835f01516040516140b191815260200190565b60405180910390a3505050565b60608360036140cd825f614363565b61ffff1614614100576140e0815f614363565b604051633a51740d60e01b815261ffff9091166004820152602401610dcb565b5f61410b85856143bf565b905061411986600183614438565b9695505050505050565b604080518082019091525f80825260208201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663ddc28c586040518060a001604052808863ffffffff168152602001614185896135a7565b8152602001878152602001868152602001851515815250306040518363ffffffff1660e01b81526004016141ba929190615174565b6040805180830381865afa1580156141d4573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906141f89190615244565b95945050505050565b63ffffffff82165f908152600860205260408120805460018201546002830154600384015493949384936142389390929091613895565b9150915080841115613fb9576040516324292aa760e01b815260040160405180910390fd5b614265614666565b5f614272845f01516144a1565b60208501519091501561428c5761428c84602001516144c8565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316632637a450826040518060a001604052808b63ffffffff1681526020016142dc8c6135a7565b81526020018a81526020018981526020015f8960200151111515815250866040518463ffffffff1660e01b8152600401614317929190615174565b60806040518083038185885af1158015614333573d5f803e3d5ffd5b50505050506040513d601f19601f82011682018060405250810190614358919061525e565b979650505050505050565b5f61436f826002615047565b835110156143b65760405162461bcd60e51b8152602060048201526014602482015273746f55696e7431365f6f75744f66426f756e647360601b6044820152606401610dcb565b50016002015190565b60606001600160801b0382161561440757604080516001600160801b0319608086811b8216602084015285901b16603082015201604051602081830303815290604052614431565b6040516001600160801b0319608085901b1660208201526030016040516020818303038152906040525b9392505050565b6060836003614447825f614363565b61ffff161461445a576140e0815f614363565b84600161446785516145a7565b6144729060016152a6565b86866040516020016144889594939291906152c1565b6040516020818303038152906040529150509392505050565b5f8134146144c4576040516304fb820960e51b8152346004820152602401610dcb565b5090565b5f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e4fe1d946040518163ffffffff1660e01b8152600401602060405180830381865afa158015614525573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906145499190615327565b90506001600160a01b038116614572576040516329b99a9560e11b815260040160405180910390fd5b6115a86001600160a01b038216337f0000000000000000000000000000000000000000000000000000000000000000856145d5565b5f61ffff8211156144c4576040516306dfcc6560e41b81526010600482015260248101839052604401610dcb565b5f6040516323b872dd60e01b81526001600160a01b03851660048201526001600160a01b038416602482015282604482015260205f6064835f8a5af13d15601f3d1160015f511416171691505080612a745760405162461bcd60e51b81526020600482015260146024820152731514905394d1915497d19493d357d1905253115160621b6044820152606401610dcb565b60405180606001604052805f80191681526020015f6001600160401b031681526020016146a460405180604001604052805f81526020015f81525090565b905290565b80356001600160601b0381168114613157575f80fd5b6001600160a01b0381168114612cf9575f80fd5b8035613157816146bf565b5f8083601f8401126146ee575f80fd5b5081356001600160401b03811115614704575f80fd5b60208301915083602082850101111561471b575f80fd5b9250929050565b5f805f805f8060a08789031215614737575f80fd5b614740876146a9565b95506020870135614750816146bf565b945060408701356001600160401b0381111561476a575f80fd5b61477689828a016146de565b909550935050606087013561478a816146bf565b80925050608087013590509295509295509295565b5f805f606084860312156147b1575f80fd5b83356147bc816146bf565b95602085013595506040909401359392505050565b6001600160401b0381168114612cf9575f80fd5b5f602082840312156147f5575f80fd5b8135614431816147d1565b5f60608284031215614810575f80fd5b50919050565b5f805f805f805f60e0888a03121561482c575f80fd5b6148368989614800565b96506060880135955060808801356001600160401b0380821115614858575f80fd5b6148648b838c016146de565b909750955060a08a01359150614879826146bf565b90935060c0890135908082111561488e575f80fd5b5061489b8a828b016146de565b989b979a50959850939692959293505050565b803563ffffffff81168114613157575f80fd5b80356001600160801b0381168114613157575f80fd5b5f80604083850312156148e8575f80fd5b6148f1836148ae565b91506148ff602084016148c1565b90509250929050565b5f60208284031215614918575f80fd5b8135614431816146bf565b5f8060408385031215614934575f80fd5b61493d836148ae565b9150602083013561494d816146bf565b809150509250929050565b5f8060408385031215614969575f80fd5b614972836148ae565b946020939093013593505050565b8015158114612cf9575f80fd5b5f805f805f60a086880312156149a1575f80fd5b6149aa866148ae565b945060208601356149ba81614980565b935060408601356149ca81614980565b925060608601356149da816146bf565b91506149e8608087016148c1565b90509295509295909350565b803560ff81168114613157575f80fd5b5f805f805f805f60e0888a031215614a1a575f80fd5b8735614a25816146bf565b9650602088013595506040880135945060608801359350614a48608089016149f4565b925060a0880135915060c0880135905092959891949750929550565b5f805f8060808587031215614a77575f80fd5b8435614a82816146bf565b935060208501359250604085013591506060850135614aa0816146bf565b939692955090935050565b5f60208284031215614abb575f80fd5b614431826148ae565b5f805f805f805f60e0888a031215614ada575f80fd5b873596506020880135614aec816146bf565b95506040880135614afc816146bf565b969995985095966060810135965060808101359560a0820135955060c0909101359350915050565b5f60208284031215614b34575f80fd5b81356001600160701b0381168114614431575f80fd5b5f60208284031215614b5a575f80fd5b813561443181614980565b5f805f8060808587031215614b78575f80fd5b8435614b83816146bf565b93506020850135614b9381614980565b92506040850135614ba381614980565b9150606085013561ffff81168114614aa0575f80fd5b5f805f805f805f805f805f806101608d8f031215614bd5575f80fd5b614bdf8d356146bf565b8c359b5060208d01359a5060408d0135995060608d01359850614c0460808e016149f4565b975060a08d0135965060c08d01359550614c2160e08e01356146bf565b60e08d013594506001600160401b036101008e01351115614c40575f80fd5b614c518e6101008f01358f016146de565b9094509250614c636101208e016146d3565b91506101408d013590509295989b509295989b509295989b565b5f60208284031215614c8d575f80fd5b5035919050565b5f805f60608486031215614ca6575f80fd5b8335614cb1816146bf565b92506020840135614cc1816146bf565b91506040840135614cd1816146bf565b809150509250925092565b5f805f60608486031215614cee575f80fd5b614cf7846148ae565b92506020840135614d07816146bf565b9150614d15604085016148c1565b90509250925092565b5f805f805f805f8060e0898b031215614d35575f80fd5b8835614d40816146bf565b975060208901359650604089013595506060890135614d5e816146bf565b945060808901356001600160401b03811115614d78575f80fd5b614d848b828c016146de565b90955093505060a0890135614d98816146bf565b8092505060c089013590509295985092959890939650565b5f805f805f60808688031215614dc4575f80fd5b614dcd866146a9565b94506020860135614ddd816146bf565b935060408601356001600160401b03811115614df7575f80fd5b614e03888289016146de565b9094509250506060860135614e17816146bf565b809150509295509295909350565b5f8060208385031215614e36575f80fd5b82356001600160401b0380821115614e4c575f80fd5b818501915085601f830112614e5f575f80fd5b813581811115614e6d575f80fd5b866020606083028501011115614e81575f80fd5b60209290920196919550909350505050565b5f60608284031215614ea3575f80fd5b6144318383614800565b6020808252600c908201526b15539055551213d49256915160a21b604082015260600190565b6020808252600a90820152695245454e5452414e435960b01b604082015260600190565b5f60208284031215614f07575f80fd5b5051919050565b6001600160a01b039586168152938516602085015260408401929092529092166060820152608081019190915260a00190565b634e487b7160e01b5f52601160045260245ffd5b818103818111156120fc576120fc614f41565b6001600160a01b0393841681529190921660208201526001600160e01b0319909116604082015260600190565b5f60208284031215614fa5575f80fd5b815161443181614980565b604051606081016001600160401b0381118282101715614fde57634e487b7160e01b5f52604160045260245ffd5b60405290565b5f60608284031215614ff4575f80fd5b614ffc614fb0565b615005836148ae565b815260208301356020820152604083013560408201528091505092915050565b61ffff82811682821603908082111561504057615040614f41565b5092915050565b808201808211156120fc576120fc614f41565b5f6001600160401b0380831681810361507557615075614f41565b6001019392505050565b80820281158282048414176120fc576120fc614f41565b5f826150b057634e487b7160e01b5f52601260045260245ffd5b500490565b634e487b7160e01b5f52603260045260245ffd5b602080825282518282018190525f919060409081850190868401855b8281101561511a578151805163ffffffff168552868101518786015285015185850152606090930192908501906001016150e5565b5091979650505050505050565b5f5b83811015615141578181015183820152602001615129565b50505f910152565b5f8151808452615160816020860160208601615127565b601f01601f19169290920160200192915050565b6040815263ffffffff8351166040820152602083015160608201525f604084015160a060808401526151a960e0840182615149565b90506060850151603f198483030160a08501526151c68282615149565b60809690960151151560c08501525050506001600160a01b039190911660209091015290565b5f604082840312156151fc575f80fd5b604051604081018181106001600160401b038211171561522a57634e487b7160e01b5f52604160045260245ffd5b604052825181526020928301519281019290925250919050565b5f60408284031215615254575f80fd5b61443183836151ec565b5f6080828403121561526e575f80fd5b615276614fb0565b825181526020830151615288816147d1565b602082015261529a84604085016151ec565b60408201529392505050565b61ffff81811683821601908082111561504057615040614f41565b5f86516152d2818460208b01615127565b6001600160f81b031960f888811b82169285019283526001600160f01b031960f089901b16600184015286901b1660038201528351615318816004840160208801615127565b01600401979650505050505050565b5f60208284031215615337575f80fd5b8151614431816146bf56fea264697066735822122024354ee82ccbadd74af752050ba0f64dbc9084de8a475de8255e5616f2249c7e64736f6c634300081500330000000000000000000000005f2f11ad8656439d5c14d9b351f8b09cdac2a02d00000000000000000000000069d210d3b60e939bfa6e87cccc4fab7e8f44c16b000000000000000000000000fcb9a6bf02c43f9e38bb102fd960cc1e738e787d000000000000000000000000ee7d8bcfb72bc1880d0cf19822eb0a2e6577ab620000000000000000000000006f475642a6e85809b1c36fa62763669b1b48dd5b0000000000000000000000005f2f11ad8656439d5c14d9b351f8b09cdac2a02d0000000000000000000000000000000000000000000000000000000000000001
Deployed Bytecode
0x6080604052600436106103be575f3560e01c80637d25a05e116101f4578063bf67138411610113578063d7424e33116100a8578063e96e38e211610078578063e96e38e214610ceb578063f2fde38b14610d0a578063f51b1aca14610d29578063fbfa77cf14610d48578063ff7bd03d14610d7b575f80fd5b8063d7424e3314610c50578063dbd5edc714610c6f578063de35f5cb14610cad578063e83931af14610ccc575f80fd5b8063ca5eb5e1116100e3578063ca5eb5e114610b90578063cab716e814610baf578063d182221614610bc2578063d555f36814610c31575f80fd5b8063bf67138414610b14578063bf7e214f14610b33578063c272198d14610b52578063c29d2f1014610b71575f80fd5b80639d57442011610189578063b187bd2611610159578063b187bd2614610a98578063b5ba618214610ab8578063b92d0eff14610ad7578063bb0b6a5314610ae9575f80fd5b80639d57442014610a155780639fdb11b614610a34578063a924bf6114610a5a578063abd626b014610a79575f80fd5b80638dfd8ba1116101c45780638dfd8ba11461099957806394f51289146109b85780639a94d3d0146109cb5780639ac4f42d146109f6575f80fd5b80637d25a05e146109115780638456cb59146109485780638a6733f91461095c5780638da5cb5b1461097b575f80fd5b80633d935d9e116102e057806355a2d64d116102755780635f45bac8116102455780635f45bac814610880578063703d37681461089f5780637a9e5e4b146108d35780637bd876b6146108f2575f80fd5b806355a2d64d1461076957806355b56c0c146107885780635c465430146107c85780635e280f111461084d575f80fd5b806345ad6063116102b057806345ad60631461069857806346b563f4146106b75780634fb3ccc5146106d657806351c32a8814610709575f80fd5b80633d935d9e146105e15780633e64ce99146106005780633f4ba83a1461061f57806341fee44a14610633575f80fd5b806318aed921116103565780632c524c42116103265780632c524c42146105655780633400288b1461058457806334dafd6b146105a35780633b575407146105c2575f80fd5b806318aed921146104e95780631b62636c146105085780631ba9a45814610527578063202eac5714610546575f80fd5b806312056e2d1161039157806312056e2d1461047857806313137d65146104975780631568fc58146104aa57806317442b70146104c9575f80fd5b80630511ef43146103c257806305921740146103f75780630b48a8b81461040c5780630efe6a8b14610457575b5f80fd5b3480156103cd575f80fd5b506004546103e290600160881b900460ff1681565b60405190151581526020015b60405180910390f35b61040a610405366004614722565b610d9a565b005b348015610417575f80fd5b5061043f7f000000000000000000000000ee7d8bcfb72bc1880d0cf19822eb0a2e6577ab6281565b6040516001600160a01b0390911681526020016103ee565b61046a61046536600461479f565b610e40565b6040519081526020016103ee565b348015610483575f80fd5b5061040a6104923660046147e5565b611049565b61040a6104a5366004614816565b6110d9565b3480156104b5575f80fd5b5061040a6104c43660046148d7565b611194565b3480156104d4575f80fd5b506040805160018082526020820152016103ee565b3480156104f4575f80fd5b5061040a610503366004614908565b611269565b348015610513575f80fd5b5061040a610522366004614908565b61134f565b348015610532575f80fd5b5061040a610541366004614908565b6113cf565b348015610551575f80fd5b5061040a610560366004614923565b61144a565b348015610570575f80fd5b5061040a61057f366004614908565b6114f1565b34801561058f575f80fd5b5061040a61059e366004614958565b61156d565b3480156105ae575f80fd5b5061040a6105bd36600461498d565b6115ac565b3480156105cd575f80fd5b5061040a6105dc366004614908565b611700565b3480156105ec575f80fd5b5061046a6105fb366004614a04565b61177e565b34801561060b575f80fd5b5061046a61061a366004614a64565b61187c565b34801561062a575f80fd5b5061040a611b09565b34801561063e575f80fd5b5061067761064d366004614908565b60036020525f908152604090205460ff8082169161010081049091169062010000900461ffff1683565b604080519315158452911515602084015261ffff16908201526060016103ee565b3480156106a3575f80fd5b5061040a6106b2366004614aab565b611b71565b3480156106c2575f80fd5b5061040a6106d1366004614ac4565b611bfa565b3480156106e1575f80fd5b5061043f7f000000000000000000000000fcb9a6bf02c43f9e38bb102fd960cc1e738e787d81565b348015610714575f80fd5b50610749610723366004614aab565b60086020525f908152604090208054600182015460028301546003909301549192909184565b6040805194855260208501939093529183015260608201526080016103ee565b348015610774575f80fd5b5061040a610783366004614aab565b611e04565b348015610793575f80fd5b506107496107a2366004614aab565b60096020525f908152604090208054600182015460028301546003909301549192909184565b3480156107d3575f80fd5b5061081d6107e2366004614908565b60066020525f90815260409020805460019091015460ff80831692610100810482169262010000820483169263010000009092049091169085565b6040805195151586529315156020860152911515928401929092529015156060830152608082015260a0016103ee565b348015610858575f80fd5b5061043f7f0000000000000000000000006f475642a6e85809b1c36fa62763669b1b48dd5b81565b34801561088b575f80fd5b5061040a61089a366004614908565b611eaa565b3480156108aa575f80fd5b506108be6108b9366004614aab565b611f24565b604080519283526020830191909152016103ee565b3480156108de575f80fd5b5061040a6108ed366004614908565b611f84565b3480156108fd575f80fd5b5061040a61090c366004614b24565b612068565b34801561091c575f80fd5b5061093061092b366004614958565b6120fa565b6040516001600160401b0390911681526020016103ee565b348015610953575f80fd5b5061040a612102565b348015610967575f80fd5b5061040a610976366004614b4a565b612170565b348015610986575f80fd5b505f5461043f906001600160a01b031681565b3480156109a4575f80fd5b5061040a6109b3366004614b65565b6121ee565b61046a6109c6366004614bb9565b612307565b3480156109d6575f80fd5b5061046a6109e5366004614c7d565b60056020525f908152604090205481565b348015610a01575f80fd5b5061040a610a10366004614908565b612440565b348015610a20575f80fd5b5061046a610a2f366004614a64565b6124c2565b348015610a3f575f80fd5b5060045461093090600160401b90046001600160401b031681565b348015610a65575f80fd5b5061040a610a74366004614908565b612587565b348015610a84575f80fd5b5061040a610a93366004614c94565b612600565b348015610aa3575f80fd5b506004546103e290600160801b900460ff1681565b348015610ac3575f80fd5b5061040a610ad2366004614cdc565b612721565b348015610ae2575f80fd5b503061043f565b348015610af4575f80fd5b5061046a610b03366004614aab565b60076020525f908152604090205481565b348015610b1f575f80fd5b5061040a610b2e366004614908565b61281e565b348015610b3e575f80fd5b5060015461043f906001600160a01b031681565b348015610b5d575f80fd5b506108be610b6c366004614aab565b61289a565b348015610b7c575f80fd5b5061040a610b8b366004614908565b6128f0565b348015610b9b575f80fd5b5061040a610baa366004614908565b6129d1565b61046a610bbd366004614d1e565b612a7b565b348015610bcd575f80fd5b50610c0b610bdc366004614aab565b600a6020525f908152604090205460ff808216916101008104909116906201000090046001600160801b031683565b60408051931515845291151560208401526001600160801b0316908201526060016103ee565b348015610c3c575f80fd5b5061040a610c4b366004614aab565b612ba2565b348015610c5b575f80fd5b5061046a610c6a366004614db0565b612c22565b348015610c7a575f80fd5b50600454610c9590600160901b90046001600160701b031681565b6040516001600160701b0390911681526020016103ee565b348015610cb8575f80fd5b50600454610930906001600160401b031681565b348015610cd7575f80fd5b5061040a610ce6366004614908565b612c6d565b348015610cf6575f80fd5b5061040a610d05366004614e25565b612cfc565b348015610d15575f80fd5b5061040a610d24366004614908565b612d87565b348015610d34575f80fd5b5061040a610d43366004614e25565b612e02565b348015610d53575f80fd5b5061043f7f00000000000000000000000069d210d3b60e939bfa6e87cccc4fab7e8f44c16b81565b348015610d86575f80fd5b506103e2610d95366004614e93565b612e8d565b610daf335f356001600160e01b031916612ec1565b610dd45760405162461bcd60e51b8152600401610dcb90614ead565b60405180910390fd5b600254600114610df65760405162461bcd60e51b8152600401610dcb90614ed3565b60028055600454600160801b900460ff1615610e255760405163e0f9e71d60e01b815260040160405180910390fd5b610e33868686868686612f67565b5050600160025550505050565b5f610e56335f356001600160e01b031916612ec1565b610e725760405162461bcd60e51b8152600401610dcb90614ead565b600254600114610e945760405162461bcd60e51b8152600401610dcb90614ed3565b600280555f610ea2856130a1565b90505f73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03871601610fde57345f03610eea5760405163259be69560e11b815260040160405180910390fd5b7f000000000000000000000000ee7d8bcfb72bc1880d0cf19822eb0a2e6577ab626001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004015f604051808303818588803b158015610f43575f80fd5b505af1158015610f55573d5f803e3d5ffd5b50349850610fb49350506001600160a01b037f000000000000000000000000ee7d8bcfb72bc1880d0cf19822eb0a2e6577ab621691507f00000000000000000000000069d210d3b60e939bfa6e87cccc4fab7e8f44c16b90508761315c565b507f000000000000000000000000ee7d8bcfb72bc1880d0cf19822eb0a2e6577ab62945030611000565b3415610ffd57604051631cf02cf960e21b815260040160405180910390fd5b50335b61100e8686868433876131de565b925061103b33878786600460089054906101000a90046001600160401b03166001600160401b0316613475565b505060016002559392505050565b61105e335f356001600160e01b031916612ec1565b61107a5760405162461bcd60e51b8152600401610dcb90614ead565b6203f480816001600160401b031611156110a757604051631fac010160e21b815260040160405180910390fd5b600480546001600160401b03909216600160401b026fffffffffffffffff000000000000000019909216919091179055565b7f0000000000000000000000006f475642a6e85809b1c36fa62763669b1b48dd5b6001600160a01b03163314611124576040516391ac5e4f60e01b8152336004820152602401610dcb565b6020870180359061113e90611139908a614aab565b6135a7565b1461117c576111506020880188614aab565b60405163309afaf360e21b815263ffffffff909116600482015260208801356024820152604401610dcb565b61118b878787878787876135e2565b50505050505050565b6111a9335f356001600160e01b031916612ec1565b6111c55760405162461bcd60e51b8152600401610dcb90614ead565b806001600160801b03165f036111ee5760405163c80ed59560e01b815260040160405180910390fd5b63ffffffff82165f818152600a6020908152604091829020805462010000600160901b031916620100006001600160801b038716908102919091178255835194855291840191909152917f0aa48359f83e8464fda3f4ea4bd3f2d6af01e90b46ab9464aa7d538e1772947a91015b60405180910390a1505050565b61127e335f356001600160e01b031916612ec1565b61129a5760405162461bcd60e51b8152600401610dcb90614ead565b6001600160a01b0381165f81815260066020526040808220805462ffffff191662010101179055517fd658022b1a3aaf6ad3b3c615253712807f21a8f7bc3e4996e10618175d4afb2b9190a26040516001600160a01b038216907f79fc685a7dbabb75a67df5e69a90602cef1f19bc465b060eab1ac56685e04a13905f90a26040516001600160a01b038216907f3afb02134e37f7205acf470adc2fc4ebb70614b1599a602d069790915380e2aa905f90a250565b611364335f356001600160e01b031916612ec1565b6113805760405162461bcd60e51b8152600401610dcb90614ead565b6001600160a01b0381165f81815260066020526040808220805462ff0000191662010000179055517f3afb02134e37f7205acf470adc2fc4ebb70614b1599a602d069790915380e2aa9190a250565b6113e4335f356001600160e01b031916612ec1565b6114005760405162461bcd60e51b8152600401610dcb90614ead565b6001600160a01b0381165f81815260066020526040808220805462ff000019169055517f77cb944c14da76928795279d1519ce9150085a06e0a53c61d5a86fc4e0fd57c69190a250565b61145f335f356001600160e01b031916612ec1565b61147b5760405162461bcd60e51b8152600401610dcb90614ead565b63ffffffff82165f908152600a60205260409020805460ff191660011781556114ad836001600160a01b0384166136d5565b6040805163ffffffff851681526001600160a01b03841660208201527fe925de263dcdbdc20307c9ab92758ed8cc0edf3d173dad4a3aa54c070f27a543910161125c565b611506335f356001600160e01b031916612ec1565b6115225760405162461bcd60e51b8152600401610dcb90614ead565b6001600160a01b0381165f81815260066020526040808220805460ff19166001179055517fd658022b1a3aaf6ad3b3c615253712807f21a8f7bc3e4996e10618175d4afb2b9190a250565b611582335f356001600160e01b031916612ec1565b61159e5760405162461bcd60e51b8152600401610dcb90614ead565b6115a882826136d5565b5050565b6115c1335f356001600160e01b031916612ec1565b6115dd5760405162461bcd60e51b8152600401610dcb90614ead565b8280156115f157506001600160801b038116155b1561160f5760405163c80ed59560e01b815260040160405180910390fd5b60408051606081018252851515815284151560208083019182526001600160801b0385811684860190815263ffffffff8b165f908152600a90935294909120925183549251945161ffff1990931690151561ff00191617610100941515949094029390931762010000600160901b0319166201000091909316029190911790556116a2856001600160a01b0384166136d5565b6040805163ffffffff871681528515156020820152841515818301526001600160a01b038416606082015290517f5dbe727bffd24a6d61a5aeef919510389c66c0deeaa82634862cf4f098961fb89181900360800190a15050505050565b611715335f356001600160e01b031916612ec1565b6117315760405162461bcd60e51b8152600401610dcb90614ead565b6001600160a01b0381165f81815260066020526040808220805461ff001916610100179055517f79fc685a7dbabb75a67df5e69a90602cef1f19bc465b060eab1ac56685e04a139190a250565b5f611794335f356001600160e01b031916612ec1565b6117b05760405162461bcd60e51b8152600401610dcb90614ead565b6002546001146117d25760405162461bcd60e51b8152600401610dcb90614ed3565b600280558773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03821601611815576040516316df5df960e31b815260040160405180910390fd5b5f61181f8a6130a1565b905061182f8a8a89898989613722565b61183d8a8a8a3333866131de565b925061186a338b8b86600460089054906101000a90046001600160401b03166001600160401b0316613475565b50506001600255979650505050505050565b5f611892335f356001600160e01b031916612ec1565b6118ae5760405162461bcd60e51b8152600401610dcb90614ead565b600454600160801b900460ff16156118d95760405163e0f9e71d60e01b815260040160405180910390fd5b6001600160a01b0385165f908152600360209081526040918290208251606081018452905460ff80821615158352610100820416151592820183905262010000900461ffff16928101929092526119435760405163645fd19f60e11b815260040160405180910390fd5b845f0361196357604051630ea3153160e21b815260040160405180910390fd5b604051634104b9ed60e11b81526001600160a01b038781166004830152611a19917f000000000000000000000000fcb9a6bf02c43f9e38bb102fd960cc1e738e787d9091169063820973da90602401602060405180830381865afa1580156119cd573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119f19190614ef7565b86907f0000000000000000000000000000000000000000000000000de0b6b3a764000061387a565b915083821015611a3c576040516302620f6160e61b815260040160405180910390fd5b6040516318457e6160e01b81526001600160a01b037f00000000000000000000000069d210d3b60e939bfa6e87cccc4fab7e8f44c16b16906318457e6190611a909086908a90879033908c90600401614f0e565b5f604051808303815f87803b158015611aa7575f80fd5b505af1158015611ab9573d5f803e3d5ffd5b50505050856001600160a01b03167fdcc60b41ff1c604459e6aa4a7299817416b19fc586a392f111646e26597c4af986604051611af891815260200190565b60405180910390a250949350505050565b611b1e335f356001600160e01b031916612ec1565b611b3a5760405162461bcd60e51b8152600401610dcb90614ead565b6004805460ff60801b191690556040517fa45f47fdea8a1efdd9029a5691c7f759c32b7c698632b563573e155625d16933905f90a1565b611b86335f356001600160e01b031916612ec1565b611ba25760405162461bcd60e51b8152600401610dcb90614ead565b63ffffffff81165f818152600a6020908152604091829020805461ff0019168155915192835290917fc45af64a13a09ef916a1114c59589294ec9c3095f2bfbbb093a7a96656858ded91015b60405180910390a15050565b611c0f335f356001600160e01b031916612ec1565b611c2b5760405162461bcd60e51b8152600401610dcb90614ead565b80611c368342614f55565b10611c5457604051634c1eef1760e11b815260040160405180910390fd5b604080516001600160a01b038089166020830152871691810191909152606081018590526080810184905260a0810183905260c081018290525f9060e00160408051601f1981840301815291815281516020928301205f8b815260059093529120549091508114611cd85760405163fa174ecb60e01b815260040160405180910390fd5b5f888152600560205260408120556001600160a01b03861673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14611d105785611d32565b7f000000000000000000000000ee7d8bcfb72bc1880d0cf19822eb0a2e6577ab625b6040516318457e6160e01b81529096506001600160a01b037f00000000000000000000000069d210d3b60e939bfa6e87cccc4fab7e8f44c16b16906318457e6190611d89908a908a908a9083908b90600401614f0e565b5f604051808303815f87803b158015611da0575f80fd5b505af1158015611db2573d5f803e3d5ffd5b50505050866001600160a01b0316887faf98ea774275cadfa3e477a7b52cba03e01197445a76bd5d0d561608708c362483604051611df291815260200190565b60405180910390a35050505050505050565b611e19335f356001600160e01b031916612ec1565b611e355760405162461bcd60e51b8152600401610dcb90614ead565b63ffffffff81165f908152600a60205260408120805471ffffffffffffffffffffffffffffffffffff19169055611e6d9082906136d5565b60405163ffffffff821681527f11a9d1a77f76361ed131c19b1dc5758504c51dbde2e49fc973a0ef9577ad13d5906020015b60405180910390a150565b611ebf335f356001600160e01b031916612ec1565b611edb5760405162461bcd60e51b8152600401610dcb90614ead565b6001600160a01b0381165f81815260066020526040808220805461ff0019169055517f039bcf51833310242b8b7c6aa0fbabf1bf2b5e5270807ee020f1920ef200666b9190a250565b63ffffffff81165f90815260096020908152604080832081516080810183528154808252600183015494820185905260028301549382018490526003909201546060820181905285949193611f7a939291613895565b9250925050915091565b5f546001600160a01b0316331480612015575060015460405163b700961360e01b81526001600160a01b039091169063b700961390611fd690339030906001600160e01b03195f351690600401614f68565b602060405180830381865afa158015611ff1573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906120159190614f95565b61201d575f80fd5b600180546001600160a01b0319166001600160a01b03831690811790915560405133907fa3396fd7f6e0a21b50e5089d2da70d5ac0a3bbbd1f617a93f134b76389980198905f90a350565b61207d335f356001600160e01b031916612ec1565b6120995760405162461bcd60e51b8152600401610dcb90614ead565b6004805471ffffffffffffffffffffffffffffffffffff16600160901b6001600160701b038416908102919091179091556040519081527f752cd3d8df6864142257fa3a2e02aedf2dc09f1875c2a25b4f117d45c7334d5d90602001611e9f565b5f5b92915050565b612117335f356001600160e01b031916612ec1565b6121335760405162461bcd60e51b8152600401610dcb90614ead565b6004805460ff60801b1916600160801b1790556040517f9e87fac88ff661f02d44f95383c817fece4bce600a3dab7a54406878b965e752905f90a1565b612185335f356001600160e01b031916612ec1565b6121a15760405162461bcd60e51b8152600401610dcb90614ead565b60048054821515600160881b0260ff60881b199091161790556040517fa3fe47e2502292ca20854524008d366d3cad5da2426cfb2484099f06f328e4a090611e9f90831515815260200190565b612203335f356001600160e01b031916612ec1565b61221f5760405162461bcd60e51b8152600401610dcb90614ead565b6103e861ffff8216111561224657604051636c5cde8760e01b815260040160405180910390fd5b6040805160608082018352851515808352851515602080850182815261ffff8881168789018181526001600160a01b038e165f818152600387528b902099518a549551925161ffff1990961690151561ff00191617610100921515929092029190911763ffff0000191662010000949093169390930291909117909655865193845290830191909152938101929092527fe08301321781ac43935a2099b2c3fd42de0a0ee87a519cac00e8c9cecd26ff12910160405180910390a250505050565b5f61231d335f356001600160e01b031916612ec1565b6123395760405162461bcd60e51b8152600401610dcb90614ead565b60025460011461235b5760405162461bcd60e51b8152600401610dcb90614ed3565b600280558c73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b0382160161239e576040516316df5df960e31b815260040160405180910390fd5b5f6123a88f6130a1565b90506123b88f8f8e8e8e8e613722565b6123c68f8f8f3333866131de565b9250506123f4338f8f85600460089054906101000a90046001600160401b03166001600160401b0316613475565b6001600160601b0382111561241c576040516389588ab360e01b815260040160405180910390fd5b61242a828888888888612f67565b5060016002559c9b505050505050505050505050565b612455335f356001600160e01b031916612ec1565b6124715760405162461bcd60e51b8152600401610dcb90614ead565b6001600160a01b0381165f81815260066020526040808220805463ff00000019166301000000179055517f5e92c085dffcb69d025c31c9ed03d1869e4737ba81e8649c623398caa1b72f159190a250565b5f6124d8335f356001600160e01b031916612ec1565b6124f45760405162461bcd60e51b8152600401610dcb90614ead565b6002546001146125165760405162461bcd60e51b8152600401610dcb90614ed3565b600280555f612524866130a1565b90506125348686863387866131de565b9150856001600160a01b03167f6f9b974223f85a1ae805c33b8b519039e2435481d949db1110de151a94d587af8660405161257191815260200190565b60405180910390a2506001600255949350505050565b61259c335f356001600160e01b031916612ec1565b6125b85760405162461bcd60e51b8152600401610dcb90614ead565b6001600160a01b0381165f81815260066020526040808220805460ff19169055517fae893dda71e2eee548f8291f458cceae4bd22b56a79906928591e4420444c0e99190a250565b6001600160a01b0383165f9081526006602052604090205460ff168061264257506001600160a01b0382165f90815260066020526040902054610100900460ff165b8061266a57506001600160a01b0381165f9081526006602052604090205462010000900460ff165b806126a85750600454600160881b900460ff1680156126a857506001600160a01b0381165f908152600660205260409020546301000000900460ff16155b156126e157604051632821264f60e01b81526001600160a01b038085166004830152808416602483015282166044820152606401610dcb565b6001600160a01b0383165f9081526006602052604090206001015442101561271c5760405163f64059db60e01b815260040160405180910390fd5b505050565b612736335f356001600160e01b031916612ec1565b6127525760405162461bcd60e51b8152600401610dcb90614ead565b806001600160801b03165f0361277b5760405163c80ed59560e01b815260040160405180910390fd5b63ffffffff83165f908152600a60205260409020805461010071ffffffffffffffffffffffffffffffffff0019909116620100006001600160801b03851602171781556127d1846001600160a01b0385166136d5565b6040805163ffffffff861681526001600160a01b03851660208201527f34fe916485e02ec88e487b0e611e5c9bacabba9e3eaae7a900aa08be8197d419910160405180910390a150505050565b612833335f356001600160e01b031916612ec1565b61284f5760405162461bcd60e51b8152600401610dcb90614ead565b6001600160a01b0381165f81815260066020526040808220805463ff00000019169055517f1c2a701d65e1c6e2860263c884eae0b10db82e3ddd60640d53c7d53c6c998e799190a250565b63ffffffff81165f90815260086020908152604080832081516080810183528154808252600183015494820185905260028301549382018490526003909201546060820181905285949193611f7a939291613895565b612905335f356001600160e01b031916612ec1565b6129215760405162461bcd60e51b8152600401610dcb90614ead565b6001600160a01b0381165f81815260066020526040808220805462ffffff19169055517fae893dda71e2eee548f8291f458cceae4bd22b56a79906928591e4420444c0e99190a26040516001600160a01b038216907f039bcf51833310242b8b7c6aa0fbabf1bf2b5e5270807ee020f1920ef200666b905f90a26040516001600160a01b038216907f77cb944c14da76928795279d1519ce9150085a06e0a53c61d5a86fc4e0fd57c6905f90a250565b6129e6335f356001600160e01b031916612ec1565b612a025760405162461bcd60e51b8152600401610dcb90614ead565b60405163ca5eb5e160e01b81526001600160a01b0382811660048301527f0000000000000000000000006f475642a6e85809b1c36fa62763669b1b48dd5b169063ca5eb5e1906024015f604051808303815f87803b158015612a62575f80fd5b505af1158015612a74573d5f803e3d5ffd5b5050505050565b5f612a91335f356001600160e01b031916612ec1565b612aad5760405162461bcd60e51b8152600401610dcb90614ead565b600254600114612acf5760405162461bcd60e51b8152600401610dcb90614ed3565b600280558873eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03821601612b12576040516316df5df960e31b815260040160405180910390fd5b5f612b1c8b6130a1565b9050612b2c8b8b8b3333866131de565b9250612b59338c8c86600460089054906101000a90046001600160401b03166001600160401b0316613475565b6001600160601b03831115612b81576040516389588ab360e01b815260040160405180910390fd5b612b8f838989898989612f67565b5050600160025598975050505050505050565b612bb7335f356001600160e01b031916612ec1565b612bd35760405162461bcd60e51b8152600401610dcb90614ead565b63ffffffff81165f818152600a6020908152604091829020805460ff19168155915192835290917f1cb867ed6a020e020ea220d4f48bb8e36552abf9095e093e377d33933f2b31e49101611bee565b604080518082019091526001600160601b03861681526001600160a01b03851660208201525f9081612c5382613910565b9050612c6181878787613957565b98975050505050505050565b6001600160a01b0381165f9081526006602052604090205460ff1615612cbe57604051632821264f60e01b81526001600160a01b03821660048201525f602482018190526044820152606401610dcb565b6001600160a01b0381165f90815260066020526040902060010154421015612cf95760405163f64059db60e01b815260040160405180910390fd5b50565b612d11335f356001600160e01b031916612ec1565b612d2d5760405162461bcd60e51b8152600401610dcb90614ead565b6115a88282808060200260200160405190810160405280939291908181526020015f905b82821015612d7d57612d6e60608302860136819003810190614fe4565b81526020019060010190612d51565b5050505050613b26565b612d9c335f356001600160e01b031916612ec1565b612db85760405162461bcd60e51b8152600401610dcb90614ead565b5f80546001600160a01b0319166001600160a01b0383169081178255604051909133917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a350565b612e17335f356001600160e01b031916612ec1565b612e335760405162461bcd60e51b8152600401610dcb90614ead565b6115a88282808060200260200160405190810160405280939291908181526020015f905b82821015612e8357612e7460608302860136819003810190614fe4565b81526020019060010190612e57565b5050505050613c18565b5f602082018035906007908390612ea49086614aab565b63ffffffff16815260208101919091526040015f20541492915050565b6001545f906001600160a01b03168015801590612f48575060405163b700961360e01b81526001600160a01b0382169063b700961390612f0990879030908890600401614f68565b602060405180830381865afa158015612f24573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612f489190614f95565b80612f5f57505f546001600160a01b038581169116145b949350505050565b612f72335f33612600565b6040516318457e6160e01b81525f600482018190526024820181905260448201523360648201526001600160601b03871660848201527f00000000000000000000000069d210d3b60e939bfa6e87cccc4fab7e8f44c16b6001600160a01b0316906318457e619060a4015f604051808303815f87803b158015612ff3575f80fd5b505af1158015613005573d5f803e3d5ffd5b5050604080518082019091526001600160601b03891681526001600160a01b038816602082015291505f905061303a82613910565b90505f61304a8288888888613d0a565b6040516001600160601b038b1681529091506001600160a01b0389169082907fe0ec62d39b054dc2fd626dbc271483735df6e6fa1ef8389754bf8ab27a75eab29060200160405180910390a3505050505050505050565b604080516060810182525f8082526020820181905291810191909152600454600160801b900460ff16156130e85760405163e0f9e71d60e01b815260040160405180910390fd5b506001600160a01b0381165f908152600360209081526040918290208251606081018452905460ff8082161515808452610100830490911615159383019390935262010000900461ffff16928101929092526131575760405163645fd19f60e11b815260040160405180910390fd5b919050565b5f60405163095ea7b360e01b81526001600160a01b038416600482015282602482015260205f6044835f895af13d15601f3d1160015f5114161716915050806131d85760405162461bcd60e51b815260206004820152600e60248201526d1054141493d59157d1905253115160921b6044820152606401610dcb565b50505050565b6004545f90600160901b90046001600160701b03168682036132135760405163259be69560e11b815260040160405180910390fd5b604051634104b9ed60e11b81526001600160a01b0389811660048301526132c9917f0000000000000000000000000000000000000000000000000de0b6b3a7640000917f000000000000000000000000fcb9a6bf02c43f9e38bb102fd960cc1e738e787d169063820973da90602401602060405180830381865afa15801561329d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906132c19190614ef7565b89919061387a565b91505f836040015161ffff16116132e05781613303565b61330383604001516127106132f59190615025565b839061ffff1661271061387a565b9150858210156133265760405163097b2ad560e31b815260040160405180910390fd5b6001600160701b03818116146133e957806001600160701b03167f00000000000000000000000069d210d3b60e939bfa6e87cccc4fab7e8f44c16b6001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561339c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906133c09190614ef7565b6133ca9084615047565b11156133e95760405163ed32f3bb60e01b815260040160405180910390fd5b604051631ceb5d1960e11b81526001600160a01b037f00000000000000000000000069d210d3b60e939bfa6e87cccc4fab7e8f44c16b16906339d6ba329061343d9088908c908c908a908990600401614f0e565b5f604051808303815f87803b158015613454575f80fd5b505af1158015613466573d5f803e3d5ffd5b50505050509695505050505050565b600480545f91908290613490906001600160401b031661505a565b82546001600160401b039182166101009390930a838102920219161790915590508115613537576134c18242615047565b6001600160a01b038781165f81815260066020908152604091829020600101949094558051938401919091529087169082015260608101859052608081018490524260a082015260c0810183905260e00160408051601f1981840301815291815281516020928301205f84815260059093529120555b846001600160a01b0316866001600160a01b0316827fe96d7872363f475d18b2f5390caaa5eaa96b2d38e42c62afe4ac08ebd2b13c3a87874288604051613597949392919093845260208401929092526040830152606082015260800190565b60405180910390a4505050505050565b63ffffffff81165f90815260076020526040812054806120fc5760405163f6ff4fb760e01b815263ffffffff84166004820152602401610dcb565b5f600a816135f360208b018b614aab565b63ffffffff16815260208082019290925260409081015f208151606081018352905460ff808216151580845261010083049091161515948301949094526201000090046001600160801b031691810191909152915061367b576136596020890189614aab565b6040516315b73a2960e21b815263ffffffff9091166004820152602401610dcb565b5f61368886880188614c7d565b90506136c061369a60208b018b614aab565b6040805180820190915260a084901c81526001600160a01b038416602082015251613f5d565b6136ca8882613fd2565b505050505050505050565b63ffffffff82165f81815260076020908152604091829020849055815192835282018390527f238399d427b947898edb290f5ff0f9109849b1c3ba196a42e35f00c50a54b98b9101611bee565b60405163d505accf60e01b81523360048201526001600160a01b037f00000000000000000000000069d210d3b60e939bfa6e87cccc4fab7e8f44c16b81166024830152604482018790526064820186905260ff8516608483015260a4820184905260c4820183905287169063d505accf9060e4015f604051808303815f87803b1580156137ad575f80fd5b505af19250505080156137be575060015b61387257604051636eb1769f60e11b81523360048201526001600160a01b037f00000000000000000000000069d210d3b60e939bfa6e87cccc4fab7e8f44c16b8116602483015286919088169063dd62ed3e90604401602060405180830381865afa15801561382f573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906138539190614ef7565b1015613872576040516301b8851f60e41b815260040160405180910390fd5b505050505050565b5f825f19048411830215820261388e575f80fd5b5091020490565b5f80806138a28642614f55565b90508381106138b6575f9250849150613906565b5f846138c2838861507f565b6138cc9190615096565b9050808811156138e5576138e08189614f55565b6138e7565b5f5b935083861115613900576138fb8487614f55565b613902565b5f5b9250505b5094509492505050565b80515f906001600160601b03101561393b57604051633524486360e01b815260040160405180910390fd5b81516020909201516001600160a01b031660a09290921b171790565b5f6001600160a01b03821673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee148015906139b757507f00000000000000000000000000000000000000000000000000000000000000016001600160a01b0316826001600160a01b031614155b156139d557604051637f3cd08160e11b815260040160405180910390fd5b5f6139e284860186614aab565b63ffffffff81165f908152600a60209081526040918290208251606081018452905460ff8082161515835261010082041615159282018390526201000090046001600160801b03169281019290925291925090613a5a5760405163420eae3760e01b815263ffffffff83166004820152602401610dcb565b5f87604051602001613a6e91815260200190565b60405160208183030381529060405290505f613ab683604001515f613aaf60408051600360f01b602082015281516002818303018152602290910190915290565b91906140be565b90505f613ae58584846001600160a01b038b1673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1415614123565b90506001600160a01b03871673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14613b15578060200151613b18565b80515b9a9950505050505050505050565b5f5b8151811015613be8575f60085f848481518110613b4757613b476150b5565b60200260200101515f015163ffffffff1663ffffffff1681526020019081526020015f209050613b93838381518110613b8257613b826150b5565b60200260200101515f01515f614201565b828281518110613ba557613ba56150b5565b6020026020010151602001518160020181905550828281518110613bcb57613bcb6150b5565b602090810291909101015160400151600390910155600101613b28565b507f55254e344b7fc8e2e038c1f7f20a1c7afe659c1a3bbfc4e35dd1ca9bba0ca0a081604051611e9f91906150c9565b5f5b8151811015613cda575f60095f848481518110613c3957613c396150b5565b60200260200101515f015163ffffffff1663ffffffff1681526020019081526020015f209050613c85838381518110613c7457613c746150b5565b60200260200101515f01515f613f5d565b828281518110613c9757613c976150b5565b6020026020010151602001518160020181905550828281518110613cbd57613cbd6150b5565b602090810291909101015160400151600390910155600101613c1a565b507f983af742b0b5ca79aa5c0be76cea126e1baf3139ecd04624deac13853c4bebde81604051611e9f91906150c9565b5f80613d1885870187614aab565b9050613d4c81613d46896040805180820190915260a082901c81526001600160a01b03909116602082015290565b51614201565b63ffffffff81165f908152600a60209081526040918290208251606081018452905460ff8082161515835261010082041615159282018390526201000090046001600160801b031692810192909252613dc05760405163420eae3760e01b815263ffffffff83166004820152602401610dcb565b5f88604051602001613dd491815260200190565b60405160208183030381529060405290505f613e1583604001515f613aaf60408051600360f01b602082015281516002818303018152602290910190915290565b90505f613e448584846001600160a01b038c1673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1415614123565b905073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b03891601613eab578051871015613ea657805160405163f5ac3fa760e01b815263ffffffff87166004820152602481019190915260448101889052606401610dcb565b613f3e565b7f00000000000000000000000000000000000000000000000000000000000000016001600160a01b0316886001600160a01b031603613f25578681602001511115613ea657602081015160405163f5ac3fa760e01b815263ffffffff87166004820152602481019190915260448101889052606401610dcb565b604051637f3cd08160e11b815260040160405180910390fd5b5f613f4c868585853361425d565b519c9b505050505050505050505050565b63ffffffff82165f90815260096020526040812080546001820154600283015460038401549394938493613f949390929091613895565b9150915080841115613fb957604051636a526abb60e01b815260040160405180910390fd5b613fc38483615047565b83555050426001909101555050565b60408051808201825260a083901c8082526001600160a01b03808516602084018190529351631ceb5d1960e11b815292937f00000000000000000000000069d210d3b60e939bfa6e87cccc4fab7e8f44c16b909116926339d6ba3292614041925f928392839291600401614f0e565b5f604051808303815f87803b158015614058575f80fd5b505af115801561406a573d5f803e3d5ffd5b5050505080602001516001600160a01b0316837fb944fddc61d7fedb8b736790454ba972000703b0d21c7481d6dbf95b7c2cc2f1835f01516040516140b191815260200190565b60405180910390a3505050565b60608360036140cd825f614363565b61ffff1614614100576140e0815f614363565b604051633a51740d60e01b815261ffff9091166004820152602401610dcb565b5f61410b85856143bf565b905061411986600183614438565b9695505050505050565b604080518082019091525f80825260208201527f0000000000000000000000006f475642a6e85809b1c36fa62763669b1b48dd5b6001600160a01b031663ddc28c586040518060a001604052808863ffffffff168152602001614185896135a7565b8152602001878152602001868152602001851515815250306040518363ffffffff1660e01b81526004016141ba929190615174565b6040805180830381865afa1580156141d4573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906141f89190615244565b95945050505050565b63ffffffff82165f908152600860205260408120805460018201546002830154600384015493949384936142389390929091613895565b9150915080841115613fb9576040516324292aa760e01b815260040160405180910390fd5b614265614666565b5f614272845f01516144a1565b60208501519091501561428c5761428c84602001516144c8565b7f0000000000000000000000006f475642a6e85809b1c36fa62763669b1b48dd5b6001600160a01b0316632637a450826040518060a001604052808b63ffffffff1681526020016142dc8c6135a7565b81526020018a81526020018981526020015f8960200151111515815250866040518463ffffffff1660e01b8152600401614317929190615174565b60806040518083038185885af1158015614333573d5f803e3d5ffd5b50505050506040513d601f19601f82011682018060405250810190614358919061525e565b979650505050505050565b5f61436f826002615047565b835110156143b65760405162461bcd60e51b8152602060048201526014602482015273746f55696e7431365f6f75744f66426f756e647360601b6044820152606401610dcb565b50016002015190565b60606001600160801b0382161561440757604080516001600160801b0319608086811b8216602084015285901b16603082015201604051602081830303815290604052614431565b6040516001600160801b0319608085901b1660208201526030016040516020818303038152906040525b9392505050565b6060836003614447825f614363565b61ffff161461445a576140e0815f614363565b84600161446785516145a7565b6144729060016152a6565b86866040516020016144889594939291906152c1565b6040516020818303038152906040529150509392505050565b5f8134146144c4576040516304fb820960e51b8152346004820152602401610dcb565b5090565b5f7f0000000000000000000000006f475642a6e85809b1c36fa62763669b1b48dd5b6001600160a01b031663e4fe1d946040518163ffffffff1660e01b8152600401602060405180830381865afa158015614525573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906145499190615327565b90506001600160a01b038116614572576040516329b99a9560e11b815260040160405180910390fd5b6115a86001600160a01b038216337f0000000000000000000000006f475642a6e85809b1c36fa62763669b1b48dd5b856145d5565b5f61ffff8211156144c4576040516306dfcc6560e41b81526010600482015260248101839052604401610dcb565b5f6040516323b872dd60e01b81526001600160a01b03851660048201526001600160a01b038416602482015282604482015260205f6064835f8a5af13d15601f3d1160015f511416171691505080612a745760405162461bcd60e51b81526020600482015260146024820152731514905394d1915497d19493d357d1905253115160621b6044820152606401610dcb565b60405180606001604052805f80191681526020015f6001600160401b031681526020016146a460405180604001604052805f81526020015f81525090565b905290565b80356001600160601b0381168114613157575f80fd5b6001600160a01b0381168114612cf9575f80fd5b8035613157816146bf565b5f8083601f8401126146ee575f80fd5b5081356001600160401b03811115614704575f80fd5b60208301915083602082850101111561471b575f80fd5b9250929050565b5f805f805f8060a08789031215614737575f80fd5b614740876146a9565b95506020870135614750816146bf565b945060408701356001600160401b0381111561476a575f80fd5b61477689828a016146de565b909550935050606087013561478a816146bf565b80925050608087013590509295509295509295565b5f805f606084860312156147b1575f80fd5b83356147bc816146bf565b95602085013595506040909401359392505050565b6001600160401b0381168114612cf9575f80fd5b5f602082840312156147f5575f80fd5b8135614431816147d1565b5f60608284031215614810575f80fd5b50919050565b5f805f805f805f60e0888a03121561482c575f80fd5b6148368989614800565b96506060880135955060808801356001600160401b0380821115614858575f80fd5b6148648b838c016146de565b909750955060a08a01359150614879826146bf565b90935060c0890135908082111561488e575f80fd5b5061489b8a828b016146de565b989b979a50959850939692959293505050565b803563ffffffff81168114613157575f80fd5b80356001600160801b0381168114613157575f80fd5b5f80604083850312156148e8575f80fd5b6148f1836148ae565b91506148ff602084016148c1565b90509250929050565b5f60208284031215614918575f80fd5b8135614431816146bf565b5f8060408385031215614934575f80fd5b61493d836148ae565b9150602083013561494d816146bf565b809150509250929050565b5f8060408385031215614969575f80fd5b614972836148ae565b946020939093013593505050565b8015158114612cf9575f80fd5b5f805f805f60a086880312156149a1575f80fd5b6149aa866148ae565b945060208601356149ba81614980565b935060408601356149ca81614980565b925060608601356149da816146bf565b91506149e8608087016148c1565b90509295509295909350565b803560ff81168114613157575f80fd5b5f805f805f805f60e0888a031215614a1a575f80fd5b8735614a25816146bf565b9650602088013595506040880135945060608801359350614a48608089016149f4565b925060a0880135915060c0880135905092959891949750929550565b5f805f8060808587031215614a77575f80fd5b8435614a82816146bf565b935060208501359250604085013591506060850135614aa0816146bf565b939692955090935050565b5f60208284031215614abb575f80fd5b614431826148ae565b5f805f805f805f60e0888a031215614ada575f80fd5b873596506020880135614aec816146bf565b95506040880135614afc816146bf565b969995985095966060810135965060808101359560a0820135955060c0909101359350915050565b5f60208284031215614b34575f80fd5b81356001600160701b0381168114614431575f80fd5b5f60208284031215614b5a575f80fd5b813561443181614980565b5f805f8060808587031215614b78575f80fd5b8435614b83816146bf565b93506020850135614b9381614980565b92506040850135614ba381614980565b9150606085013561ffff81168114614aa0575f80fd5b5f805f805f805f805f805f806101608d8f031215614bd5575f80fd5b614bdf8d356146bf565b8c359b5060208d01359a5060408d0135995060608d01359850614c0460808e016149f4565b975060a08d0135965060c08d01359550614c2160e08e01356146bf565b60e08d013594506001600160401b036101008e01351115614c40575f80fd5b614c518e6101008f01358f016146de565b9094509250614c636101208e016146d3565b91506101408d013590509295989b509295989b509295989b565b5f60208284031215614c8d575f80fd5b5035919050565b5f805f60608486031215614ca6575f80fd5b8335614cb1816146bf565b92506020840135614cc1816146bf565b91506040840135614cd1816146bf565b809150509250925092565b5f805f60608486031215614cee575f80fd5b614cf7846148ae565b92506020840135614d07816146bf565b9150614d15604085016148c1565b90509250925092565b5f805f805f805f8060e0898b031215614d35575f80fd5b8835614d40816146bf565b975060208901359650604089013595506060890135614d5e816146bf565b945060808901356001600160401b03811115614d78575f80fd5b614d848b828c016146de565b90955093505060a0890135614d98816146bf565b8092505060c089013590509295985092959890939650565b5f805f805f60808688031215614dc4575f80fd5b614dcd866146a9565b94506020860135614ddd816146bf565b935060408601356001600160401b03811115614df7575f80fd5b614e03888289016146de565b9094509250506060860135614e17816146bf565b809150509295509295909350565b5f8060208385031215614e36575f80fd5b82356001600160401b0380821115614e4c575f80fd5b818501915085601f830112614e5f575f80fd5b813581811115614e6d575f80fd5b866020606083028501011115614e81575f80fd5b60209290920196919550909350505050565b5f60608284031215614ea3575f80fd5b6144318383614800565b6020808252600c908201526b15539055551213d49256915160a21b604082015260600190565b6020808252600a90820152695245454e5452414e435960b01b604082015260600190565b5f60208284031215614f07575f80fd5b5051919050565b6001600160a01b039586168152938516602085015260408401929092529092166060820152608081019190915260a00190565b634e487b7160e01b5f52601160045260245ffd5b818103818111156120fc576120fc614f41565b6001600160a01b0393841681529190921660208201526001600160e01b0319909116604082015260600190565b5f60208284031215614fa5575f80fd5b815161443181614980565b604051606081016001600160401b0381118282101715614fde57634e487b7160e01b5f52604160045260245ffd5b60405290565b5f60608284031215614ff4575f80fd5b614ffc614fb0565b615005836148ae565b815260208301356020820152604083013560408201528091505092915050565b61ffff82811682821603908082111561504057615040614f41565b5092915050565b808201808211156120fc576120fc614f41565b5f6001600160401b0380831681810361507557615075614f41565b6001019392505050565b80820281158282048414176120fc576120fc614f41565b5f826150b057634e487b7160e01b5f52601260045260245ffd5b500490565b634e487b7160e01b5f52603260045260245ffd5b602080825282518282018190525f919060409081850190868401855b8281101561511a578151805163ffffffff168552868101518786015285015185850152606090930192908501906001016150e5565b5091979650505050505050565b5f5b83811015615141578181015183820152602001615129565b50505f910152565b5f8151808452615160816020860160208601615127565b601f01601f19169290920160200192915050565b6040815263ffffffff8351166040820152602083015160608201525f604084015160a060808401526151a960e0840182615149565b90506060850151603f198483030160a08501526151c68282615149565b60809690960151151560c08501525050506001600160a01b039190911660209091015290565b5f604082840312156151fc575f80fd5b604051604081018181106001600160401b038211171561522a57634e487b7160e01b5f52604160045260245ffd5b604052825181526020928301519281019290925250919050565b5f60408284031215615254575f80fd5b61443183836151ec565b5f6080828403121561526e575f80fd5b615276614fb0565b825181526020830151615288816147d1565b602082015261529a84604085016151ec565b60408201529392505050565b61ffff81811683821601908082111561504057615040614f41565b5f86516152d2818460208b01615127565b6001600160f81b031960f888811b82169285019283526001600160f01b031960f089901b16600184015286901b1660038201528351615318816004840160208801615127565b01600401979650505050505050565b5f60208284031215615337575f80fd5b8151614431816146bf56fea264697066735822122024354ee82ccbadd74af752050ba0f64dbc9084de8a475de8255e5616f2249c7e64736f6c63430008150033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000005f2f11ad8656439d5c14d9b351f8b09cdac2a02d00000000000000000000000069d210d3b60e939bfa6e87cccc4fab7e8f44c16b000000000000000000000000fcb9a6bf02c43f9e38bb102fd960cc1e738e787d000000000000000000000000ee7d8bcfb72bc1880d0cf19822eb0a2e6577ab620000000000000000000000006f475642a6e85809b1c36fa62763669b1b48dd5b0000000000000000000000005f2f11ad8656439d5c14d9b351f8b09cdac2a02d0000000000000000000000000000000000000000000000000000000000000001
-----Decoded View---------------
Arg [0] : _owner (address): 0x5F2F11ad8656439d5C14d9B351f8b09cDaC2A02d
Arg [1] : _vault (address): 0x69d210d3b60E939BFA6E87cCcC4fAb7e8F44C16B
Arg [2] : _accountant (address): 0xFCb9a6bF02C43f9E38Bb102fd960Cc1e738e787d
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] : 00000000000000000000000069d210d3b60e939bfa6e87cccc4fab7e8f44c16b
Arg [2] : 000000000000000000000000fcb9a6bf02c43f9e38bb102fd960cc1e738e787d
Arg [3] : 000000000000000000000000ee7d8bcfb72bc1880d0cf19822eb0a2e6577ab62
Arg [4] : 0000000000000000000000006f475642a6e85809b1c36fa62763669b1b48dd5b
Arg [5] : 0000000000000000000000005f2f11ad8656439d5c14d9b351f8b09cdac2a02d
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000001
Deployed Bytecode Sourcemap
641:10974:30:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3647:33:34;;;;;;;;;;-1:-1:-1;3647:33:34;;;;-1:-1:-1;;;3647:33:34;;;;;;;;;179:14:39;;172:22;154:41;;142:2;127:18;3647:33:34;;;;;;;;4458:333:31;;;;;;:::i;:::-;;:::i;:::-;;7509:35:34;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;2048:32:39;;;2030:51;;2018:2;2003:18;7509:35:34;1863:224:39;17922:1156:34;;;;;;:::i;:::-;;:::i;:::-;;;2640:25:39;;;2628:2;2613:18;17922:1156:34;2494:177:39;9901:242:34;;;;;;;;;;-1:-1:-1;9901:242:34;;;;;:::i;:::-;;:::i;3998:708:11:-;;;;;;:::i;:::-;;:::i;6979:359:30:-;;;;;;;;;;-1:-1:-1;6979:359:30;;;;;:::i;:::-;;:::i;1321:243:9:-;;;;;;;;;;-1:-1:-1;1321:243:9;;;856:1:12;5102:34:39;;;5167:2;5152:18;;5145:43;5038:18;1321:243:9;4895:299:39;10284:301:34;;;;;;;;;;-1:-1:-1;10284:301:34;;;;;:::i;:::-;;:::i;12212:152::-;;;;;;;;;;-1:-1:-1;12212:152:34;;;;;:::i;:::-;;:::i;12492:155::-;;;;;;;;;;-1:-1:-1;12492:155:34;;;;;:::i;:::-;;:::i;4791:304:30:-;;;;;;;;;;-1:-1:-1;4791:304:30;;;;;:::i;:::-;;:::i;11155:140:34:-;;;;;;;;;;-1:-1:-1;11155:140:34;;;;;:::i;:::-;;:::i;1720:111:10:-;;;;;;;;;;-1:-1:-1;1720:111:10;;;;;:::i;:::-;;:::i;3849:554:30:-;;;;;;;;;;-1:-1:-1;3849:554:30;;;;;:::i;:::-;;:::i;11686:134:34:-;;;;;;;;;;-1:-1:-1;11686:134:34;;;;;:::i;:::-;;:::i;19201:646::-;;;;;;;;;;-1:-1:-1;19201:646:34;;;;;:::i;:::-;;:::i;20566:818::-;;;;;;;;;;-1:-1:-1;20566:818:34;;;;;:::i;:::-;;:::i;8452:99::-;;;;;;;;;;;;;:::i;3002:40::-;;;;;;;;;;-1:-1:-1;3002:40:34;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8689:14:39;;8682:22;8664:41;;8748:14;;8741:22;8736:2;8721:18;;8714:50;8812:6;8800:19;8780:18;;;8773:47;8652:2;8637:18;3002:40:34;8476:350:39;6112:208:30;;;;;;;;;;-1:-1:-1;6112:208:30;;;;;:::i;:::-;;:::i;16367:1302:34:-;;;;;;;;;;-1:-1:-1;16367:1302:34;;;;;:::i;:::-;;:::i;7283:55::-;;;;;;;;;;;;;;;1301:67:33;;;;;;;;;;-1:-1:-1;1301:67:33;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;10232:25:39;;;10288:2;10273:18;;10266:34;;;;10316:18;;;10309:34;10374:2;10359:18;;10352:34;10219:3;10204:19;1301:67:33;10001:391:39;4511:178:30;;;;;;;;;;-1:-1:-1;4511:178:30;;;;;:::i;:::-;;:::i;1374:66:33:-;;;;;;;;;;-1:-1:-1;1374:66:33;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4296:64:34;;;;;;;;;;-1:-1:-1;4296:64:34;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;10657:14:39;;10650:22;10632:41;;10716:14;;10709:22;10704:2;10689:18;;10682:50;10775:14;;10768:22;10748:18;;;10741:50;;;;10834:14;;10827:22;10822:2;10807:18;;10800:50;10881:3;10866:19;;10859:35;10619:3;10604:19;4296:64:34;10397:503:39;442:46:10;;;;;;;;;;;;;;;11942:137:34;;;;;;;;;;-1:-1:-1;11942:137:34;;;;;:::i;:::-;;:::i;3096:329:33:-;;;;;;;;;;-1:-1:-1;3096:329:33;;;;;:::i;:::-;;:::i;:::-;;;;11315:25:39;;;11371:2;11356:18;;11349:34;;;;11288:18;3096:329:33;11141:248:39;1523:434:22;;;;;;;;;;-1:-1:-1;1523:434:22;;;;;:::i;:::-;;:::i;13817:126:34:-;;;;;;;;;;-1:-1:-1;13817:126:34;;;;;:::i;:::-;;:::i;3136:129:11:-;;;;;;;;;;-1:-1:-1;3136:129:11;;;;;:::i;:::-;;:::i;:::-;;;-1:-1:-1;;;;;12128:31:39;;;12110:50;;12098:2;12083:18;3136:129:11;11966:200:39;8195:94:34;;;;;;;;;;;;;:::i;12757:211::-;;;;;;;;;;-1:-1:-1;12757:211:34;;;;;:::i;:::-;;:::i;562:20:22:-;;;;;;;;;;-1:-1:-1;562:20:22;;;;-1:-1:-1;;;;;562:20:22;;;8768:426:34;;;;;;;;;;-1:-1:-1;8768:426:34;;;;;:::i;:::-;;:::i;2956:1113:31:-;;;;;;:::i;:::-;;:::i;4082:55:34:-;;;;;;;;;;-1:-1:-1;4082:55:34;;;;;:::i;:::-;;;;;;;;;;;;;;13133:198;;;;;;;;;;-1:-1:-1;13133:198:34;;;;;:::i;:::-;;:::i;20018:421::-;;;;;;;;;;-1:-1:-1;20018:421:34;;;;;:::i;:::-;;:::i;3406:29::-;;;;;;;;;;-1:-1:-1;3406:29:34;;;;-1:-1:-1;;;3406:29:34;;-1:-1:-1;;;;;3406:29:34;;;11418:143;;;;;;;;;;-1:-1:-1;11418:143:34;;;;;:::i;:::-;;:::i;14546:602::-;;;;;;;;;;-1:-1:-1;14546:602:34;;;;;:::i;:::-;;:::i;3531:20::-;;;;;;;;;;-1:-1:-1;3531:20:34;;;;-1:-1:-1;;;3531:20:34;;;;;;5195:497:30;;;;;;;;;;-1:-1:-1;5195:497:30;;;;;:::i;:::-;;:::i;1748:110:11:-;;;;;;;;;;-1:-1:-1;1846:4:11;1748:110;;565:48:10;;;;;;;;;;-1:-1:-1;565:48:10;;;;;:::i;:::-;;;;;;;;;;;;;;13513:197:34;;;;;;;;;;-1:-1:-1;13513:197:34;;;;;:::i;:::-;;:::i;589:26:22:-;;;;;;;;;;-1:-1:-1;589:26:22;;;;-1:-1:-1;;;;;589:26:22;;;2453:323:33;;;;;;;;;;-1:-1:-1;2453:323:33;;;;;:::i;:::-;;:::i;10719:308:34:-;;;;;;;;;;-1:-1:-1;10719:308:34;;;;;:::i;:::-;;:::i;3251:108:10:-;;;;;;;;;;-1:-1:-1;3251:108:10;;;;;:::i;:::-;;:::i;1569:912:31:-;;;;;;:::i;:::-;;:::i;1686:42:30:-;;;;;;;;;;-1:-1:-1;1686:42:30;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;1686:42:30;;;;;;;17403:14:39;;17396:22;17378:41;;17462:14;;17455:22;17450:2;17435:18;;17428:50;-1:-1:-1;;;;;17514:47:39;17494:18;;;17487:75;17366:2;17351:18;1686:42:30;17188:380:39;5796:214:30;;;;;;;;;;-1:-1:-1;5796:214:30;;;;;:::i;:::-;;:::i;4887:357:31:-;;;;;;;;;;-1:-1:-1;4887:357:31;;;;;:::i;:::-;;:::i;3840:45:34:-;;;;;;;;;;-1:-1:-1;3840:45:34;;;;-1:-1:-1;;;3840:45:34;;-1:-1:-1;;;;;3840:45:34;;;;;;-1:-1:-1;;;;;18514:43:39;;;18496:62;;18484:2;18469:18;3840:45:34;18350:214:39;3129:26:34;;;;;;;;;;-1:-1:-1;3129:26:34;;;;-1:-1:-1;;;;;3129:26:34;;;15286:369;;;;;;;;;;-1:-1:-1;15286:369:34;;;;;:::i;:::-;;:::i;6436:157:30:-;;;;;;;;;;-1:-1:-1;6436:157:30;;;;;:::i;:::-;;:::i;1963:164:22:-;;;;;;;;;;-1:-1:-1;1963:164:22;;;;;:::i;:::-;;:::i;6708:155:30:-;;;;;;;;;;-1:-1:-1;6708:155:30;;;;;:::i;:::-;;:::i;7148:34:34:-;;;;;;;;;;;;;;;2400:149:11;;;;;;;;;;-1:-1:-1;2400:149:11;;;;;:::i;:::-;;:::i;4458:333:31:-;902:33:22;915:10;927:7;;-1:-1:-1;;;;;;927:7:22;902:12;:33::i;:::-;894:58;;;;-1:-1:-1;;;894:58:22;;;;;;;:::i;:::-;;;;;;;;;512:6:26::1;;522:1;512:11;504:34;;;;-1:-1:-1::0;;;504:34:26::1;;;;;;;:::i;:::-;558:1;549:10:::0;;4662:8:31::2;::::0;-1:-1:-1;;;4662:8:31;::::2;;;4658:58;;;4679:37;;-1:-1:-1::0;;;4679:37:31::2;;;;;;;;;;;4658:58;4726;4734:11;4747:2;4751:14;;4767:8;4777:6;4726:7;:58::i;:::-;-1:-1:-1::0;;591:1:26::1;582:6;:10:::0;-1:-1:-1;;;;4458:333:31:o;17922:1156:34:-;18095:14;902:33:22;915:10;927:7;;-1:-1:-1;;;;;;927:7:22;902:12;:33::i;:::-;894:58;;;;-1:-1:-1;;;894:58:22;;;;;;;:::i;:::-;512:6:26::1;;522:1;512:11;504:34;;;;-1:-1:-1::0;;;504:34:26::1;;;;;;;:::i;:::-;558:1;549:10:::0;;18125:18:34::2;18146:28;18161:12:::0;18146:14:::2;:28::i;:::-;18125:49:::0;-1:-1:-1;18185:12:34::2;-1:-1:-1::0;;;;;;;18211:31:34;::::2;::::0;18207:670:::2;;18262:9;18275:1;18262:14:::0;18258:68:::2;;18285:41;;-1:-1:-1::0;;;18285:41:34::2;;;;;;;;;;;18258:68;18340:13;-1:-1:-1::0;;;;;18340:21:34::2;;18369:9;18340:41;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;-1:-1:-1::0;18458:9:34::2;::::0;-1:-1:-1;18481:56:34::2;::::0;-1:-1:-1;;;;;;;18481:13:34::2;:25;::::0;-1:-1:-1;18515:5:34::2;::::0;-1:-1:-1;18458:9:34;18481:25:::2;:56::i;:::-;-1:-1:-1::0;18619:13:34::2;::::0;-1:-1:-1;18731:4:34::2;18207:670;;;18771:9;:13:::0;18767:68:::2;;18793:42;;-1:-1:-1::0;;;18793:42:34::2;;;;;;;;;;;18767:68;-1:-1:-1::0;18856:10:34::2;18207:670;18896:80;18910:12;18924:13;18939:11;18952:4;18958:10;18970:5;18896:13;:80::i;:::-;18887:89;;18986:85;19006:10;19018:12;19032:13;19047:6;19055:15;;;;;;;;;-1:-1:-1::0;;;;;19055:15:34::2;-1:-1:-1::0;;;;;18986:85:34::2;:19;:85::i;:::-;-1:-1:-1::0;;591:1:26::1;582:6;:10:::0;17922:1156:34;;-1:-1:-1;;;17922:1156:34:o;9901:242::-;902:33:22;915:10;927:7;;-1:-1:-1;;;;;;927:7:22;902:12;:33::i;:::-;894:58;;;;-1:-1:-1;;;894:58:22;;;;;;;:::i;:::-;2636:6:34::1;9990:16;-1:-1:-1::0;;;;;9990:40:34::1;;9986:106;;;10039:53;;-1:-1:-1::0;;;10039:53:34::1;;;;;;;;;;;9986:106;10102:15;:34:::0;;-1:-1:-1;;;;;10102:34:34;;::::1;-1:-1:-1::0;;;10102:34:34::1;-1:-1:-1::0;;10102:34:34;;::::1;::::0;;;::::1;::::0;;9901:242::o;3998:708:11:-;4311:8;-1:-1:-1;;;;;4303:31:11;4324:10;4303:31;4299:68;;4343:24;;-1:-1:-1;;;4343:24:11;;4356:10;4343:24;;;2030:51:39;2003:18;;4343:24:11;1863:224:39;4299:68:11;4503:14;;;;;;4467:32;;4484:14;;4503:7;4484:14;:::i;:::-;4467:16;:32::i;:::-;:50;4463:103;;4535:14;;;;:7;:14;:::i;:::-;4526:40;;-1:-1:-1;;;4526:40:11;;20585:10:39;20573:23;;;4526:40:11;;;20555:42:39;4551:14:11;;;;20613:18:39;;;20606:34;20528:18;;4526:40:11;20383:263:39;4463:103:11;4640:59;4651:7;4660:5;4667:8;;4677:9;4688:10;;4640;:59::i;:::-;3998:708;;;;;;;:::o;6979:359:30:-;902:33:22;915:10;927:7;;-1:-1:-1;;;;;;927:7:22;902:12;:33::i;:::-;894:58;;;;-1:-1:-1;;;894:58:22;;;;;;;:::i;:::-;7082:15:30::1;-1:-1:-1::0;;;;;7082:20:30::1;7101:1;7082:20:::0;7078:96:::1;;7125:38;;-1:-1:-1::0;;;7125:38:30::1;;;;;;;;;;;7078:96;7205:19;::::0;::::1;7183;7205::::0;;;:10:::1;:19;::::0;;;;;;;;7234:39;;-1:-1:-1;;;;;;7234:39:30::1;::::0;-1:-1:-1;;;;;7234:39:30;::::1;::::0;;::::1;::::0;;;::::1;::::0;;7289:42;;20824::39;;;20882:18;;;20875:75;;;;7205:19:30;7289:42:::1;::::0;20797:18:39;7289:42:30::1;;;;;;;;7068:270;6979:359:::0;;:::o;10284:301:34:-;902:33:22;915:10;927:7;;-1:-1:-1;;;;;;927:7:22;902:12;:33::i;:::-;894:58;;;;-1:-1:-1;;;894:58:22;;;;;;;:::i;:::-;-1:-1:-1;;;;;10347:24:34;::::1;;::::0;;;:18:::1;:24;::::0;;;;;:40;;-1:-1:-1;;10445:44:34;;;;;10504:14;::::1;::::0;10347:24;10504:14:::1;10533:12;::::0;-1:-1:-1;;;;;10533:12:34;::::1;::::0;::::1;::::0;;;::::1;10560:18;::::0;-1:-1:-1;;;;;10560:18:34;::::1;::::0;::::1;::::0;;;::::1;10284:301:::0;:::o;12212:152::-;902:33:22;915:10;927:7;;-1:-1:-1;;;;;;927:7:22;902:12;:33::i;:::-;894:58;;;;-1:-1:-1;;;894:58:22;;;;;;;:::i;:::-;-1:-1:-1;;;;;12280:24:34;::::1;;::::0;;;:18:::1;:24;::::0;;;;;:44;;-1:-1:-1;;12280:44:34::1;::::0;::::1;::::0;;12339:18;::::1;::::0;12280:24;12339:18:::1;12212:152:::0;:::o;12492:155::-;902:33:22;915:10;927:7;;-1:-1:-1;;;;;;927:7:22;902:12;:33::i;:::-;894:58;;;;-1:-1:-1;;;894:58:22;;;;;;;:::i;:::-;-1:-1:-1;;;;;12561:24:34;::::1;12601:5;12561:24:::0;;;:18:::1;:24;::::0;;;;;:45;;-1:-1:-1;;12561:45:34::1;::::0;;12621:19;::::1;::::0;12601:5;12621:19:::1;12492:155:::0;:::o;4791:304:30:-;902:33:22;915:10;927:7;;-1:-1:-1;;;;;;927:7:22;902:12;:33::i;:::-;894:58;;;;-1:-1:-1;;;894:58:22;;;;;;;:::i;:::-;4915:19:30::1;::::0;::::1;4893;4915::::0;;;:10:::1;:19;::::0;;;;4944:30;;-1:-1:-1;;4944:30:30::1;4970:4;4944:30;::::0;;4984:43:::1;4915:19:::0;-1:-1:-1;;;;;5002:22:30;::::1;4984:8;:43::i;:::-;5043:45;::::0;;21164:10:39;21152:23;;21134:42;;-1:-1:-1;;;;;21212:32:39;;21207:2;21192:18;;21185:60;5043:45:30::1;::::0;21107:18:39;5043:45:30::1;20961:290:39::0;11155:140:34;902:33:22;915:10;927:7;;-1:-1:-1;;;;;;927:7:22;902:12;:33::i;:::-;894:58;;;;-1:-1:-1;;;894:58:22;;;;;;;:::i;:::-;-1:-1:-1;;;;;11219:24:34;::::1;;::::0;;;:18:::1;:24;::::0;;;;;:40;;-1:-1:-1;;11219:40:34::1;11255:4;11219:40;::::0;;11274:14;::::1;::::0;11219:24;11274:14:::1;11155:140:::0;:::o;1720:111:10:-;902:33:22;915:10;927:7;;-1:-1:-1;;;;;;927:7:22;902:12;:33::i;:::-;894:58;;;;-1:-1:-1;;;894:58:22;;;;;;;:::i;:::-;1803:21:10::1;1812:4;1818:5;1803:8;:21::i;:::-;1720:111:::0;;:::o;3849:554:30:-;902:33:22;915:10;927:7;;-1:-1:-1;;;;;;927:7:22;902:12;:33::i;:::-;894:58;;;;-1:-1:-1;;;894:58:22;;;;;;;:::i;:::-;4058:15:30::1;:39;;;;-1:-1:-1::0;;;;;;4077:20:30;::::1;::::0;4058:39:::1;4054:115;;;4120:38;;-1:-1:-1::0;;;4120:38:30::1;;;;;;;;;;;4054:115;4200:58;::::0;;::::1;::::0;::::1;::::0;;;::::1;;::::0;;;::::1;;;::::0;;::::1;::::0;;;-1:-1:-1;;;;;4200:58:30;;::::1;::::0;;;;;;4178:19:::1;::::0;::::1;-1:-1:-1::0;4178:19:30;;;:10:::1;:19:::0;;;;;;;:80;;;;;;;;-1:-1:-1;;4178:80:30;;;;::::1;;-1:-1:-1::0;;4178:80:30;;::::1;::::0;::::1;;::::0;;;::::1;::::0;;;::::1;-1:-1:-1::0;;;;;;4178:80:30::1;::::0;;;;::::1;;::::0;;;::::1;::::0;;4268:43:::1;4178:19:::0;-1:-1:-1;;;;;4286:22:30;::::1;4984:8;:43::i;4268:::-;4327:69;::::0;;21504:10:39;21492:23;;21474:42;;21559:14;;21552:22;21547:2;21532:18;;21525:50;21618:14;;21611:22;21591:18;;;21584:50;-1:-1:-1;;;;;21670:32:39;;21665:2;21650:18;;21643:60;4327:69:30;;::::1;::::0;;;;21461:3:39;4327:69:30;;::::1;3849:554:::0;;;;;:::o;11686:134:34:-;902:33:22;915:10;927:7;;-1:-1:-1;;;;;;927:7:22;902:12;:33::i;:::-;894:58;;;;-1:-1:-1;;;894:58:22;;;;;;;:::i;:::-;-1:-1:-1;;;;;11748:24:34;::::1;;::::0;;;:18:::1;:24;::::0;;;;;:38;;-1:-1:-1;;11748:38:34::1;;;::::0;;11801:12;::::1;::::0;11748:24;11801:12:::1;11686:134:::0;:::o;19201:646::-;19492:14;902:33:22;915:10;927:7;;-1:-1:-1;;;;;;927:7:22;902:12;:33::i;:::-;894:58;;;;-1:-1:-1;;;894:58:22;;;;;;;:::i;:::-;512:6:26::1;;522:1;512:11;504:34;;;;-1:-1:-1::0;;;504:34:26::1;;;;;;;:::i;:::-;558:1;549:10:::0;;19468:12:34;-1:-1:-1;;;;;;;6884:22:34;::::2;::::0;6880:85:::2;;6915:50;;-1:-1:-1::0;;;6915:50:34::2;;;;;;;;;;;6880:85;19518:18:::3;19539:28;19554:12;19539:14;:28::i;:::-;19518:49;;19578:61;19592:12;19606:13;19621:8;19631:1;19634;19637;19578:13;:61::i;:::-;19659:86;19673:12;19687:13;19702:11;19715:10;19727;19739:5;19659:13;:86::i;:::-;19650:95;;19755:85;19775:10;19787:12;19801:13;19816:6;19824:15;;;;;;;;;-1:-1:-1::0;;;;;19824:15:34::3;-1:-1:-1::0;;;;;19755:85:34::3;:19;:85::i;:::-;-1:-1:-1::0;;591:1:26::1;582:6;:10:::0;19201:646:34;;-1:-1:-1;;;;;;;19201:646:34:o;20566:818::-;20720:17;902:33:22;915:10;927:7;;-1:-1:-1;;;;;;927:7:22;902:12;:33::i;:::-;894:58;;;;-1:-1:-1;;;894:58:22;;;;;;;:::i;:::-;20757:8:34::1;::::0;-1:-1:-1;;;20757:8:34;::::1;;;20753:58;;;20774:37;;-1:-1:-1::0;;;20774:37:34::1;;;;;;;;;;;20753:58;-1:-1:-1::0;;;;;20842:24:34;::::1;20821:18;20842:24:::0;;;:9:::1;:24;::::0;;;;;;;;20821:45;;::::1;::::0;::::1;::::0;;;;::::1;::::0;;::::1;;;::::0;;::::1;::::0;::::1;;;;::::0;;::::1;::::0;;;;;::::1;;;::::0;;;;;;;20876:82:::1;;20910:48;;-1:-1:-1::0;;;20910:48:34::1;;;;;;;;;;;20876:82;20973:11;20988:1;20973:16:::0;20969:70:::1;;20998:41;;-1:-1:-1::0;;;20998:41:34::1;;;;;;;;;;;20969:70;21084:44;::::0;-1:-1:-1;;;21084:44:34;;-1:-1:-1;;;;;2048:32:39;;;21084:44:34::1;::::0;::::1;2030:51:39::0;21061:79:34::1;::::0;21084:10:::1;:29:::0;;::::1;::::0;::::1;::::0;2003:18:39;;21084:44:34::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;21061:11:::0;;21130:9:::1;21061:22;:79::i;:::-;21049:91;;21166:13;21154:9;:25;21150:88;;;21188:50;;-1:-1:-1::0;;;21188:50:34::1;;;;;;;;;;;21150:88;21248:65;::::0;-1:-1:-1;;;21248:65:34;;-1:-1:-1;;;;;21248:5:34::1;:10;::::0;::::1;::::0;:65:::1;::::0;21259:2;;21263:13;;21278:9;;21289:10:::1;::::0;21301:11;;21248:65:::1;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;21349:13;-1:-1:-1::0;;;;;21328:49:34::1;;21365:11;21328:49;;;;2640:25:39::0;;2628:2;2613:18;;2494:177;21328:49:34::1;;;;;;;;20743:641;20566:818:::0;;;;;;:::o;8452:99::-;902:33:22;915:10;927:7;;-1:-1:-1;;;;;;927:7:22;902:12;:33::i;:::-;894:58;;;;-1:-1:-1;;;894:58:22;;;;;;;:::i;:::-;8503:8:34::1;:16:::0;;-1:-1:-1;;;;8503:16:34::1;::::0;;8534:10:::1;::::0;::::1;::::0;8514:5:::1;::::0;8534:10:::1;8452:99::o:0;6112:208:30:-;902:33:22;915:10;927:7;;-1:-1:-1;;;;;;927:7:22;902:12;:33::i;:::-;894:58;;;;-1:-1:-1;;;894:58:22;;;;;;;:::i;:::-;6211:19:30::1;::::0;::::1;6189;6211::::0;;;:10:::1;:19;::::0;;;;;;;;6240:29;;-1:-1:-1;;6240:29:30::1;::::0;;6285:28;;22817:42:39;;;6211:19:30;;6285:28:::1;::::0;22790:18:39;6285:28:30::1;;;;;;;;6179:141;6112:208:::0;:::o;16367:1302:34:-;902:33:22;915:10;927:7;;-1:-1:-1;;;;;;927:7:22;902:12;:33::i;:::-;894:58;;;;-1:-1:-1;;;894:58:22;;;;;;;:::i;:::-;16695:32:34;16656:34:::1;16674:16:::0;16656:15:::1;:34;:::i;:::-;16655:72;16651:232;;16824:48;;-1:-1:-1::0;;;16824:48:34::1;;;;;;;;;;;16651:232;16937:144;::::0;;-1:-1:-1;;;;;23478:15:39;;;16937:144:34::1;::::0;::::1;23460:34:39::0;23530:15;;23510:18;;;23503:43;;;;23562:18;;;23555:34;;;23605:18;;;23598:34;;;23648:19;;;23641:35;;;23692:19;;;23685:35;;;16892:19:34::1;::::0;23394::39;;16937:144:34::1;::::0;;-1:-1:-1;;16937:144:34;;::::1;::::0;;;;;;16914:177;;16937:144:::1;16914:177:::0;;::::1;::::0;17105:27:::1;::::0;;;:20:::1;:27:::0;;;;;;16914:177;;-1:-1:-1;17105:42:34;::::1;17101:100;;17156:45;;-1:-1:-1::0;;;17156:45:34::1;;;;;;;;;;;17101:100;17265:27;::::0;;;:20:::1;:27;::::0;;;;17258:34;-1:-1:-1;;;;;17396:22:34;::::1;2466:42;17396:22;:62;;17446:12;17396:62;;;17429:13;17396:62;17522:79;::::0;-1:-1:-1;;;17522:79:34;;17381:77;;-1:-1:-1;;;;;;17522:5:34::1;:10;::::0;::::1;::::0;:79:::1;::::0;17533:8;;17381:77;;17564:13;;17533:8;;17589:11;;17522:79:::1;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;17653:8;-1:-1:-1::0;;;;;17617:45:34::1;17633:5;17617:45;17640:11;17617:45;;;;2640:25:39::0;;2628:2;2613:18;;2494:177;17617:45:34::1;;;;;;;;16641:1028;16367:1302:::0;;;;;;;:::o;4511:178:30:-;902:33:22;915:10;927:7;;-1:-1:-1;;;;;;927:7:22;902:12;:33::i;:::-;894:58;;;;-1:-1:-1;;;894:58:22;;;;;;;:::i;:::-;4587:19:30::1;::::0;::::1;;::::0;;;:10:::1;:19;::::0;;;;4580:26;;-1:-1:-1;;4580:26:30;;;4616:29:::1;::::0;4598:7;;4616:8:::1;:29::i;:::-;4661:21;::::0;22847:10:39;22835:23;;22817:42;;4661:21:30::1;::::0;22805:2:39;22790:18;4661:21:30::1;;;;;;;;4511:178:::0;:::o;11942:137:34:-;902:33:22;915:10;927:7;;-1:-1:-1;;;;;;927:7:22;902:12;:33::i;:::-;894:58;;;;-1:-1:-1;;;894:58:22;;;;;;;:::i;:::-;-1:-1:-1;;;;;12005:24:34;::::1;12039:5;12005:24:::0;;;:18:::1;:24;::::0;;;;;:39;;-1:-1:-1;;12005:39:34::1;::::0;;12059:13;::::1;::::0;12039:5;12059:13:::1;11942:137:::0;:::o;3096:329:33:-;3303:26;;;3207:29;3303:26;;;:17;:26;;;;;;;;3281:48;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3207:29;;3281:48;;3346:72;;3281:48;;3346:16;:72::i;:::-;3339:79;;;;;3096:329;;;:::o;1523:434:22:-;1794:5;;-1:-1:-1;;;;;1794:5:22;1780:10;:19;;:76;;-1:-1:-1;1803:9:22;;:53;;-1:-1:-1;;;1803:53:22;;-1:-1:-1;;;;;1803:9:22;;;;:17;;:53;;1821:10;;1841:4;;-1:-1:-1;;;;;;1803:9:22;1848:7;;;1803:53;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;1772:85;;;;;;1868:9;:24;;-1:-1:-1;;;;;;1868:24:22;-1:-1:-1;;;;;1868:24:22;;;;;;;;1908:42;;1925:10;;1908:42;;-1:-1:-1;;1908:42:22;1523:434;:::o;13817:126:34:-;902:33:22;915:10;927:7;;-1:-1:-1;;;;;;927:7:22;902:12;:33::i;:::-;894:58;;;;-1:-1:-1;;;894:58:22;;;;;;;:::i;:::-;13885:10:34::1;:16:::0;;;::::1;-1:-1:-1::0;;;;;;;;13885:16:34;::::1;::::0;;::::1;::::0;;;::::1;::::0;;;13917:18:::1;::::0;18496:62:39;;;13917:18:34::1;::::0;18484:2:39;18469:18;13917::34::1;18350:214:39::0;3136:129:11;3226:12;3136:129;;;;;:::o;8195:94:34:-;902:33:22;915:10;927:7;;-1:-1:-1;;;;;;927:7:22;902:12;:33::i;:::-;894:58;;;;-1:-1:-1;;;894:58:22;;;;;;;:::i;:::-;8244:8:34::1;:15:::0;;-1:-1:-1;;;;8244:15:34::1;-1:-1:-1::0;;;8244:15:34::1;::::0;;8274:8:::1;::::0;::::1;::::0;8244:15;;8274:8:::1;8195:94::o:0;12757:211::-;902:33:22;915:10;927:7;;-1:-1:-1;;;;;;927:7:22;902:12;:33::i;:::-;894:58;;;;-1:-1:-1;;;894:58:22;;;;;;;:::i;:::-;12852:21:34::1;:46:::0;;;::::1;;-1:-1:-1::0;;;12852:46:34::1;-1:-1:-1::0;;;;12852:46:34;;::::1;;::::0;;12913:48:::1;::::0;::::1;::::0;::::1;::::0;12876:22;179:14:39;172:22;154:41;;142:2;127:18;;14:187;8768:426:34;902:33:22;915:10;927:7;;-1:-1:-1;;;;;;927:7:22;902:12;:33::i;:::-;894:58;;;;-1:-1:-1;;;894:58:22;;;;;;;:::i;:::-;2826:5:34::1;8924:32;::::0;::::1;;8920:96;;;8965:51;;-1:-1:-1::0;;;8965:51:34::1;;;;;;;;;;;8920:96;9045:50;::::0;;::::1;::::0;;::::1;::::0;;;::::1;;::::0;;;;::::1;;;::::0;;::::1;::::0;;;::::1;::::0;;::::1;::::0;;;;;;-1:-1:-1;;;;;9026:16:34;::::1;-1:-1:-1::0;9026:16:34;;;:9:::1;:16:::0;;;;;:69;;;;;;;;-1:-1:-1;;9026:69:34;;;;::::1;;-1:-1:-1::0;;9026:69:34;;::::1;::::0;::::1;;::::0;;;::::1;::::0;;;::::1;-1:-1:-1::0;;9026:69:34::1;::::0;;;;::::1;::::0;;;::::1;::::0;;;::::1;::::0;;;9110:77;;8664:41:39;;;8721:18;;;8714:50;;;;8780:18;;;8773:47;;;;9110:77:34::1;::::0;8637:18:39;9110:77:34::1;;;;;;;8768:426:::0;;;;:::o;2956:1113:31:-;3419:21;902:33:22;915:10;927:7;;-1:-1:-1;;;;;;927:7:22;902:12;:33::i;:::-;894:58;;;;-1:-1:-1;;;894:58:22;;;;;;;:::i;:::-;512:6:26::1;;522:1;512:11;504:34;;;;-1:-1:-1::0;;;504:34:26::1;;;;;;;:::i;:::-;558:1;549:10:::0;;3387:12:31;-1:-1:-1;;;;;;;6884:22:34;::::2;::::0;6880:85:::2;;6915:50;;-1:-1:-1::0;;;6915:50:34::2;;;;;;;;;;;6880:85;3496:18:31::3;3517:28;3532:12;3517:14;:28::i;:::-;3496:49;;3559:61;3573:12;3587:13;3602:8;3612:1;3615;3618;3559:13;:61::i;:::-;3650:86;3664:12;3678:13;3693:11;3706:10;3718;3730:5;3650:13;:86::i;:::-;3634:102;;3482:265;3756:92;3776:10;3788:12;3802:13;3817;3832:15;;;;;;;;;-1:-1:-1::0;;;;;3832:15:31::3;-1:-1:-1::0;;;;;3756:92:31::3;:19;:92::i;:::-;-1:-1:-1::0;;;;;3888:32:31;::::3;3884:100;;;3929:55;;-1:-1:-1::0;;;3929:55:31::3;;;;;;;;;;;3884:100;3994:68;4009:13;4025:2;4029:14;;4045:8;4055:6;3994:7;:68::i;:::-;-1:-1:-1::0;591:1:26::1;582:6;:10:::0;2956:1113:31;;-1:-1:-1;;;;;;;;;;;;2956:1113:31:o;13133:198:34:-;902:33:22;915:10;927:7;;-1:-1:-1;;;;;;927:7:22;902:12;:33::i;:::-;894:58;;;;-1:-1:-1;;;894:58:22;;;;;;;:::i;:::-;-1:-1:-1;;;;;13218:28:34;::::1;;::::0;;;:18:::1;:28;::::0;;;;;:56;;-1:-1:-1;;13218:56:34::1;::::0;::::1;::::0;;13289:35;::::1;::::0;13218:28;13289:35:::1;13133:198:::0;:::o;20018:421::-;20191:14;902:33:22;915:10;927:7;;-1:-1:-1;;;;;;927:7:22;902:12;:33::i;:::-;894:58;;;;-1:-1:-1;;;894:58:22;;;;;;;:::i;:::-;512:6:26::1;;522:1;512:11;504:34;;;;-1:-1:-1::0;;;504:34:26::1;;;;;;;:::i;:::-;558:1;549:10:::0;;20221:18:34::2;20242:28;20257:12:::0;20242:14:::2;:28::i;:::-;20221:49;;20290:78;20304:12;20318:13;20333:11;20346:10;20358:2;20362:5;20290:13;:78::i;:::-;20281:87;;20403:12;-1:-1:-1::0;;;;;20383:49:34::2;;20418:13;20383:49;;;;2640:25:39::0;;2628:2;2613:18;;2494:177;20383:49:34::2;;;;;;;;-1:-1:-1::0;591:1:26::1;582:6;:10:::0;20018:421:34;;-1:-1:-1;;;;20018:421:34:o;11418:143::-;902:33:22;915:10;927:7;;-1:-1:-1;;;;;;927:7:22;902:12;:33::i;:::-;894:58;;;;-1:-1:-1;;;894:58:22;;;;;;;:::i;:::-;-1:-1:-1;;;;;11483:24:34;::::1;11519:5;11483:24:::0;;;:18:::1;:24;::::0;;;;;:41;;-1:-1:-1;;11483:41:34::1;::::0;;11539:15;::::1;::::0;11519:5;11539:15:::1;11418:143:::0;:::o;14546:602::-;-1:-1:-1;;;;;14661:24:34;;;;;;:18;:24;;;;;:33;;;;:66;;-1:-1:-1;;;;;;14698:22:34;;;;;;:18;:22;;;;;:29;;;;;;14661:66;:127;;;-1:-1:-1;;;;;;14747:28:34;;;;;;:18;:28;;;;;:41;;;;;;14661:127;:224;;;-1:-1:-1;14809:21:34;;-1:-1:-1;;;14809:21:34;;;;:75;;;;-1:-1:-1;;;;;;14835:28:34;;;;;;:18;:28;;;;;:49;;;;;;14834:50;14809:75;14644:347;;;14917:63;;-1:-1:-1;;;14917:63:34;;-1:-1:-1;;;;;24644:15:39;;;14917:63:34;;;24626:34:39;24696:15;;;24676:18;;;24669:43;24748:15;;24728:18;;;24721:43;24561:18;;14917:63:34;24386:384:39;14644:347:34;-1:-1:-1;;;;;15004:24:34;;;;;;:18;:24;;;;;:40;;;15047:15;-1:-1:-1;15000:142:34;;;15085:46;;-1:-1:-1;;;15085:46:34;;;;;;;;;;;15000:142;14546:602;;;:::o;5195:497:30:-;902:33:22;915:10;927:7;;-1:-1:-1;;;;;;927:7:22;902:12;:33::i;:::-;894:58;;;;-1:-1:-1;;;894:58:22;;;;;;;:::i;:::-;5344:15:30::1;-1:-1:-1::0;;;;;5344:20:30::1;5363:1;5344:20:::0;5340:96:::1;;5387:38;;-1:-1:-1::0;;;5387:38:30::1;;;;;;;;;;;5340:96;5467:19;::::0;::::1;5445;5467::::0;;;:10:::1;:19;::::0;;;;5496:28;;::::1;-1:-1:-1::0;;5534:39:30;;;;-1:-1:-1;;;;;5534:39:30;::::1;;::::0;;;;5583:43:::1;5467:19:::0;-1:-1:-1;;;;;5601:22:30;::::1;4984:8;:43::i;5583:::-;5642;::::0;;21164:10:39;21152:23;;21134:42;;-1:-1:-1;;;;;21212:32:39;;21207:2;21192:18;;21185:60;5642:43:30::1;::::0;21107:18:39;5642:43:30::1;;;;;;;5330:362;5195:497:::0;;;:::o;13513:197:34:-;902:33:22;915:10;927:7;;-1:-1:-1;;;;;;927:7:22;902:12;:33::i;:::-;894:58;;;;-1:-1:-1;;;894:58:22;;;;;;;:::i;:::-;-1:-1:-1;;;;;13597:28:34;::::1;13649:5;13597:28:::0;;;:18:::1;:28;::::0;;;;;:57;;-1:-1:-1;;13597:57:34::1;::::0;;13669:34;::::1;::::0;13649:5;13669:34:::1;13513:197:::0;:::o;2453:323:33:-;2653:27;;;2560:30;2653:27;;;:18;:27;;;;;;;;2631:49;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2560:30;;2631:49;;2697:72;;2631:49;;2697:16;:72::i;10719:308:34:-;902:33:22;915:10;927:7;;-1:-1:-1;;;;;;927:7:22;902:12;:33::i;:::-;894:58;;;;-1:-1:-1;;;894:58:22;;;;;;;:::i;:::-;-1:-1:-1;;;;;10783:24:34;::::1;10819:5;10783:24:::0;;;:18:::1;:24;::::0;;;;;:41;;-1:-1:-1;;10883:45:34;;;10943:15;::::1;::::0;10819:5;10943:15:::1;10973:13;::::0;-1:-1:-1;;;;;10973:13:34;::::1;::::0;::::1;::::0;;;::::1;11001:19;::::0;-1:-1:-1;;;;;11001:19:34;::::1;::::0;::::1;::::0;;;::::1;10719:308:::0;:::o;3251:108:10:-;902:33:22;915:10;927:7;;-1:-1:-1;;;;;;927:7:22;902:12;:33::i;:::-;894:58;;;;-1:-1:-1;;;894:58:22;;;;;;;:::i;:::-;3321:31:10::1;::::0;-1:-1:-1;;;3321:31:10;;-1:-1:-1;;;;;2048:32:39;;;3321:31:10::1;::::0;::::1;2030:51:39::0;3321:8:10::1;:20;::::0;::::1;::::0;2003:18:39;;3321:31:10::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;3251:108:::0;:::o;1569:912:31:-;1941:21;902:33:22;915:10;927:7;;-1:-1:-1;;;;;;927:7:22;902:12;:33::i;:::-;894:58;;;;-1:-1:-1;;;894:58:22;;;;;;;:::i;:::-;512:6:26::1;;522:1;512:11;504:34;;;;-1:-1:-1::0;;;504:34:26::1;;;;;;;:::i;:::-;558:1;549:10:::0;;1909:12:31;-1:-1:-1;;;;;;;6884:22:34;::::2;::::0;6880:85:::2;;6915:50;;-1:-1:-1::0;;;6915:50:34::2;;;;;;;;;;;6880:85;1997:18:31::3;2018:28;2033:12;2018:14;:28::i;:::-;1997:49;;2072:86;2086:12;2100:13;2115:11;2128:10;2140;2152:5;2072:13;:86::i;:::-;2056:102;;2168:92;2188:10;2200:12;2214:13;2229;2244:15;;;;;;;;;-1:-1:-1::0;;;;;2244:15:31::3;-1:-1:-1::0;;;;;2168:92:31::3;:19;:92::i;:::-;-1:-1:-1::0;;;;;2300:32:31;::::3;2296:100;;;2341:55;;-1:-1:-1::0;;;2341:55:31::3;;;;;;;;;;;2296:100;2406:68;2421:13;2437:2;2441:14;;2457:8;2467:6;2406:7;:68::i;:::-;-1:-1:-1::0;;591:1:26::1;582:6;:10:::0;1569:912:31;;-1:-1:-1;;;;;;;;1569:912:31:o;5796:214:30:-;902:33:22;915:10;927:7;;-1:-1:-1;;;;;;927:7:22;902:12;:33::i;:::-;894:58;;;;-1:-1:-1;;;894:58:22;;;;;;;:::i;:::-;5897:19:30::1;::::0;::::1;5875;5897::::0;;;:10:::1;:19;::::0;;;;;;;;5926:31;;-1:-1:-1;;5926:31:30::1;::::0;;5973:30;;22817:42:39;;;5897:19:30;;5973:30:::1;::::0;22790:18:39;5973:30:30::1;22672:193:39::0;4887:357:31;5090:35;;;;;;;;;-1:-1:-1;;;;;5090:35:31;;;;-1:-1:-1;;;;;5090:35:31;;;;;;5033:11;;;5153:20;5090:35;5153:18;:20::i;:::-;5135:38;;5191:46;5203:7;5212:14;;5228:8;5191:11;:46::i;:::-;5184:53;4887:357;-1:-1:-1;;;;;;;;4887:357:31:o;15286:369:34:-;-1:-1:-1;;;;;15358:24:34;;;;;;:18;:24;;;;;:33;;;15354:144;;;15414:73;;-1:-1:-1;;;15414:73:34;;-1:-1:-1;;;;;24644:15:39;;15414:73:34;;;24626:34:39;15472:1:34;24676:18:39;;;24669:43;;;24728:18;;;24721:43;24561:18;;15414:73:34;24386:384:39;15354:144:34;-1:-1:-1;;;;;15511:24:34;;;;;;:18;:24;;;;;:40;;;15554:15;-1:-1:-1;15507:142:34;;;15592:46;;-1:-1:-1;;;15592:46:34;;;;;;;;;;;15507:142;15286:369;:::o;6436:157:30:-;902:33:22;915:10;927:7;;-1:-1:-1;;;;;;927:7:22;902:12;:33::i;:::-;894:58;;;;-1:-1:-1;;;894:58:22;;;;;;;:::i;:::-;6545:41:30::1;6568:17;;6545:41;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;::::0;::::1;;::::0;;::::1;::::0;::::1;::::0;::::1;:::i;:::-;;;;;;;;;;;;;;;;;:22;:41::i;1963:164:22:-:0;902:33;915:10;927:7;;-1:-1:-1;;;;;;927:7:22;902:12;:33::i;:::-;894:58;;;;-1:-1:-1;;;894:58:22;;;;;;;:::i;:::-;2046:5:::1;:16:::0;;-1:-1:-1;;;;;;2046:16:22::1;-1:-1:-1::0;;;;;2046:16:22;::::1;::::0;;::::1;::::0;;2078:42:::1;::::0;2046:16;;2099:10:::1;::::0;2078:42:::1;::::0;2046:5;2078:42:::1;1963:164:::0;:::o;6708:155:30:-;902:33:22;915:10;927:7;;-1:-1:-1;;;;;;927:7:22;902:12;:33::i;:::-;894:58;;;;-1:-1:-1;;;894:58:22;;;;;;;:::i;:::-;6816:40:30::1;6838:17;;6816:40;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;::::0;::::1;;::::0;;::::1;::::0;::::1;::::0;::::1;:::i;:::-;;;;;;;;;;;;;;;;;:21;:40::i;2400:149:11:-:0;2482:4;2529:13;;;;;;2505:5;;2482:4;;2511:13;;2529:6;2511:13;:::i;:::-;2505:20;;;;;;;;;;;;;-1:-1:-1;2505:20:11;;:37;;2400:149;-1:-1:-1;;2400:149:11:o;977:540:22:-;1097:9;;1064:4;;-1:-1:-1;;;;;1097:9:22;1415:27;;;;;:77;;-1:-1:-1;1446:46:22;;-1:-1:-1;;;1446:46:22;;-1:-1:-1;;;;;1446:12:22;;;;;:46;;1459:4;;1473;;1480:11;;1446:46;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;1414:96;;;-1:-1:-1;1505:5:22;;-1:-1:-1;;;;;1497:13:22;;;1505:5;;1497:13;1414:96;1407:103;977:540;-1:-1:-1;;;;977:540:22:o;5427:850:31:-;5671:50;5686:10;5706:1;5710:10;5671:14;:50::i;:::-;5767:69;;-1:-1:-1;;;5767:69:31;;5786:1;5767:69;;;25862:34:39;;;25912:18;;;25905:43;;;25964:18;;;25957:34;5812:10:31;26007:18:39;;;26000:43;-1:-1:-1;;;;;26080:39:39;;26059:19;;;26052:68;5767:5:31;-1:-1:-1;;;;;5767:10:31;;;;25796:19:39;;5767:69:31;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;5906:35:31;;;;;;;;;-1:-1:-1;;;;;5906:35:31;;;;-1:-1:-1;;;;;5906:35:31;;;;;;;-1:-1:-1;5876:27:31;;-1:-1:-1;6109:20:31;5906:35;6109:18;:20::i;:::-;6091:38;;6140:17;6160:55;6173:7;6182:14;;6198:8;6208:6;6160:12;:55::i;:::-;6231:39;;-1:-1:-1;;;;;26294:39:39;;26276:58;;6140:75:31;;-1:-1:-1;;;;;;6231:39:31;;;6140:75;;6231:39;;26264:2:39;26249:18;6231:39:31;;;;;;;5560:717;;;5427:850;;;;;;:::o;22518:294:34:-;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;22619:8:34;;-1:-1:-1;;;22619:8:34;;;;22615:58;;;22636:37;;-1:-1:-1;;;22636:37:34;;;;;;;;;;;22615:58;-1:-1:-1;;;;;;22691:23:34;;;;;;:9;:23;;;;;;;;;22683:31;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;22724:81;;22757:48;;-1:-1:-1;;;22757:48:34;;;;;;;;;;;22724:81;22518:294;;;:::o;4729:1605:27:-;4840:12;5010:4;5004:11;-1:-1:-1;;;5133:17:27;5126:93;-1:-1:-1;;;;;5270:2:27;5266:51;5262:1;5243:17;5239:25;5232:86;5404:6;5399:2;5380:17;5376:26;5369:42;6256:2;6253:1;6249:2;6230:17;6227:1;6220:5;6213;6208:51;5777:16;5770:24;5764:2;5746:16;5743:24;5739:1;5735;5729:8;5726:15;5722:46;5719:76;5519:754;5508:765;;;6301:7;6293:34;;;;-1:-1:-1;;;6293:34:27;;26547:2:39;6293:34:27;;;26529:21:39;26586:2;26566:18;;;26559:30;-1:-1:-1;;;26605:18:39;;;26598:44;26659:18;;6293:34:27;26345:338:39;6293:34:27;4830:1504;4729:1605;;;:::o;21591:863:34:-;21836:10;;21796:14;;-1:-1:-1;;;21836:10:34;;-1:-1:-1;;;;;21836:10:34;21860:18;;;21856:72;;21887:41;;-1:-1:-1;;;21887:41:34;;;;;;;;;;;21856:72;21983:43;;-1:-1:-1;;;21983:43:34;;-1:-1:-1;;;;;2048:32:39;;;21983:43:34;;;2030:51:39;21947:80:34;;21972:9;;21983:10;:29;;;;2003:18:39;;21983:43:34;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;21947:13;;:80;:24;:80::i;:::-;21938:89;;22067:1;22046:5;:18;;;:22;;;:82;;22122:6;22046:82;;;22071:48;22095:5;:18;;;22089:3;:24;;;;:::i;:::-;22071:6;;:48;;22115:3;22071:17;:48::i;:::-;22037:91;;22151:11;22142:6;:20;22138:81;;;22171:48;;-1:-1:-1;;;22171:48:34;;;;;;;;;;;22138:81;-1:-1:-1;;;;;22233:24:34;;;;22229:151;;22308:3;-1:-1:-1;;;;;22277:34:34;22286:5;-1:-1:-1;;;;;22286:17:34;;:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;22277:28;;:6;:28;:::i;:::-;:34;22273:95;;;22320:48;;-1:-1:-1;;;22320:48:34;;;;;;;;;;;22273:95;22389:58;;-1:-1:-1;;;22389:58:34;;-1:-1:-1;;;;;22389:5:34;:11;;;;:58;;22401:4;;22407:12;;22421:13;;22436:2;;22440:6;;22389:58;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;21812:642;21591:863;;;;;;;;:::o;22885:845::-;23171:12;23169:14;;23153:13;;23171:12;23153:13;;23169:14;;-1:-1:-1;;;;;23169:14:34;;:::i;:::-;;;-1:-1:-1;;;;;23169:14:34;;;;;;;;;;;;;;;;;;;;-1:-1:-1;23287:26:34;;23283:319;;23372:40;23390:22;23372:15;:40;:::i;:::-;-1:-1:-1;;;;;23329:24:34;;;;;;;:18;:24;;;;;;;;;:40;;:83;;;;23483:94;;;;;23460:34:39;;;;23530:15;;;23510:18;;;23503:43;23562:18;;;23555:34;;;23605:18;;;23598:34;;;23537:15:34;23648:19:39;;;23641:35;23692:19;;;23685:35;;;23394:19;;23483:94:34;;;-1:-1:-1;;23483:94:34;;;;;;;;;23456:135;;23483:94;23456:135;;;;23426:27;;;;:20;:27;;;;;:165;23283:319;23645:12;-1:-1:-1;;;;;23616:107:34;23631:4;-1:-1:-1;;;;;23616:107:34;23624:5;23616:107;23660:13;23675:6;23683:15;23700:22;23616:107;;;;;;;;10232:25:39;;;10288:2;10273:18;;10266:34;;;;10331:2;10316:18;;10309:34;10374:2;10359:18;;10352:34;10219:3;10204:19;;10001:391;23616:107:34;;;;;;;;23074:656;22885:845;;;;;:::o;2717:196:10:-;2821:11;;;2787:7;2821:11;;;:5;:11;;;;;;;2842:43;;2873:12;;-1:-1:-1;;;2873:12:10;;22847:10:39;22835:23;;2873:12:10;;;22817:42:39;22790:18;;2873:12:10;22672:193:39;7679:576:30;7892:19;7914:10;7892:19;7925:14;;;;:7;:14;:::i;:::-;7914:26;;;;;;;;;;;;;;;;-1:-1:-1;7914:26:30;7892:48;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;7892:48:30;;;;;;;;;-1:-1:-1;7950:93:30;;8028:14;;;;:7;:14;:::i;:::-;7988:55;;-1:-1:-1;;;7988:55:30;;22847:10:39;22835:23;;;7988:55:30;;;22817:42:39;22790:18;;7988:55:30;22672:193:39;7950:93:30;8053:15;8071:31;;;;8082:8;8071:31;:::i;:::-;8053:49;-1:-1:-1;8112:87:30;8144:14;;;;:7;:14;:::i;:::-;-1:-1:-1;;;;;;;;;893:3:32;888:8;;;865:32;;-1:-1:-1;;;;;907:26:32;;-1:-1:-1;;;907:26:32;8160:38:30;8112:31;:87::i;:::-;8209:39;8233:5;8240:7;8209:23;:39::i;:::-;7882:373;;7679:576;;;;;;;:::o;2285:134:10:-;2358:11;;;;;;;:5;:11;;;;;;;;;:19;;;2392:20;;20555:42:39;;;20613:18;;20606:34;;;2392:20:10;;20528:18:39;2392:20:10;20383:263:39;23788:452:34;23938:81;;-1:-1:-1;;;23938:81:34;;23958:10;23938:81;;;28364:34:39;-1:-1:-1;;;;;23978:5:34;28434:15:39;;28414:18;;;28407:43;28466:18;;;28459:34;;;28509:18;;;28502:34;;;28585:4;28573:17;;28552:19;;;28545:46;28607:19;;;28600:35;;;28651:19;;;28644:35;;;23938:19:34;;;;;28298::39;;23938:81:34;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23934:300;;24055:50;;-1:-1:-1;;;24055:50:34;;24078:10;24055:50;;;28902:34:39;-1:-1:-1;;;;;24098:5:34;28972:15:39;;28952:18;;;28945:43;24108:13:34;;24055:22;;;;;;28837:18:39;;24055:50:34;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:66;24051:173;;;24148:61;;-1:-1:-1;;;24148:61:34;;;;;;;;;;;24051:173;23788:452;;;;;;:::o;1564:526:25:-;1680:9;1928:1;-1:-1:-1;;1911:19:25;1908:1;1905:26;1902:1;1898:34;1891:42;1878:11;1874:60;1864:116;;1964:1;1961;1954:12;1864:116;-1:-1:-1;2051:9:25;;2047:27;;1564:526::o;6271:884:33:-;6440:29;;;6541:30;6559:12;6541:15;:30;:::i;:::-;6510:61;;6609:7;6585:20;:31;6581:568;;6656:1;6632:25;;6689:6;6671:24;;6581:568;;;6769:13;6819:7;6786:29;6795:20;6786:6;:29;:::i;:::-;6785:41;;;;:::i;:::-;6769:57;;6883:5;6864:15;:24;;:54;;6895:23;6913:5;6895:15;:23;:::i;:::-;6864:54;;;6891:1;6864:54;6840:78;;7080:21;7070:6;:31;;:68;;7108:30;7117:21;7108:6;:30;:::i;:::-;7070:68;;;7104:1;7070:68;7052:86;;6712:437;6581:568;6500:655;6271:884;;;;;;;:::o;1009:237:32:-;1101:13;;1076:9;;-1:-1:-1;;;;;;1097:78:32;;;1142:33;;-1:-1:-1;;;1142:33:32;;;;;;;;;;;1097:78;1191:13;;1234:4;;;;;-1:-1:-1;;;;;1221:18:32;1208:3;1191:20;;;;1186:25;1221:18;;1009:237::o;10644:969:30:-;10793:11;-1:-1:-1;;;;;10883:27:30;;2466:42:34;10883:27:30;;;;:59;;;10935:7;-1:-1:-1;;;;;10914:28:30;10922:8;-1:-1:-1;;;;;10914:28:30;;;10883:59;10879:127;;;10965:30;;-1:-1:-1;;;10965:30:30;;;;;;;;;;;10879:127;11015:20;11038:36;;;;11049:14;11038:36;:::i;:::-;11105:25;;;11084:18;11105:25;;;:10;:25;;;;;;;;;11084:46;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;11084:46:30;;;;;;;;11105:25;;-1:-1:-1;11084:46:30;11140:112;;11189:52;;-1:-1:-1;;;11189:52:30;;22847:10:39;22835:23;;11189:52:30;;;22817:42:39;22790:18;;11189:52:30;22672:193:39;11140:112:30;11261:14;11289:7;11278:19;;;;;;2640:25:39;;2628:2;2613:18;;2494:177;11278:19:30;;;;;;;;;;;;;11261:36;;11307:20;11330:80;11385:5;:21;;;11408:1;11330:27;936:24:13;;;-1:-1:-1;;;936:24:13;;;31429:51:39;936:24:13;;;;;;;;;31496:11:39;;;;936:24:13;;;;860:107;11330:27:30;:54;:80;:54;:80::i;:::-;11307:103;-1:-1:-1;11420:30:30;11453:62;11460:13;11475:1;11307:103;-1:-1:-1;;;;;11487:27:30;;2466:42:34;11487:27:30;;11453:6;:62::i;:::-;11420:95;-1:-1:-1;;;;;;11532:27:30;;2466:42:34;11532:27:30;:74;;11585:10;:21;;;11532:74;;;11562:20;;11532:74;11526:80;10644:969;-1:-1:-1;;;;;;;;;;10644:969:30:o;3786:774:33:-;3918:9;3913:572;3937:17;:24;3933:1;:28;3913:572;;;3986:20;4009:18;:48;4028:17;4046:1;4028:20;;;;;;;;:::i;:::-;;;;;;;:28;;;4009:48;;;;;;;;;;;;;;;3986:71;;4195:65;4228:17;4246:1;4228:20;;;;;;;;:::i;:::-;;;;;;;:28;;;4258:1;4195:32;:65::i;:::-;4387:17;4405:1;4387:20;;;;;;;;:::i;:::-;;;;;;;:26;;;4376:2;:8;;:37;;;;4443:17;4461:1;4443:20;;;;;;;;:::i;:::-;;;;;;;;;;;:27;;;4431:9;;;;:39;3963:3;;3913:572;;;;4509:44;4535:17;4509:44;;;;;;:::i;4916:770::-;5047:9;5042:570;5066:17;:24;5062:1;:28;5042:570;;;5115:20;5138:17;:47;5156:17;5174:1;5156:20;;;;;;;;:::i;:::-;;;;;;;:28;;;5138:47;;;;;;;;;;;;;;;5115:70;;5323:64;5355:17;5373:1;5355:20;;;;;;;;:::i;:::-;;;;;;;:28;;;5385:1;5323:31;:64::i;:::-;5514:17;5532:1;5514:20;;;;;;;;:::i;:::-;;;;;;;:26;;;5503:2;:8;;:37;;;;5570:17;5588:1;5570:20;;;;;;;;:::i;:::-;;;;;;;;;;;:27;;;5558:9;;;;:39;5092:3;;5042:570;;;;5636:43;5661:17;5636:43;;;;;;:::i;8973:1385:30:-;9126:17;;9182:36;;;;9193:14;9182:36;:::i;:::-;9159:59;;9228:87;9261:13;9276:26;:7;-1:-1:-1;;;;;;;;;893:3:32;888:8;;;865:32;;-1:-1:-1;;;;;907:26:32;;;-1:-1:-1;;;907:26:32;-1:-1:-1;777:163:32;9276:26:30;:38;9228:32;:87::i;:::-;9346:25;;;9325:18;9346:25;;;:10;:25;;;;;;;;;9325:46;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;9325:46:30;;;;;;;;9381:112;;9430:52;;-1:-1:-1;;;9430:52:30;;22847:10:39;22835:23;;9430:52:30;;;22817:42:39;22790:18;;9430:52:30;22672:193:39;9381:112:30;9502:14;9530:7;9519:19;;;;;;2640:25:39;;2628:2;2613:18;;2494:177;9519:19:30;;;;;;;;;;;;;9502:36;;9548:20;9571:80;9626:5;:21;;;9649:1;9571:27;936:24:13;;;-1:-1:-1;;;936:24:13;;;31429:51:39;936:24:13;;;;;;;;;31496:11:39;;;;936:24:13;;;;860:107;9571:80:30;9548:103;-1:-1:-1;9661:23:30;9687:62;9694:13;9709:1;9548:103;-1:-1:-1;;;;;9721:27:30;;2466:42:34;9721:27:30;;9687:6;:62::i;:::-;9661:88;-1:-1:-1;;;;;;;;9763:27:30;;;9759:463;;9810:13;;:22;-1:-1:-1;9806:136:30;;;9905:13;;9859:68;;-1:-1:-1;;;9859:68:30;;30638:10:39;30626:23;;9859:68:30;;;30608:42:39;30666:18;;;30659:34;;;;30709:18;;;30702:34;;;30581:18;;9859:68:30;30407:335:39;9806:136:30;9759:463;;;9983:7;-1:-1:-1;;;;;9962:28:30;9970:8;-1:-1:-1;;;;;9962:28:30;;9958:264;;10027:6;10010:3;:14;;;:23;10006:138;;;10106:14;;;;10060:69;;-1:-1:-1;;;10060:69:30;;30638:10:39;30626:23;;10060:69:30;;;30608:42:39;30666:18;;;30659:34;;;;30709:18;;;30702:34;;;30581:18;;10060:69:30;30407:335:39;9958:264:30;10181:30;;-1:-1:-1;;;10181:30:30;;;;;;;;;;;9958:264;10231:31;10265:51;10273:13;10288:1;10291:7;10300:3;10305:10;10265:7;:51::i;:::-;10339:12;;8973:1385;-1:-1:-1;;;;;;;;;;;;8973:1385:30:o;8652:675:33:-;8878:26;;;8855:20;8878:26;;;:17;:26;;;;;9003:17;;9022:14;;;;9038:8;;;;9048:9;;;;8878:26;;8855:20;;;8986:72;;9003:17;;9022:14;;8986:16;:72::i;:::-;8915:143;;;;9082:15;9072:7;:25;9068:64;;;9106:26;;-1:-1:-1;;;9106:26:33;;;;;;;;;;;9068:64;9247:31;9271:7;9247:21;:31;:::i;:::-;9227:51;;-1:-1:-1;;9305:15:33;9288:14;;;;:32;-1:-1:-1;;8652:675:33:o;6445:328:31:-;-1:-1:-1;;;;;;;;893:3:32;888:8;;;865:32;;;-1:-1:-1;;;;;907:26:32;;;-1:-1:-1;;;907:26:32;;;6637:66:31;;-1:-1:-1;;;6637:66:31;;-1:-1:-1;;6637:5:31;:11;;;;;;:66;;-1:-1:-1;;;;;;907:26:32;6637:66:31;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6761:1;:4;;;-1:-1:-1;;;;;6719:47:31;6735:9;6719:47;6746:1;:13;;;6719:47;;;;2640:25:39;;2628:2;2613:18;;2494:177;6719:47:31;;;;;;;;6523:250;6445:328;;:::o;1658:331:13:-;1822:12;1795:8;356:1;625:20;1795:8;643:1;625:17;:20::i;:::-;:30;;;621:82;;682:20;:8;700:1;682:17;:20::i;:::-;664:39;;-1:-1:-1;;;664:39:13;;31692:6:39;31680:19;;;664:39:13;;;31662:38:39;31635:18;;664:39:13;31518:188:39;621:82:13;1850:19:::1;1872:35;1894:4;1900:6;1872:21;:35::i;:::-;1850:57;;1924:58;1942:8;411:1;1975:6;1924:17;:58::i;:::-;1917:65:::0;1658:331;-1:-1:-1;;;;;;1658:331:13:o;2051:353:12:-;-1:-1:-1;;;;;;;;;;;;;;;;;2258:8:12;-1:-1:-1;;;;;2258:14:12;;2286:86;;;;;;;;2302:7;2286:86;;;;;;2311:25;2328:7;2311:16;:25::i;:::-;2286:86;;;;2338:8;2286:86;;;;2348:8;2286:86;;;;2358:13;2286:86;;;;;2382:4;2258:139;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;2251:146;2051:353;-1:-1:-1;;;;;2051:353:12:o;7567:678:33:-;7794:27;;;7771:20;7794:27;;;:18;:27;;;;;7920:17;;7939:14;;;;7955:8;;;;7965:9;;;;7794:27;;7771:20;;;7903:72;;7920:17;;7939:14;;7903:16;:72::i;:::-;7832:143;;;;7999:15;7989:7;:25;7985:65;;;8023:27;;-1:-1:-1;;;8023:27:33;;;;;;;;;;;3163:741:12;3364:31;;:::i;:::-;3529:20;3552:26;3563:4;:14;;;3552:10;:26::i;:::-;3592:15;;;;3529:49;;-1:-1:-1;3592:19:12;3588:53;;3613:28;3625:4;:15;;;3613:11;:28::i;:::-;3659:8;-1:-1:-1;;;;;3659:85:12;;3752:12;3779:92;;;;;;;;3795:7;3779:92;;;;;;3804:25;3821:7;3804:16;:25::i;:::-;3779:92;;;;3831:8;3779:92;;;;3841:8;3779:92;;;;3869:1;3851:4;:15;;;:19;3779:92;;;;;3873:14;3659:238;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;3652:245;3163:741;-1:-1:-1;;;;;;;3163:741:12:o;12935:305:8:-;13013:6;13056:10;:6;13065:1;13056:10;:::i;:::-;13039:6;:13;:27;;13031:60;;;;-1:-1:-1;;;13031:60:8;;34700:2:39;13031:60:8;;;34682:21:39;34739:2;34719:18;;;34712:30;-1:-1:-1;;;34758:18:39;;;34751:50;34818:18;;13031:60:8;34498:344:39;13031:60:8;-1:-1:-1;13168:29:8;13184:3;13168:29;13162:36;;12935:305::o;2699:191:13:-;2783:12;-1:-1:-1;;;;;2814:11:13;;;:69;;2853:30;;;-1:-1:-1;;;;;;35082:3:39;35078:16;;;35074:25;;2853:30:13;;;35062:38:39;35134:16;;;35130:25;35116:12;;;35109:47;35172:12;2853:30:13;;;;;;;;;;;;2814:69;;;2828:22;;-1:-1:-1;;;;;;35344:3:39;35340:16;;;35336:62;2828:22:13;;;35324:75:39;35415:12;;2828:22:13;;;;;;;;;;;;2814:69;2807:76;2699:191;-1:-1:-1;;;2699:191:13:o;2304:389::-;2470:12;2443:8;356:1;625:20;2443:8;643:1;625:17;:20::i;:::-;:30;;;621:82;;682:20;:8;700:1;682:17;:20::i;621:82::-;2535:8:::1;454:1;2580:25;:7;:14;:23;:25::i;:::-;:29;::::0;2608:1:::1;2580:29;:::i;:::-;2644:11;2669:7;2505:181;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;2498:188;;2304:389:::0;;;;;;:::o;4600:191:12:-;4666:17;4712:10;4699:9;:23;4695:62;;4731:26;;-1:-1:-1;;;4731:26:12;;4747:9;4731:26;;;2640:25:39;2613:18;;4731:26:12;2494:177:39;4695:62:12;-1:-1:-1;4774:10:12;4600:191::o;5168:409::-;5321:15;5339:8;-1:-1:-1;;;;;5339:16:12;;:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;5321:36;-1:-1:-1;;;;;;5371:21:12;;5367:54;;5401:20;;-1:-1:-1;;;5401:20:12;;;;;;;;;;;5367:54;5495:75;-1:-1:-1;;;;;5495:31:12;;5527:10;5547:8;5558:11;5495:31;:75::i;16291:213:21:-;16347:6;16377:16;16369:24;;16365:103;;;16416:41;;-1:-1:-1;;;16416:41:21;;16447:2;16416:41;;;36843:36:39;36895:18;;;36888:34;;;36816:18;;16416:41:21;36662:266:39;1328:1782:27;1466:12;1636:4;1630:11;-1:-1:-1;;;1759:17:27;1752:93;-1:-1:-1;;;;;1896:4:27;1892:53;1888:1;1869:17;1865:25;1858:88;-1:-1:-1;;;;;2038:2:27;2034:51;2029:2;2010:17;2006:26;1999:87;2172:6;2167:2;2148:17;2144:26;2137:42;3026:2;3023:1;3018:3;2999:17;2996:1;2989:5;2982;2977:52;2545:16;2538:24;2532:2;2514:16;2511:24;2507:1;2503;2497:8;2494:15;2490:46;2487:76;2287:756;2276:767;;;3071:7;3063:40;;;;-1:-1:-1;;;3063:40:27;;37135:2:39;3063:40:27;;;37117:21:39;37174:2;37154:18;;;37147:30;-1:-1:-1;;;37193:18:39;;;37186:50;37253:18;;3063:40:27;36933:344:39;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;206:179:39:-;273:20;;-1:-1:-1;;;;;322:38:39;;312:49;;302:77;;375:1;372;365:12;390:131;-1:-1:-1;;;;;465:31:39;;455:42;;445:70;;511:1;508;501:12;526:134;594:20;;623:31;594:20;623:31;:::i;665:347::-;716:8;726:6;780:3;773:4;765:6;761:17;757:27;747:55;;798:1;795;788:12;747:55;-1:-1:-1;821:20:39;;-1:-1:-1;;;;;853:30:39;;850:50;;;896:1;893;886:12;850:50;933:4;925:6;921:17;909:29;;985:3;978:4;969:6;961;957:19;953:30;950:39;947:59;;;1002:1;999;992:12;947:59;665:347;;;;;:::o;1017:841::-;1136:6;1144;1152;1160;1168;1176;1229:3;1217:9;1208:7;1204:23;1200:33;1197:53;;;1246:1;1243;1236:12;1197:53;1269:28;1287:9;1269:28;:::i;:::-;1259:38;;1347:2;1336:9;1332:18;1319:32;1360:31;1385:5;1360:31;:::i;:::-;1410:5;-1:-1:-1;1466:2:39;1451:18;;1438:32;-1:-1:-1;;;;;1482:30:39;;1479:50;;;1525:1;1522;1515:12;1479:50;1564:58;1614:7;1605:6;1594:9;1590:22;1564:58;:::i;:::-;1641:8;;-1:-1:-1;1538:84:39;-1:-1:-1;;1728:2:39;1713:18;;1700:32;1741:33;1700:32;1741:33;:::i;:::-;1793:7;1783:17;;;1847:3;1836:9;1832:19;1819:33;1809:43;;1017:841;;;;;;;;:::o;2092:397::-;2183:6;2191;2199;2252:2;2240:9;2231:7;2227:23;2223:32;2220:52;;;2268:1;2265;2258:12;2220:52;2307:9;2294:23;2326:31;2351:5;2326:31;:::i;:::-;2376:5;2428:2;2413:18;;2400:32;;-1:-1:-1;2479:2:39;2464:18;;;2451:32;;2092:397;-1:-1:-1;;;2092:397:39:o;2676:129::-;-1:-1:-1;;;;;2754:5:39;2750:30;2743:5;2740:41;2730:69;;2795:1;2792;2785:12;2810:245;2868:6;2921:2;2909:9;2900:7;2896:23;2892:32;2889:52;;;2937:1;2934;2927:12;2889:52;2976:9;2963:23;2995:30;3019:5;2995:30;:::i;3060:154::-;3119:5;3164:2;3155:6;3150:3;3146:16;3142:25;3139:45;;;3180:1;3177;3170:12;3139:45;-1:-1:-1;3202:6:39;3060:154;-1:-1:-1;3060:154:39:o;3219:1047::-;3361:6;3369;3377;3385;3393;3401;3409;3462:3;3450:9;3441:7;3437:23;3433:33;3430:53;;;3479:1;3476;3469:12;3430:53;3502;3547:7;3536:9;3502:53;:::i;:::-;3492:63;;3602:2;3591:9;3587:18;3574:32;3564:42;;3657:3;3646:9;3642:19;3629:33;-1:-1:-1;;;;;3722:2:39;3714:6;3711:14;3708:34;;;3738:1;3735;3728:12;3708:34;3777:58;3827:7;3818:6;3807:9;3803:22;3777:58;:::i;:::-;3854:8;;-1:-1:-1;3751:84:39;-1:-1:-1;3939:3:39;3924:19;;3911:33;;-1:-1:-1;3953:31:39;3911:33;3953:31;:::i;:::-;4003:5;;-1:-1:-1;4061:3:39;4046:19;;4033:33;;4078:16;;;4075:36;;;4107:1;4104;4097:12;4075:36;;4146:60;4198:7;4187:8;4176:9;4172:24;4146:60;:::i;:::-;3219:1047;;;;-1:-1:-1;3219:1047:39;;-1:-1:-1;3219:1047:39;;;;4120:86;;-1:-1:-1;;;3219:1047:39:o;4271:163::-;4338:20;;4398:10;4387:22;;4377:33;;4367:61;;4424:1;4421;4414:12;4439:188;4507:20;;-1:-1:-1;;;;;4556:46:39;;4546:57;;4536:85;;4617:1;4614;4607:12;4632:258;4699:6;4707;4760:2;4748:9;4739:7;4735:23;4731:32;4728:52;;;4776:1;4773;4766:12;4728:52;4799:28;4817:9;4799:28;:::i;:::-;4789:38;;4846;4880:2;4869:9;4865:18;4846:38;:::i;:::-;4836:48;;4632:258;;;;;:::o;5199:247::-;5258:6;5311:2;5299:9;5290:7;5286:23;5282:32;5279:52;;;5327:1;5324;5317:12;5279:52;5366:9;5353:23;5385:31;5410:5;5385:31;:::i;5451:319::-;5518:6;5526;5579:2;5567:9;5558:7;5554:23;5550:32;5547:52;;;5595:1;5592;5585:12;5547:52;5618:28;5636:9;5618:28;:::i;:::-;5608:38;;5696:2;5685:9;5681:18;5668:32;5709:31;5734:5;5709:31;:::i;:::-;5759:5;5749:15;;;5451:319;;;;;:::o;5775:252::-;5842:6;5850;5903:2;5891:9;5882:7;5878:23;5874:32;5871:52;;;5919:1;5916;5909:12;5871:52;5942:28;5960:9;5942:28;:::i;:::-;5932:38;6017:2;6002:18;;;;5989:32;;-1:-1:-1;;;5775:252:39:o;6032:118::-;6118:5;6111:13;6104:21;6097:5;6094:32;6084:60;;6140:1;6137;6130:12;6155:665;6243:6;6251;6259;6267;6275;6328:3;6316:9;6307:7;6303:23;6299:33;6296:53;;;6345:1;6342;6335:12;6296:53;6368:28;6386:9;6368:28;:::i;:::-;6358:38;;6446:2;6435:9;6431:18;6418:32;6459:28;6481:5;6459:28;:::i;:::-;6506:5;-1:-1:-1;6563:2:39;6548:18;;6535:32;6576:30;6535:32;6576:30;:::i;:::-;6625:7;-1:-1:-1;6684:2:39;6669:18;;6656:32;6697:33;6656:32;6697:33;:::i;:::-;6749:7;-1:-1:-1;6775:39:39;6809:3;6794:19;;6775:39;:::i;:::-;6765:49;;6155:665;;;;;;;;:::o;6825:156::-;6891:20;;6951:4;6940:16;;6930:27;;6920:55;;6971:1;6968;6961:12;6986:675;7111:6;7119;7127;7135;7143;7151;7159;7212:3;7200:9;7191:7;7187:23;7183:33;7180:53;;;7229:1;7226;7219:12;7180:53;7268:9;7255:23;7287:31;7312:5;7287:31;:::i;:::-;7337:5;-1:-1:-1;7389:2:39;7374:18;;7361:32;;-1:-1:-1;7440:2:39;7425:18;;7412:32;;-1:-1:-1;7491:2:39;7476:18;;7463:32;;-1:-1:-1;7514:37:39;7546:3;7531:19;;7514:37;:::i;:::-;7504:47;;7598:3;7587:9;7583:19;7570:33;7560:43;;7650:3;7639:9;7635:19;7622:33;7612:43;;6986:675;;;;;;;;;;:::o;7666:539::-;7766:6;7774;7782;7790;7843:3;7831:9;7822:7;7818:23;7814:33;7811:53;;;7860:1;7857;7850:12;7811:53;7899:9;7886:23;7918:31;7943:5;7918:31;:::i;:::-;7968:5;-1:-1:-1;8020:2:39;8005:18;;7992:32;;-1:-1:-1;8071:2:39;8056:18;;8043:32;;-1:-1:-1;8127:2:39;8112:18;;8099:32;8140:33;8099:32;8140:33;:::i;:::-;7666:539;;;;-1:-1:-1;7666:539:39;;-1:-1:-1;;7666:539:39:o;8831:184::-;8889:6;8942:2;8930:9;8921:7;8917:23;8913:32;8910:52;;;8958:1;8955;8948:12;8910:52;8981:28;8999:9;8981:28;:::i;9020:732::-;9133:6;9141;9149;9157;9165;9173;9181;9234:3;9222:9;9213:7;9209:23;9205:33;9202:53;;;9251:1;9248;9241:12;9202:53;9287:9;9274:23;9264:33;;9347:2;9336:9;9332:18;9319:32;9360:31;9385:5;9360:31;:::i;:::-;9410:5;-1:-1:-1;9467:2:39;9452:18;;9439:32;9480:33;9439:32;9480:33;:::i;:::-;9020:732;;;;-1:-1:-1;9532:7:39;;9586:2;9571:18;;9558:32;;-1:-1:-1;9637:3:39;9622:19;;9609:33;;9689:3;9674:19;;9661:33;;-1:-1:-1;9741:3:39;9726:19;;;9713:33;;-1:-1:-1;9020:732:39;-1:-1:-1;;9020:732:39:o;11664:297::-;11723:6;11776:2;11764:9;11755:7;11751:23;11747:32;11744:52;;;11792:1;11789;11782:12;11744:52;11831:9;11818:23;-1:-1:-1;;;;;11874:5:39;11870:42;11863:5;11860:53;11850:81;;11927:1;11924;11917:12;12171:241;12227:6;12280:2;12268:9;12259:7;12255:23;12251:32;12248:52;;;12296:1;12293;12286:12;12248:52;12335:9;12322:23;12354:28;12376:5;12354:28;:::i;12625:700::-;12718:6;12726;12734;12742;12795:3;12783:9;12774:7;12770:23;12766:33;12763:53;;;12812:1;12809;12802:12;12763:53;12851:9;12838:23;12870:31;12895:5;12870:31;:::i;:::-;12920:5;-1:-1:-1;12977:2:39;12962:18;;12949:32;12990:30;12949:32;12990:30;:::i;:::-;13039:7;-1:-1:-1;13098:2:39;13083:18;;13070:32;13111:30;13070:32;13111:30;:::i;:::-;13160:7;-1:-1:-1;13219:2:39;13204:18;;13191:32;13267:6;13254:20;;13242:33;;13232:61;;13289:1;13286;13279:12;13330:1261;13516:6;13524;13532;13540;13548;13556;13564;13572;13580;13588;13596:7;13605;13659:3;13647:9;13638:7;13634:23;13630:33;13627:53;;;13676:1;13673;13666:12;13627:53;13689:49;13727:9;13714:23;13689:49;:::i;:::-;13770:9;13757:23;13747:33;;13827:2;13816:9;13812:18;13799:32;13789:42;;13878:2;13867:9;13863:18;13850:32;13840:42;;13929:2;13918:9;13914:18;13901:32;13891:42;;13952:37;13984:3;13973:9;13969:19;13952:37;:::i;:::-;13942:47;;14036:3;14025:9;14021:19;14008:33;13998:43;;14088:3;14077:9;14073:19;14060:33;14050:43;;14102:59;14155:3;14144:9;14140:19;14127:33;14102:59;:::i;:::-;14208:3;14197:9;14193:19;14180:33;14170:43;;-1:-1:-1;;;;;14256:3:39;14245:9;14241:19;14228:33;14225:57;14222:77;;;14295:1;14292;14285:12;14222:77;14334:85;14411:7;14403:3;14392:9;14388:19;14375:33;14364:9;14360:49;14334:85;:::i;:::-;14438:8;;-1:-1:-1;14465:8:39;-1:-1:-1;14493:39:39;14527:3;14512:19;;14493:39;:::i;:::-;14482:50;;14580:3;14569:9;14565:19;14552:33;14541:44;;13330:1261;;;;;;;;;;;;;;:::o;14596:180::-;14655:6;14708:2;14696:9;14687:7;14683:23;14679:32;14676:52;;;14724:1;14721;14714:12;14676:52;-1:-1:-1;14747:23:39;;14596:180;-1:-1:-1;14596:180:39:o;14963:529::-;15040:6;15048;15056;15109:2;15097:9;15088:7;15084:23;15080:32;15077:52;;;15125:1;15122;15115:12;15077:52;15164:9;15151:23;15183:31;15208:5;15183:31;:::i;:::-;15233:5;-1:-1:-1;15290:2:39;15275:18;;15262:32;15303:33;15262:32;15303:33;:::i;:::-;15355:7;-1:-1:-1;15414:2:39;15399:18;;15386:32;15427:33;15386:32;15427:33;:::i;:::-;15479:7;15469:17;;;14963:529;;;;;:::o;15497:393::-;15573:6;15581;15589;15642:2;15630:9;15621:7;15617:23;15613:32;15610:52;;;15658:1;15655;15648:12;15610:52;15681:28;15699:9;15681:28;:::i;:::-;15671:38;;15759:2;15748:9;15744:18;15731:32;15772:31;15797:5;15772:31;:::i;:::-;15822:5;-1:-1:-1;15846:38:39;15880:2;15865:18;;15846:38;:::i;:::-;15836:48;;15497:393;;;;;:::o;16121:1062::-;16273:6;16281;16289;16297;16305;16313;16321;16329;16382:3;16370:9;16361:7;16357:23;16353:33;16350:53;;;16399:1;16396;16389:12;16350:53;16438:9;16425:23;16457:31;16482:5;16457:31;:::i;:::-;16507:5;-1:-1:-1;16559:2:39;16544:18;;16531:32;;-1:-1:-1;16610:2:39;16595:18;;16582:32;;-1:-1:-1;16666:2:39;16651:18;;16638:32;16679:33;16638:32;16679:33;:::i;:::-;16731:7;-1:-1:-1;16789:3:39;16774:19;;16761:33;-1:-1:-1;;;;;16806:30:39;;16803:50;;;16849:1;16846;16839:12;16803:50;16888:58;16938:7;16929:6;16918:9;16914:22;16888:58;:::i;:::-;16965:8;;-1:-1:-1;16862:84:39;-1:-1:-1;;17052:3:39;17037:19;;17024:33;17066;17024;17066;:::i;:::-;17118:7;17108:17;;;17172:3;17161:9;17157:19;17144:33;17134:43;;16121:1062;;;;;;;;;;;:::o;17573:772::-;17683:6;17691;17699;17707;17715;17768:3;17756:9;17747:7;17743:23;17739:33;17736:53;;;17785:1;17782;17775:12;17736:53;17808:28;17826:9;17808:28;:::i;:::-;17798:38;;17886:2;17875:9;17871:18;17858:32;17899:31;17924:5;17899:31;:::i;:::-;17949:5;-1:-1:-1;18005:2:39;17990:18;;17977:32;-1:-1:-1;;;;;18021:30:39;;18018:50;;;18064:1;18061;18054:12;18018:50;18103:58;18153:7;18144:6;18133:9;18129:22;18103:58;:::i;:::-;18180:8;;-1:-1:-1;18077:84:39;-1:-1:-1;;18267:2:39;18252:18;;18239:32;18280:33;18239:32;18280:33;:::i;:::-;18332:7;18322:17;;;17573:772;;;;;;;;:::o;18569:653::-;18690:6;18698;18751:2;18739:9;18730:7;18726:23;18722:32;18719:52;;;18767:1;18764;18757:12;18719:52;18807:9;18794:23;-1:-1:-1;;;;;18877:2:39;18869:6;18866:14;18863:34;;;18893:1;18890;18883:12;18863:34;18931:6;18920:9;18916:22;18906:32;;18976:7;18969:4;18965:2;18961:13;18957:27;18947:55;;18998:1;18995;18988:12;18947:55;19038:2;19025:16;19064:2;19056:6;19053:14;19050:34;;;19080:1;19077;19070:12;19050:34;19136:7;19131:2;19123:4;19115:6;19111:17;19107:2;19103:26;19099:35;19096:48;19093:68;;;19157:1;19154;19147:12;19093:68;19188:2;19180:11;;;;;19210:6;;-1:-1:-1;18569:653:39;;-1:-1:-1;;;;18569:653:39:o;19463:235::-;19547:6;19600:2;19588:9;19579:7;19575:23;19571:32;19568:52;;;19616:1;19613;19606:12;19568:52;19639:53;19684:7;19673:9;19639:53;:::i;19703:336::-;19905:2;19887:21;;;19944:2;19924:18;;;19917:30;-1:-1:-1;;;19978:2:39;19963:18;;19956:42;20030:2;20015:18;;19703:336::o;20044:334::-;20246:2;20228:21;;;20285:2;20265:18;;;20258:30;-1:-1:-1;;;20319:2:39;20304:18;;20297:40;20369:2;20354:18;;20044:334::o;21936:184::-;22006:6;22059:2;22047:9;22038:7;22034:23;22030:32;22027:52;;;22075:1;22072;22065:12;22027:52;-1:-1:-1;22098:16:39;;21936:184;-1:-1:-1;21936:184:39:o;22125:542::-;-1:-1:-1;;;;;22454:15:39;;;22436:34;;22506:15;;;22501:2;22486:18;;22479:43;22553:2;22538:18;;22531:34;;;;22601:15;;;22596:2;22581:18;;22574:43;22648:3;22633:19;;22626:35;;;;22385:3;22370:19;;22125:542::o;22870:127::-;22931:10;22926:3;22922:20;22919:1;22912:31;22962:4;22959:1;22952:15;22986:4;22983:1;22976:15;23002:128;23069:9;;;23090:11;;;23087:37;;;23104:18;;:::i;23731:400::-;-1:-1:-1;;;;;23987:15:39;;;23969:34;;24039:15;;;;24034:2;24019:18;;24012:43;-1:-1:-1;;;;;;24091:33:39;;;24086:2;24071:18;;24064:61;23919:2;23904:18;;23731:400::o;24136:245::-;24203:6;24256:2;24244:9;24235:7;24231:23;24227:32;24224:52;;;24272:1;24269;24262:12;24224:52;24304:9;24298:16;24323:28;24345:5;24323:28;:::i;24775:343::-;24842:2;24836:9;24884:2;24872:15;;-1:-1:-1;;;;;24902:34:39;;24938:22;;;24899:62;24896:185;;;25003:10;24998:3;24994:20;24991:1;24984:31;25038:4;25035:1;25028:15;25066:4;25063:1;25056:15;24896:185;25097:2;25090:22;24775:343;:::o;25123:416::-;25215:6;25268:2;25256:9;25247:7;25243:23;25239:32;25236:52;;;25284:1;25281;25274:12;25236:52;25310:17;;:::i;:::-;25350:28;25368:9;25350:28;:::i;:::-;25343:5;25336:43;25439:2;25428:9;25424:18;25411:32;25406:2;25399:5;25395:14;25388:56;25504:2;25493:9;25489:18;25476:32;25471:2;25464:5;25460:14;25453:56;25528:5;25518:15;;;25123:416;;;;:::o;26688:171::-;26756:6;26795:10;;;26783;;;26779:27;;26818:12;;;26815:38;;;26833:18;;:::i;:::-;26815:38;26688:171;;;;:::o;26864:125::-;26929:9;;;26950:10;;;26947:36;;;26963:18;;:::i;26994:209::-;27032:3;-1:-1:-1;;;;;27113:2:39;27106:5;27102:14;27140:2;27131:7;27128:15;27125:41;;27146:18;;:::i;:::-;27195:1;27182:15;;26994:209;-1:-1:-1;;;26994:209:39:o;28999:168::-;29072:9;;;29103;;29120:15;;;29114:22;;29100:37;29090:71;;29141:18;;:::i;29172:217::-;29212:1;29238;29228:132;;29282:10;29277:3;29273:20;29270:1;29263:31;29317:4;29314:1;29307:15;29345:4;29342:1;29335:15;29228:132;-1:-1:-1;29374:9:39;;29172:217::o;29394:127::-;29455:10;29450:3;29446:20;29443:1;29436:31;29486:4;29483:1;29476:15;29510:4;29507:1;29500:15;29526:876;29763:2;29815:21;;;29885:13;;29788:18;;;29907:22;;;29734:4;;29763:2;29948;;29966:18;;;;30007:15;;;29734:4;30050:326;30064:6;30061:1;30058:13;30050:326;;;30123:13;;30165:9;;30176:10;30161:26;30149:39;;30228:11;;;30222:18;30208:12;;;30201:40;30281:11;;30275:18;30261:12;;;30254:40;30323:4;30314:14;;;;30351:15;;;;30086:1;30079:9;30050:326;;;-1:-1:-1;30393:3:39;;29526:876;-1:-1:-1;;;;;;;29526:876:39:o;31711:250::-;31796:1;31806:113;31820:6;31817:1;31814:13;31806:113;;;31896:11;;;31890:18;31877:11;;;31870:39;31842:2;31835:10;31806:113;;;-1:-1:-1;;31953:1:39;31935:16;;31928:27;31711:250::o;31966:270::-;32007:3;32045:5;32039:12;32072:6;32067:3;32060:19;32088:76;32157:6;32150:4;32145:3;32141:14;32134:4;32127:5;32123:16;32088:76;:::i;:::-;32218:2;32197:15;-1:-1:-1;;32193:29:39;32184:39;;;;32225:4;32180:50;;31966:270;-1:-1:-1;;31966:270:39:o;32241:885::-;32460:2;32449:9;32442:21;32518:10;32509:6;32503:13;32499:30;32494:2;32483:9;32479:18;32472:58;32584:4;32576:6;32572:17;32566:24;32561:2;32550:9;32546:18;32539:52;32423:4;32638:2;32630:6;32626:15;32620:22;32679:4;32673:3;32662:9;32658:19;32651:33;32707:51;32753:3;32742:9;32738:19;32724:12;32707:51;:::i;:::-;32693:65;;32807:2;32799:6;32795:15;32789:22;32881:2;32877:7;32865:9;32857:6;32853:22;32849:36;32842:4;32831:9;32827:20;32820:66;32909:40;32942:6;32926:14;32909:40;:::i;:::-;33018:3;33006:16;;;;33000:23;32993:31;32986:39;32980:3;32965:19;;32958:68;-1:-1:-1;;;;;;;;33087:32:39;;;;33080:4;33065:20;;;33058:62;32895:54;32241:885::o;33131:575::-;33201:5;33249:4;33237:9;33232:3;33228:19;33224:30;33221:50;;;33267:1;33264;33257:12;33221:50;33300:4;33294:11;33344:4;33336:6;33332:17;33415:6;33403:10;33400:22;-1:-1:-1;;;;;33367:10:39;33364:34;33361:62;33358:185;;;33465:10;33460:3;33456:20;33453:1;33446:31;33500:4;33497:1;33490:15;33528:4;33525:1;33518:15;33358:185;33559:4;33552:24;33624:16;;33609:32;;33695:2;33680:18;;;33674:25;33657:15;;;33650:50;;;;-1:-1:-1;33594:6:39;33131:575;-1:-1:-1;33131:575:39:o;33711:258::-;33810:6;33863:2;33851:9;33842:7;33838:23;33834:32;33831:52;;;33879:1;33876;33869:12;33831:52;33902:61;33955:7;33944:9;33902:61;:::i;33974:519::-;34077:6;34130:3;34118:9;34109:7;34105:23;34101:33;34098:53;;;34147:1;34144;34137:12;34098:53;34173:17;;:::i;:::-;34219:9;34213:16;34206:5;34199:31;34275:2;34264:9;34260:18;34254:25;34288:32;34312:7;34288:32;:::i;:::-;34347:2;34336:14;;34329:31;34392:70;34454:7;34449:2;34434:18;;34392:70;:::i;:::-;34387:2;34376:14;;34369:94;34380:5;33974:519;-1:-1:-1;;;33974:519:39:o;35438:168::-;35505:6;35531:10;;;35543;;;35527:27;;35566:11;;;35563:37;;;35580:18;;:::i;35611:790::-;35860:3;35898:6;35892:13;35914:66;35973:6;35968:3;35961:4;35953:6;35949:17;35914:66;:::i;:::-;-1:-1:-1;;;;;;36041:3:39;36077:16;;;36073:25;;36002:16;;;36059:40;;;-1:-1:-1;;;;;;36156:3:39;36134:16;;;36130:38;36126:1;36115:13;;36108:61;36204:16;;;36200:25;36196:1;36185:13;;36178:48;36251:13;;36273:78;36251:13;36338:1;36327:13;;36320:4;36308:17;;36273:78;:::i;:::-;36371:20;36393:1;36367:28;;35611:790;-1:-1:-1;;;;;;;35611:790:39:o;36406:251::-;36476:6;36529:2;36517:9;36508:7;36504:23;36500:32;36497:52;;;36545:1;36542;36535:12;36497:52;36577:9;36571:16;36596:31;36621:5;36596:31;:::i
Swarm Source
ipfs://24354ee82ccbadd74af752050ba0f64dbc9084de8a475de8255e5616f2249c7e
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.