More Info
Private Name Tags
ContractCreator
Latest 6 from a total of 6 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Execute Order | 59554752 | 138 days ago | IN | 0 POL | 0.02683768 | ||||
Execute Order | 59554732 | 138 days ago | IN | 0 POL | 0.03462552 | ||||
Execute Order | 59554722 | 138 days ago | IN | 0 POL | 0.03209083 | ||||
Execute Order | 57220864 | 197 days ago | IN | 0 POL | 0.03653797 | ||||
Execute Order | 57220837 | 197 days ago | IN | 0 POL | 0.027015 | ||||
Execute Order | 57189365 | 198 days ago | IN | 0 POL | 0.02031013 |
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
OrderBook
Compiler Version
v0.8.23+commit.f704f362
Optimization Enabled:
Yes with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.23; import {IPriceOracle} from "./price-oracles/interfaces/IPriceOracle.sol"; import {IOrderBook} from "./interfaces/IOrderBook.sol"; import {IPhutureOnDonationCallback} from "./interfaces/IPhutureOnDonationCallback.sol"; import {IVault} from "./interfaces/IVault.sol"; import {Currency, CurrencyLib} from "./libraries/CurrencyLib.sol"; import {FixedPointMathLib} from "solmate/utils/FixedPointMathLib.sol"; import {OrderLib} from "./libraries/OrderLib.sol"; import {PriceLib} from "./price-oracles/libraries/PriceLib.sol"; import {SafeCastLib} from "solmate/utils/SafeCastLib.sol"; import {Owned} from "solmate/auth/Owned.sol"; /// @title OrderBook /// @notice This contract is responsible for setting up the execution of orders for the Index contract OrderBook is IOrderBook, IPhutureOnDonationCallback, Owned { using CurrencyLib for Currency; using FixedPointMathLib for *; using OrderLib for *; using PriceLib for *; using SafeCastLib for uint256; uint16 internal constant MAX_BPS = 10_000; /// @dev The address of the Vault contract address public immutable vault; /// @dev Addresses of fund managers allowed to execute trades mapping(address => bool) public isFundManager; /// @dev orderId => Set of orders OrderLib.OrderRegistry internal _orders; /// @dev The address of the Vault contract mapping(bytes32 => uint256) internal _balancesOf; /// @dev Number of orders to be received from the remote chains int256 internal incomingOrders; /// @notice The address of the Messenger contract address public messenger; /// @dev notice The address of the price oracle contract address public priceOracle; /// @dev The maximum slippage allowed in basis points uint16 public maxSlippageInBP; /// @notice Thrown when an unauthorized caller attempts to access a function error Forbidden(); /// @notice Thrown when the amount exceeds the order size error AmountExceedsOrderSize(); /// @notice Thrown when the donation fails error DonateFailure(); /// @notice Thrown when the consume amount does not match the sold amount error ConsumeAmountMismatch(); /// @notice Thrown when the orders are not sorted error Sorting(); /// @notice Thrown when the sender is not authorized /// @dev Only fund managers are allowed to execute trades error BadSender(); /// @notice Thrown when the slippage is too high error HighLoss(); /// @notice Thrown when the order is not empty error NotEmpty(); /// @notice Thrown when the index is used more than once error UsedIndex(); /// @notice Thrown when the length of arrays do not match error LengthMismatch(); /// @notice Thrown when the number of orders does not match the expected count error OrdersLength(); /// @dev Modifier to restrict access to a specific address /// @param addr The address allowed to access the function modifier only(address addr) { if (msg.sender != addr) revert Forbidden(); _; } constructor(address _owner, address _vault, address _messenger, address _priceOracle, uint16 _maxSlippageInBP) Owned(_owner) { messenger = _messenger; vault = _vault; priceOracle = _priceOracle; maxSlippageInBP = _maxSlippageInBP; } receive() external payable {} /// @notice Updates the fund manager status for the given address /// /// @param fundManager The address of the fund manager /// @param isAllowed The status of the fund manager (true for allowed, false for disallowed) function updateFundManager(address fundManager, bool isAllowed) external onlyOwner { isFundManager[fundManager] = isAllowed; } /// @notice Sets the address of the messenger contract /// /// @param _messenger The address of the messenger contract function setMessenger(address _messenger) external onlyOwner { messenger = _messenger; } /// @notice Sets the address of the price oracle contract /// /// @param _priceOracle The address of the price oracle contract function setPriceOracle(address _priceOracle) external onlyOwner { priceOracle = _priceOracle; } /// @notice Sets the maximum slippage allowed in basis points /// /// @param _maxSlippageInBP The maximum slippage allowed in basis points function setMaxSlippageInBP(uint16 _maxSlippageInBP) external onlyOwner { maxSlippageInBP = _maxSlippageInBP; } /// @notice Sets the orders and the number of incoming orders /// /// @param _incomingOrders The number of incoming orders /// @param orders The orders to be set function setOrders(uint256 _incomingOrders, OrderLib.Order[] calldata orders) external only(messenger) { _orders.set(orders); incomingOrders += int256(_incomingOrders); } /// @notice Receives the incoming orders from the remote chains /// /// @param orders The incoming orders /// @param currency The common sell currency for the orders /// @param amount The total amount of the sell currency received function receiveIncomingOrders(OrderLib.Order[] calldata orders, Currency currency, uint256 amount) external only(messenger) { _orders.set(orders); incomingOrders -= int256(orders.length); IVault(vault).donate(currency, abi.encodeCall(this.donate, (currency, amount))); } /// @notice Removes the dust orders /// /// @param _incomingOrders The number of incoming orders to be removed function removeDustOrders(uint256 _incomingOrders) external only(messenger) { incomingOrders -= int256(_incomingOrders); } /// @notice Executes an order /// @param params The parameters for executing the order function executeOrder(ExecuteOrderParams calldata params) external { if (!isFundManager[msg.sender]) revert BadSender(); if (_orders.get(params.orderId) < params.sell) revert AmountExceedsOrderSize(); bool isOutgoing = params.orderId.finalDestinationChainId != block.chainid; address recipient = isOutgoing ? messenger : vault; uint256 sellBalanceBefore = params.orderId.sellCurrency.balanceOf(vault); uint256 buyBalanceBefore = params.orderId.localBuyCurrency.balanceOf(recipient); if (isOutgoing) { IVault(vault).consume( params.orderId.sellCurrency, params.sell, params.tradeParams.target, params.tradeParams.data ); } else { IVault(vault).donate( params.orderId.localBuyCurrency, abi.encodeCall(this.consume, (params.orderId.sellCurrency, params.sell, params.tradeParams)) ); } uint256 sold = sellBalanceBefore - params.orderId.sellCurrency.balanceOf(vault); if (sold != params.sell) revert ConsumeAmountMismatch(); uint256 bought = params.orderId.localBuyCurrency.balanceOf(recipient) - buyBalanceBefore; // stores `bought` amounts to create `pendingOrders` in `finishOrderExecution` if (isOutgoing) _balancesOf[params.orderId.id()] += bought; (uint256 sellCurrencyPrice, uint256 buyCurrencyPrice) = IPriceOracle(priceOracle).prices( params.orderId.sellCurrency, params.orderId.localBuyCurrency, params.payload ); if ( sold.convertToBaseDown(sellCurrencyPrice).mulDivDown(MAX_BPS - maxSlippageInBP, MAX_BPS) > bought.convertToBaseDown(buyCurrencyPrice) ) revert HighLoss(); _orders.fill(params.orderId, sold.safeCastTo96()); emit OrderFilled(params.orderId.id(), params.sell, bought); } /// @notice Finishes the order execution and returns the pending orders /// /// @dev `orderId` should be sorted by `finalDestinationChainId` /// /// @param params The parameters for finishing the order execution /// /// @return pendingOrders The pending orders to be processed function finishOrderExecution(FinishOrderExecutionParams calldata params) external only(messenger) returns (PendingOrder[] memory pendingOrders) { if (incomingOrders != 0) revert NotEmpty(); if (params.idIndices.length != params.orderIds.length) revert LengthMismatch(); _orders.reset(params.orderIds); pendingOrders = new PendingOrder[](params.pendingOrderCounts.length); uint256 orderIndex; uint256 chainIndex; uint256 lastRemoteChainId = type(uint256).max; bool[] memory used = new bool[](params.orderIds.length); for (uint256 i; i < params.orderIds.length; ++i) { if (used[params.idIndices[i]]) revert UsedIndex(); used[params.idIndices[i]] = true; OrderLib.OrderId calldata orderId = params.orderIds[params.idIndices[i]]; if (orderId.finalDestinationChainId != block.chainid) { if (orderId.finalDestinationChainId != lastRemoteChainId) { if (lastRemoteChainId != type(uint256).max) { if (orderId.finalDestinationChainId < lastRemoteChainId) revert Sorting(); if (pendingOrders[chainIndex].orders.length != orderIndex) revert OrdersLength(); orderIndex = 0; unchecked { ++chainIndex; } } lastRemoteChainId = orderId.finalDestinationChainId; pendingOrders[chainIndex].orders = new BoughtOrder[](params.pendingOrderCounts[chainIndex]); pendingOrders[chainIndex].chainId = orderId.finalDestinationChainId; pendingOrders[chainIndex].currency = orderId.localBuyCurrency; } bytes32 idKey = orderId.id(); uint256 bought = _balancesOf[idKey]; pendingOrders[chainIndex].totalBought += bought; pendingOrders[chainIndex].orders[orderIndex] = BoughtOrder(bought, orderId.finalDestinationBuyCurrency); delete _balancesOf[idKey]; unchecked { ++orderIndex; } } } if (pendingOrders.length != 0) { if (params.pendingOrderCounts.length > chainIndex + 1) revert LengthMismatch(); if (pendingOrders[chainIndex].orders.length != orderIndex) revert OrdersLength(); } } /// @dev Callback function for handling donations to Vault /// /// @param data The data passed from the Phuture callback function phutureOnDonationCallbackV1(bytes memory data) external override only(vault) { (bool success, bytes memory returnData) = address(this).call(data); if (success) return; if (returnData.length == 0) revert DonateFailure(); // if the call failed, bubble up the reason /// @solidity memory-safe-assembly assembly { revert(add(returnData, 32), mload(returnData)) } } /// @notice Donates the specified amount of currency to the Vault /// /// @param currency The currency to be donated /// @param amount The amount of currency to be donated function donate(Currency currency, uint256 amount) external only(address(this)) { currency.transfer(vault, amount); } /// @notice Consumes the specified amount of currency from the Vault /// /// @param currency The currency to be consumed /// @param amount The amount of currency to be consumed /// @param params The trade parameters for consuming the currency function consume(Currency currency, uint96 amount, TradeParams memory params) external only(address(this)) { IVault(vault).consume(currency, amount, params.target, params.data); } /// @notice Returns the order of the given orderId /// /// @param orderId The orderId to be checked /// /// @return The order amount function orderOf(OrderLib.OrderId calldata orderId) external view returns (uint96) { return _orders.get(orderId); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.23; import {Currency} from "../../libraries/CurrencyLib.sol"; /// @title PriceOracle interface /// @notice Returns prices of Index's constituents interface IPriceOracle { function prices(Currency currency0, Currency currency1, bytes calldata) external view returns (uint256, uint256); }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.23; import {Currency} from "../libraries/CurrencyLib.sol"; import {OrderLib} from "../libraries/OrderLib.sol"; /// @title IOrderBook interface interface IOrderBook { struct TradeParams { address target; bytes data; } struct BoughtOrder { // Bought amount of local buy currency, sell amount on the remote uint256 amount; // Buy currency on the remote Currency buyCurrency; } struct PendingOrder { uint256 chainId; Currency currency; uint256 totalBought; BoughtOrder[] orders; } struct FinishOrderExecutionParams { OrderLib.OrderId[] orderIds; uint256[] idIndices; uint256[] pendingOrderCounts; } struct ExecuteOrderParams { OrderLib.OrderId orderId; uint96 sell; TradeParams tradeParams; bytes payload; } event OrderFilled(bytes32 indexed id, uint256 sold, uint256 bought); function receiveIncomingOrders(OrderLib.Order[] calldata orders, Currency currency, uint256 amount) external; function removeDustOrders(uint256 _incomingOrders) external; function setOrders(uint256 _incomingOrders, OrderLib.Order[] calldata orders) external; /// @notice Execute the given local order /// @param params Execute order data function executeOrder(ExecuteOrderParams calldata params) external; function finishOrderExecution(FinishOrderExecutionParams calldata params) external returns (PendingOrder[] memory pendingOrders); function updateFundManager(address fundManager, bool isAllowed) external; function setMessenger(address messenger) external; function setPriceOracle(address priceOracle) external; function setMaxSlippageInBP(uint16 maxSlippageInBP) external; function orderOf(OrderLib.OrderId calldata orderIdParams) external view returns (uint96 amount); }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.23; interface IPhutureOnDonationCallback { function phutureOnDonationCallbackV1(bytes calldata data) external; }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.23; import {Currency} from "../libraries/CurrencyLib.sol"; import {a160u96} from "../utils/a160u96.sol"; interface IVault { struct CurrencyWithdrawal { uint256[] currencyIndexSet; uint96[] amounts; } struct SnapshotAnatomy { a160u96[] currencies; uint256[] currencyIndexSet; } struct EndRebalancingParams { a160u96[] anatomyCurrencies; SnapshotAnatomy newAnatomy; CurrencyWithdrawal withdrawals; uint256 lastKBalance; Currency[] currencies; } struct RebalancingResult { uint256 chainId; uint256 snapshot; uint256[] currencyIdSet; a160u96[] currencies; } struct RegisterCurrenciesResult { Currency[] currencies; bytes32 currenciesHash; } function setOrderBook(address _orderBook) external; function setMessenger(address _messenger) external; function startRebalancingPhase(CurrencyWithdrawal calldata withdrawals) external; function finishRebalancingPhase(EndRebalancingParams calldata params) external returns (bytes32); function transferLatestSnapshot(address recipient, uint256 kAmountWads) external returns (uint256); function withdraw(uint256 snapshot, uint256 kAmount, address recipient) external; function registerCurrencies(Currency[] calldata currencies) external returns (RegisterCurrenciesResult memory); function donate(Currency currency, bytes memory data) external; function consume(Currency currency, uint96 amount, address target, bytes calldata data) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.23; import {IERC20, SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; type Currency is address; using {eq as ==, neq as !=} for Currency global; function eq(Currency currency, Currency other) pure returns (bool) { return Currency.unwrap(currency) == Currency.unwrap(other); } function neq(Currency currency, Currency other) pure returns (bool) { return !eq(currency, other); } /// @title CurrencyLibrary /// @dev This library allows for transferring and holding native tokens and ERC20 tokens /// @author Modified from Uniswap (https://github.com/Uniswap/v4-core/blob/main/src/types/Currency.sol) library CurrencyLib { using SafeERC20 for IERC20; using CurrencyLib for Currency; /// @dev Currency wrapper for native currency Currency public constant NATIVE = Currency.wrap(address(0)); /// @notice Thrown when a native transfer fails error NativeTransferFailed(); /// @notice Thrown when an ERC20 transfer fails error ERC20TransferFailed(); /// @notice Thrown when deposit amount exceeds current balance error AmountExceedsBalance(); /// @notice Transfers currency /// /// @param currency Currency to transfer /// @param to Address of recipient /// @param amount Currency amount ot transfer function transfer(Currency currency, address to, uint256 amount) internal { if (amount == 0) return; // implementation from // https://github.com/transmissions11/solmate/blob/e8f96f25d48fe702117ce76c79228ca4f20206cb/src/utils/SafeTransferLib.sol bool success; if (currency.isNative()) { assembly { // Transfer the ETH and store if it succeeded or not. success := call(gas(), to, amount, 0, 0, 0, 0) } if (!success) revert NativeTransferFailed(); } else { assembly { // We'll write our calldata to this slot below, but restore it later. 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 that's the total length of our calldata (4 + 32 * 2) // Counterintuitively, this call() must be positioned after the or() in the // surrounding and() because and() evaluates its arguments from right to left. call(gas(), currency, 0, freeMemoryPointer, 68, 0, 32) ) } if (!success) revert ERC20TransferFailed(); } } /// @notice Approves currency /// /// @param currency Currency to approve /// @param spender Address of spender /// @param amount Currency amount to approve function approve(Currency currency, address spender, uint256 amount) internal { if (isNative(currency)) return; IERC20(Currency.unwrap(currency)).forceApprove(spender, amount); } /// @notice Returns the balance of a given currency for a specific account /// /// @param currency The currency to check /// @param account The address of the account /// /// @return The balance of the specified currency for the given account function balanceOf(Currency currency, address account) internal view returns (uint256) { return currency.isNative() ? account.balance : IERC20(Currency.unwrap(currency)).balanceOf(account); } /// @notice Returns the balance of a given currency for this contract /// /// @param currency The currency to check /// /// @return The balance of the specified currency for this contract function balanceOfSelf(Currency currency) internal view returns (uint256) { return currency.isNative() ? address(this).balance : IERC20(Currency.unwrap(currency)).balanceOf(address(this)); } /// @notice Checks if the specified currency is the native currency /// /// @param currency The currency to check /// /// @return `true` if the specified currency is the native currency, `false` otherwise function isNative(Currency currency) internal pure returns (bool) { return currency == NATIVE; } }
// 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: BUSL-1.1 pragma solidity ^0.8.23; import {Currency} from "./CurrencyLib.sol"; /// @title OrderLib /// @notice Library for managing orders library OrderLib { struct OrderId { // Sell currency of order Currency sellCurrency; // Local buy currency of order Currency localBuyCurrency; // Final destination buy currency of order Currency finalDestinationBuyCurrency; // Final destination chainId of order uint256 finalDestinationChainId; } struct Order { // Sell amount of order uint96 sellAmount; // Id params of order OrderId idParams; } struct OrderRegistry { // Sell amount of given order mapping(bytes32 => uint96) orderOf; // Hash of registry state bytes32 ordersHash; } /// @notice Emitted when a new order is created event NewOrder( uint256 sellAmount, Currency indexed sellCurrency, Currency localBuyCurrency, Currency indexed finalDestinationBuyCurrency, uint256 finalDestinationChainId ); /// @notice Thrown when there's a mismatch in order hashes error OrderHashMismatch(); /// @notice Thrown when an order is not filled /// @param id The id of the order that was not filled error OrderNotFilled(bytes32 id); /// @notice Sets multiple orders in the registry /// /// @param self The order registry where orders are stored /// @param orders An array of orders to set in the registry function set(OrderRegistry storage self, Order[] calldata orders) internal { bytes32 newHash = self.ordersHash; for (uint256 i; i < orders.length; ++i) { if (orders[i].sellAmount == 0) continue; OrderId calldata params = orders[i].idParams; // don't need to create order for the same currency within a single chain, as it's already in the final destination if (params.sellCurrency != params.localBuyCurrency || params.finalDestinationChainId != block.chainid) { bytes32 idKey = id(params); newHash = keccak256(abi.encode(newHash, idKey)); self.orderOf[idKey] += orders[i].sellAmount; emit NewOrder( orders[i].sellAmount, params.sellCurrency, params.localBuyCurrency, params.finalDestinationBuyCurrency, params.finalDestinationChainId ); } } self.ordersHash = newHash; } /// @notice Fills a specific order from the registry /// /// @param self The order registry /// @param orderId The id params of the order to fill /// @param sell The sell amount of the order function fill(OrderRegistry storage self, OrderId calldata orderId, uint96 sell) internal { self.orderOf[id(orderId)] -= sell; } /// @notice Resets the orders in the registry /// /// @param self The order registry to reset /// /// @param orderIds An array of order id parameters to reset function reset(OrderRegistry storage self, OrderId[] calldata orderIds) internal { bytes32 ordersHash; for (uint256 i; i < orderIds.length; ++i) { bytes32 idKey = id(orderIds[i]); ordersHash = keccak256(abi.encode(ordersHash, idKey)); if (self.orderOf[idKey] != 0) revert OrderNotFilled(idKey); } if (ordersHash != self.ordersHash) revert OrderHashMismatch(); self.ordersHash = bytes32(0); } /// @notice Retrieves the sell amount of a specific order /// @param self The order registry /// /// @param orderId The id parameters of the order to retrieve /// /// @return The sell amount of the specified order function get(OrderRegistry storage self, OrderId calldata orderId) internal view returns (uint96) { return self.orderOf[id(orderId)]; } /// @dev Generates a unique id for an order based on its parameters /// /// @param self The order id parameters /// /// @return A unique bytes32 id for the order function id(OrderId calldata self) internal pure returns (bytes32) { return keccak256(abi.encode(self)); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.23; import {FixedPointMathLib} from "solmate/utils/FixedPointMathLib.sol"; /// @title PriceLib /// @notice A library for handling fixed-point arithmetic for prices library PriceLib { using FixedPointMathLib for uint256; /// @dev 2**128 uint256 internal constant Q128 = 0x100000000000000000000000000000000; uint16 internal constant PRICE_ORACLE_DECIMALS = 18; uint256 internal constant DECIMALS_MULTIPLIER = 10 ** PRICE_ORACLE_DECIMALS; /// @notice Converts (down) an amount in base units to an amount in asset units based on a fixed-price value /// @param base The amount to convert in base units /// @param price The fixed-price value represented as a uint256 /// @return The equivalent amount in asset units function convertToAssetsDown(uint256 base, uint256 price) internal pure returns (uint256) { return base.mulDivDown(price, Q128); } /// @notice Converts (up) an amount in base units to an amount in asset units based on a fixed-price value /// @param base The amount to convert in base units /// @param price The fixed-price value represented as a uint256 /// @return The equivalent amount in asset units function convertToAssetsUp(uint256 base, uint256 price) internal pure returns (uint256) { return base.mulDivUp(price, Q128); } /// @notice Converts (down) an amount in asset units to an amount in base units based on a fixed-price value /// @param assets The amount to convert in asset units /// @param price The fixed-price value represented as a uint256 /// @return The equivalent amount in base units function convertToBaseDown(uint256 assets, uint256 price) internal pure returns (uint256) { return assets.mulDivDown(Q128, price); } /// @notice Converts (up) an amount in asset units to an amount in base units based on a fixed-price value /// @param assets The amount to convert in asset units /// @param price The fixed-price value represented as a uint256 /// @return The equivalent amount in base units function convertToBaseUp(uint256 assets, uint256 price) internal pure returns (uint256) { return assets.mulDivUp(Q128, price); } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; /// @notice Safe unsigned integer casting library that reverts on overflow. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeCastLib.sol) /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/SafeCast.sol) library SafeCastLib { function safeCastTo248(uint256 x) internal pure returns (uint248 y) { require(x < 1 << 248); y = uint248(x); } function safeCastTo240(uint256 x) internal pure returns (uint240 y) { require(x < 1 << 240); y = uint240(x); } function safeCastTo232(uint256 x) internal pure returns (uint232 y) { require(x < 1 << 232); y = uint232(x); } function safeCastTo224(uint256 x) internal pure returns (uint224 y) { require(x < 1 << 224); y = uint224(x); } function safeCastTo216(uint256 x) internal pure returns (uint216 y) { require(x < 1 << 216); y = uint216(x); } function safeCastTo208(uint256 x) internal pure returns (uint208 y) { require(x < 1 << 208); y = uint208(x); } function safeCastTo200(uint256 x) internal pure returns (uint200 y) { require(x < 1 << 200); y = uint200(x); } function safeCastTo192(uint256 x) internal pure returns (uint192 y) { require(x < 1 << 192); y = uint192(x); } function safeCastTo184(uint256 x) internal pure returns (uint184 y) { require(x < 1 << 184); y = uint184(x); } function safeCastTo176(uint256 x) internal pure returns (uint176 y) { require(x < 1 << 176); y = uint176(x); } function safeCastTo168(uint256 x) internal pure returns (uint168 y) { require(x < 1 << 168); y = uint168(x); } function safeCastTo160(uint256 x) internal pure returns (uint160 y) { require(x < 1 << 160); y = uint160(x); } function safeCastTo152(uint256 x) internal pure returns (uint152 y) { require(x < 1 << 152); y = uint152(x); } function safeCastTo144(uint256 x) internal pure returns (uint144 y) { require(x < 1 << 144); y = uint144(x); } function safeCastTo136(uint256 x) internal pure returns (uint136 y) { require(x < 1 << 136); y = uint136(x); } function safeCastTo128(uint256 x) internal pure returns (uint128 y) { require(x < 1 << 128); y = uint128(x); } function safeCastTo120(uint256 x) internal pure returns (uint120 y) { require(x < 1 << 120); y = uint120(x); } function safeCastTo112(uint256 x) internal pure returns (uint112 y) { require(x < 1 << 112); y = uint112(x); } function safeCastTo104(uint256 x) internal pure returns (uint104 y) { require(x < 1 << 104); y = uint104(x); } function safeCastTo96(uint256 x) internal pure returns (uint96 y) { require(x < 1 << 96); y = uint96(x); } function safeCastTo88(uint256 x) internal pure returns (uint88 y) { require(x < 1 << 88); y = uint88(x); } function safeCastTo80(uint256 x) internal pure returns (uint80 y) { require(x < 1 << 80); y = uint80(x); } function safeCastTo72(uint256 x) internal pure returns (uint72 y) { require(x < 1 << 72); y = uint72(x); } function safeCastTo64(uint256 x) internal pure returns (uint64 y) { require(x < 1 << 64); y = uint64(x); } function safeCastTo56(uint256 x) internal pure returns (uint56 y) { require(x < 1 << 56); y = uint56(x); } function safeCastTo48(uint256 x) internal pure returns (uint48 y) { require(x < 1 << 48); y = uint48(x); } function safeCastTo40(uint256 x) internal pure returns (uint40 y) { require(x < 1 << 40); y = uint40(x); } function safeCastTo32(uint256 x) internal pure returns (uint32 y) { require(x < 1 << 32); y = uint32(x); } function safeCastTo24(uint256 x) internal pure returns (uint24 y) { require(x < 1 << 24); y = uint24(x); } function safeCastTo16(uint256 x) internal pure returns (uint16 y) { require(x < 1 << 16); y = uint16(x); } function safeCastTo8(uint256 x) internal pure returns (uint8 y) { require(x < 1 << 8); y = uint8(x); } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; /// @notice Simple single owner authorization mixin. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/auth/Owned.sol) abstract contract Owned { /*////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ event OwnershipTransferred(address indexed user, address indexed newOwner); /*////////////////////////////////////////////////////////////// OWNERSHIP STORAGE //////////////////////////////////////////////////////////////*/ address public owner; modifier onlyOwner() virtual { require(msg.sender == owner, "UNAUTHORIZED"); _; } /*////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////*/ constructor(address _owner) { owner = _owner; emit OwnershipTransferred(address(0), _owner); } /*////////////////////////////////////////////////////////////// OWNERSHIP LOGIC //////////////////////////////////////////////////////////////*/ function transferOwnership(address newOwner) public virtual onlyOwner { owner = newOwner; emit OwnershipTransferred(msg.sender, newOwner); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.23; import {Currency} from "../libraries/CurrencyLib.sol"; type a160u96 is uint256; using {addr, unpack, unpackRaw, currency, value, eq as ==, neq as !=} for a160u96 global; error AddressMismatch(address, address); function neq(a160u96 a, a160u96 b) pure returns (bool) { return !eq(a, b); } function eq(a160u96 a, a160u96 b) pure returns (bool) { return a160u96.unwrap(a) == a160u96.unwrap(b); } function currency(a160u96 packed) pure returns (Currency) { return Currency.wrap(addr(packed)); } function addr(a160u96 packed) pure returns (address) { return address(uint160(a160u96.unwrap(packed))); } function value(a160u96 packed) pure returns (uint96) { return uint96(a160u96.unwrap(packed) >> 160); } function unpack(a160u96 packed) pure returns (Currency _curr, uint96 _value) { uint256 raw = a160u96.unwrap(packed); _curr = Currency.wrap(address(uint160(raw))); _value = uint96(raw >> 160); } function unpackRaw(a160u96 packed) pure returns (address _addr, uint96 _value) { uint256 raw = a160u96.unwrap(packed); _addr = address(uint160(raw)); _value = uint96(raw >> 160); } library A160U96Factory { function create(address _addr, uint96 _value) internal pure returns (a160u96) { return a160u96.wrap((uint256(_value) << 160) | uint256(uint160(_addr))); } function create(Currency _currency, uint96 _value) internal pure returns (a160u96) { return create(Currency.unwrap(_currency), _value); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; import "../extensions/IERC20Permit.sol"; import "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; /** * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } /** * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful. */ function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove(IERC20 token, address spender, uint256 value) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } /** * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 oldAllowance = token.allowance(address(this), spender); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value)); } /** * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value)); } } /** * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval * to be set to zero before setting it to a non-zero value, such as USDT. */ function forceApprove(IERC20 token, address spender, uint256 value) internal { bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value); if (!_callOptionalReturnBool(token, approvalCall)) { _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0)); _callOptionalReturn(token, approvalCall); } } /** * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`. * Revert on invalid signature. */ function safePermit( IERC20Permit token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit(owner, spender, value, deadline, v, r, s); uint256 nonceAfter = token.nonces(owner); require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). * * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead. */ function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false // and not revert is the subcall reverts. (bool success, bytes memory returndata) = address(token).call(data); return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 amount) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * * Furthermore, `isContract` will also return true if the target contract within * the same transaction is already scheduled for destruction by `SELFDESTRUCT`, * which only has an effect at the end of a transaction. * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
{ "remappings": [ "@openzeppelin/contracts/=lib/phuture-v2-contracts/lib/@openzeppelin/contracts/", "chainlink/=lib/phuture-v2-contracts/lib/chainlink-brownie-contracts/contracts/", "forge-std/=lib/forge-std/src/", "layerzero/=lib/phuture-v2-contracts/lib/LayerZero/contracts/", "redstone/=lib/phuture-v2-contracts/lib/redstone-oracles-monorepo/packages/evm-connector/contracts/", "solmate/=lib/phuture-v2-contracts/lib/solmate/src/", "src/=lib/phuture-v2-contracts/src/", "sstore2/=lib/phuture-v2-contracts/lib/sstore2/contracts/", "@chainlink/=node_modules/@chainlink/", "@eth-optimism/=node_modules/@eth-optimism/", "@openzeppelin/contracts-upgradeable/=lib/phuture-v2-contracts/lib/openzeppelin-contracts-upgradeable/contracts/", "@redstone-finance/=node_modules/@redstone-finance/", "LayerZero/=lib/phuture-v2-contracts/lib/LayerZero/contracts/", "chainlink-brownie-contracts/=lib/phuture-v2-contracts/lib/chainlink-brownie-contracts/contracts/src/v0.6/vendor/@arbitrum/nitro-contracts/src/", "ds-test/=lib/forge-std/lib/ds-test/src/", "erc4626-tests/=lib/phuture-v2-contracts/lib/@openzeppelin/lib/erc4626-tests/", "openzeppelin-contracts-upgradeable/=lib/phuture-v2-contracts/lib/openzeppelin-contracts-upgradeable/", "openzeppelin/=lib/phuture-v2-contracts/lib/@openzeppelin/contracts/", "phuture-v2-contracts/=lib/phuture-v2-contracts/", "redstone-oracles-monorepo/=lib/phuture-v2-contracts/lib/", "solady/=lib/phuture-v2-contracts/lib/solady/src/" ], "optimizer": { "enabled": true, "runs": 200, "details": { "constantOptimizer": true, "yul": true, "yulDetails": { "stackAllocation": true } } }, "metadata": { "useLiteralContent": false, "bytecodeHash": "none", "appendCBOR": false }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "paris", "viaIR": true, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_vault","type":"address"},{"internalType":"address","name":"_messenger","type":"address"},{"internalType":"address","name":"_priceOracle","type":"address"},{"internalType":"uint16","name":"_maxSlippageInBP","type":"uint16"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AmountExceedsOrderSize","type":"error"},{"inputs":[],"name":"BadSender","type":"error"},{"inputs":[],"name":"ConsumeAmountMismatch","type":"error"},{"inputs":[],"name":"DonateFailure","type":"error"},{"inputs":[],"name":"ERC20TransferFailed","type":"error"},{"inputs":[],"name":"Forbidden","type":"error"},{"inputs":[],"name":"HighLoss","type":"error"},{"inputs":[],"name":"LengthMismatch","type":"error"},{"inputs":[],"name":"NativeTransferFailed","type":"error"},{"inputs":[],"name":"NotEmpty","type":"error"},{"inputs":[],"name":"OrderHashMismatch","type":"error"},{"inputs":[{"internalType":"bytes32","name":"id","type":"bytes32"}],"name":"OrderNotFilled","type":"error"},{"inputs":[],"name":"OrdersLength","type":"error"},{"inputs":[],"name":"Sorting","type":"error"},{"inputs":[],"name":"UsedIndex","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"sellAmount","type":"uint256"},{"indexed":true,"internalType":"Currency","name":"sellCurrency","type":"address"},{"indexed":false,"internalType":"Currency","name":"localBuyCurrency","type":"address"},{"indexed":true,"internalType":"Currency","name":"finalDestinationBuyCurrency","type":"address"},{"indexed":false,"internalType":"uint256","name":"finalDestinationChainId","type":"uint256"}],"name":"NewOrder","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"id","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"sold","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"bought","type":"uint256"}],"name":"OrderFilled","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"},{"inputs":[{"internalType":"Currency","name":"currency","type":"address"},{"internalType":"uint96","name":"amount","type":"uint96"},{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct IOrderBook.TradeParams","name":"params","type":"tuple"}],"name":"consume","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"Currency","name":"currency","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"donate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"Currency","name":"sellCurrency","type":"address"},{"internalType":"Currency","name":"localBuyCurrency","type":"address"},{"internalType":"Currency","name":"finalDestinationBuyCurrency","type":"address"},{"internalType":"uint256","name":"finalDestinationChainId","type":"uint256"}],"internalType":"struct OrderLib.OrderId","name":"orderId","type":"tuple"},{"internalType":"uint96","name":"sell","type":"uint96"},{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct IOrderBook.TradeParams","name":"tradeParams","type":"tuple"},{"internalType":"bytes","name":"payload","type":"bytes"}],"internalType":"struct IOrderBook.ExecuteOrderParams","name":"params","type":"tuple"}],"name":"executeOrder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"Currency","name":"sellCurrency","type":"address"},{"internalType":"Currency","name":"localBuyCurrency","type":"address"},{"internalType":"Currency","name":"finalDestinationBuyCurrency","type":"address"},{"internalType":"uint256","name":"finalDestinationChainId","type":"uint256"}],"internalType":"struct OrderLib.OrderId[]","name":"orderIds","type":"tuple[]"},{"internalType":"uint256[]","name":"idIndices","type":"uint256[]"},{"internalType":"uint256[]","name":"pendingOrderCounts","type":"uint256[]"}],"internalType":"struct IOrderBook.FinishOrderExecutionParams","name":"params","type":"tuple"}],"name":"finishOrderExecution","outputs":[{"components":[{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"Currency","name":"currency","type":"address"},{"internalType":"uint256","name":"totalBought","type":"uint256"},{"components":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"Currency","name":"buyCurrency","type":"address"}],"internalType":"struct IOrderBook.BoughtOrder[]","name":"orders","type":"tuple[]"}],"internalType":"struct IOrderBook.PendingOrder[]","name":"pendingOrders","type":"tuple[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isFundManager","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxSlippageInBP","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"messenger","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"Currency","name":"sellCurrency","type":"address"},{"internalType":"Currency","name":"localBuyCurrency","type":"address"},{"internalType":"Currency","name":"finalDestinationBuyCurrency","type":"address"},{"internalType":"uint256","name":"finalDestinationChainId","type":"uint256"}],"internalType":"struct OrderLib.OrderId","name":"orderId","type":"tuple"}],"name":"orderOf","outputs":[{"internalType":"uint96","name":"","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"phutureOnDonationCallbackV1","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"priceOracle","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint96","name":"sellAmount","type":"uint96"},{"components":[{"internalType":"Currency","name":"sellCurrency","type":"address"},{"internalType":"Currency","name":"localBuyCurrency","type":"address"},{"internalType":"Currency","name":"finalDestinationBuyCurrency","type":"address"},{"internalType":"uint256","name":"finalDestinationChainId","type":"uint256"}],"internalType":"struct OrderLib.OrderId","name":"idParams","type":"tuple"}],"internalType":"struct OrderLib.Order[]","name":"orders","type":"tuple[]"},{"internalType":"Currency","name":"currency","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"receiveIncomingOrders","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_incomingOrders","type":"uint256"}],"name":"removeDustOrders","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_maxSlippageInBP","type":"uint16"}],"name":"setMaxSlippageInBP","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_messenger","type":"address"}],"name":"setMessenger","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_incomingOrders","type":"uint256"},{"components":[{"internalType":"uint96","name":"sellAmount","type":"uint96"},{"components":[{"internalType":"Currency","name":"sellCurrency","type":"address"},{"internalType":"Currency","name":"localBuyCurrency","type":"address"},{"internalType":"Currency","name":"finalDestinationBuyCurrency","type":"address"},{"internalType":"uint256","name":"finalDestinationChainId","type":"uint256"}],"internalType":"struct OrderLib.OrderId","name":"idParams","type":"tuple"}],"internalType":"struct OrderLib.Order[]","name":"orders","type":"tuple[]"}],"name":"setOrders","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_priceOracle","type":"address"}],"name":"setPriceOracle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"fundManager","type":"address"},{"internalType":"bool","name":"isAllowed","type":"bool"}],"name":"updateFundManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"vault","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
60a0346200014a57601f62001e6338819003918201601f19168301916001600160401b038311848410176200014f5780849260a0946040528339810103126200014a576200004d8162000165565b906200005c6020820162000165565b6200006a6040830162000165565b9260806200007b6060850162000165565b9301519161ffff831683036200014a57600080546001600160a01b039384166001600160a01b031991821681178355604051979192859291907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a3600680549093169116179055608052600780546001600160b01b031916919093161760a09190911b61ffff60a01b16179055611ce890816200017b8239608051818181610a0301528181610dab01528181610ed301528181611046015281816111c00152818161126e01526115260152f35b600080fd5b634e487b7160e01b600052604160045260246000fd5b51906001600160a01b03821682036200014a5756fe6080604052600436101561001b575b361561001957600080fd5b005b60003560e01c80630ca3008d1461015b5780632630c12f146101565780633cb747bf146101515780634266d76e1461014c578063474aba6b14610147578063530e784f1461014257806353e1b47a1461013d578063662859671461013857806368d0eb5d1461013357806373af6cda1461012e5780638da5cb5b14610129578063a892ecf614610124578063a8ad4e7a1461011f578063ad102f9b1461011a578063ad175a8b14610115578063d809ad9a14610110578063dd6d77a71461010b578063e69d849d14610106578063f2fde38b146101015763fbfa77cf0361000e57611258565b6111e5565b611192565b611150565b6110c0565b610fac565b610f3a565b610ea1565b610e7c565b610e53565b610dee565b610931565b6108e1565b610850565b6106f9565b61032d565b610205565b6101dc565b6101b3565b346101a35760203660031901126101a3576006546001600160a01b031633036101915761018c6004356005546112b3565b600555005b604051631dd2188d60e31b8152600490fd5b600080fd5b60009103126101a357565b346101a35760003660031901126101a3576007546040516001600160a01b039091168152602090f35b346101a35760003660031901126101a3576006546040516001600160a01b039091168152602090f35b346101a35760203660031901126101a35760043561ffff811681036101a35761023960018060a01b036000541633146112cc565b6007805461ffff60a01b191660a09290921b61ffff60a01b16919091179055005b6020808201908083528351809252604092604081018260408560051b840101960194600080935b86851061029357505050505050505090565b909192939480969798603f1983820301865289519060808360a082840193855181528286015193600180841b03809516848301528a8701518b8301526060809701519682015285518095520193019186915b8882841061030957505050505090806001929a019501950193969594929190610281565b8451805187528701518216878701528c9695019493909301926001909201916102e5565b346101a35760206003196020813601126101a3576004908135916001600160401b0383116101a357828101916060809185360301126101a3576006546001600160a01b031633036106d8576005546106c857602484019361038e8585611307565b905061039a858061133c565b919050036106b4576044906103b86103b2868061133c565b9061181c565b016103cd6103c68286611307565b9050611388565b6000948592600019916103ea6103e3828061133c565b9050611407565b98885b6103f7838061133c565b90508110156106395761042761042161041a836104148688611307565b9061144f565b358d611464565b51151590565b6106285761044561043f61041a836104148688611307565b60019052565b8b610468610453858061133c565b61046185610414888a611307565b3591611478565b8981013546810361047f575b5050506001016103ed565b80888c929e959e03610542575b50610535600194929361052484866000958f8f906105109161050b6104b18e9d6118c1565b986104ee6104c98b6000526004602052604060002090565b5497604090816104d98888611464565b51016104e68b8251611506565b9052016114eb565b906104f76107df565b9788526001600160a01b0390911690870152565b611464565b5101519061051e8383611464565b52611464565b506000526004602052604060002090565b55019990508b3880610474565b90999897919291600181016105c7575b50979896979683918a908982848d8261056b8e8e611307565b610575929161144f565b3561057f90611488565b9261058991611464565b510152610596838d611464565b51528a6105a48683016114eb565b826105af8584611464565b516001600160a01b039092169101525093925061048c565b915080939295979950979395971061061757886105e4848a611464565b51015151036106065787966001909201959194919391926000918d9083610552565b604051631d7194ef60e21b81528990fd5b604051631bf2e81960e21b81528a90fd5b6040516362e4a1c960e11b81528990fd5b88868b8a8a88888551610659575b60405180610655888261025a565b0390f35b9061066391611307565b905061066e826114f8565b106106a05761067d9084611464565b5101515103610690578180808080610647565b50604051631d7194ef60e21b8152fd5b6040516001621398b960e31b031981528590fd5b6040516001621398b960e31b031981528390fd5b506040516332e7879360e01b8152fd5b50604051631dd2188d60e31b8152fd5b6001600160a01b038116036101a357565b346101a35760203660031901126101a357600435610716816106e8565b6000546001600160a01b03919061073090831633146112cc565b166001600160601b0360a01b6007541617600755600080f35b6001600160601b038116036101a357565b634e487b7160e01b600052604160045260246000fd5b604081019081106001600160401b0382111761078b57604052565b61075a565b6001600160401b03811161078b57604052565b60a081019081106001600160401b0382111761078b57604052565b90601f801991011681019081106001600160401b0382111761078b57604052565b604051906107ec82610770565b565b6001600160401b03811161078b57601f01601f191660200190565b81601f820112156101a357803590610820826107ee565b9261082e60405194856107be565b828452602083830101116101a357816000926020809301838601378301015290565b346101a3576003196060368201126101a3576004359061086f826106e8565b60243561087b81610749565b604435926001600160401b03928385116101a35760409085360301126101a357604051926108a884610770565b84600401356108b6816106e8565b845260248501359081116101a3576100199460046108d79236920101610809565b6020840152611513565b346101a35760203660031901126101a3576004356108fe816106e8565b6000546001600160a01b03919061091890831633146112cc565b166001600160601b0360a01b6006541617600655600080f35b346101a3576003196020368201126101a3576004908135916001600160401b0383116101a35760e08382019284360301126101a3573360009081526001602052604090205460ff1615610ddf576109aa61099d61098d846118c1565b6000526002602052604060002090565b546001600160601b031690565b9060848401916001600160601b036109d06109c485611609565b6001600160601b031690565b911610610dd0576064840135461480159190610da9576006546001600160a01b0316905b6109fd856114eb565b95610a297f00000000000000000000000000000000000000000000000000000000000000008098611925565b90866024820192610a4286610a3d866114eb565b611925565b998715610ce6576001600160a01b038116610a5c846114eb565b90610a668b611609565b90610a93610a8960a48901610a83610a7e828b611613565b6114eb565b98611613565b60208101906116e9565b9390823b156101a3578a610ac060009687936040519b8c9889978896636f4342cb60e01b8852870161171b565b03925af1908115610c8957610ae993610ae392610ccd575b505b610a3d8b6114eb565b90611751565b93610af66109c488611609565b8503610cbc57610b6295969798610b13610b1892610a3d866114eb565b611751565b95610c8e575b60075490610b4160c4610b39610b338c6114eb565b956114eb565b92018a6116e9565b919093604097889384519687948594633de4bb6f60e21b86528a8601611774565b03816001600160a01b0385165afa918215610c8957600090600093610c3e575b50610bbb91610bae610ba761ffff610b9d610bb4958a6119a7565b9360a01c1661179d565b61ffff1690565b906119cc565b91866119a7565b10610c305750610c0a610c047fb38583f2adb435cac858db9d3e8d3ca952ccb32307e2f3d0053b415d2d2934819596610bff610bf9610c2b956119e7565b826119ff565b6118c1565b95611609565b915192839283602090939291936001600160601b0360408201951681520152565b0390a2005b8251638594407b60e01b8152fd5b610b9d9350610bb4915091610bae610ba761ffff610c74610bbb968b3d8d11610c82575b610c6c81836107be565b81019061175e565b979095505050505091610b82565b503d610c62565b6115fd565b610caa610c9a896118c1565b6000526004602052604060002090565b610cb5878254611506565b9055610b1e565b60405163f6afb74760e01b81528490fd5b80610cda610ce092610790565b806101a8565b38610ad8565b6001600160a01b0381169250610cfb856114eb565b8a610d4d8b610d3f610d23610d18610d12866114eb565b93611609565b9460a48b0190611613565b6040516329f0da3d60e11b602082015294859360248501611649565b03601f1981018352826107be565b843b156101a357610d7894600092838a6040519889958694859363a68a299760e01b855284016116c7565b03925af1908115610c8957610ae993610ae392610d96575b50610ada565b80610cda610da392610790565b38610d90565b7f0000000000000000000000000000000000000000000000000000000000000000906109f4565b6040516338c31d0d60e11b8152fd5b60405163f9b5d12d60e01b8152fd5b346101a35760403660031901126101a357600435610e0b816106e8565b602435908115158092036101a3576000546001600160a01b039190610e3390831633146112cc565b16600052600160205260406000209060ff80198354169116179055600080f35b346101a35760003660031901126101a3576000546040516001600160a01b039091168152602090f35b346101a35760003660031901126101a357602061ffff60075460a01c16604051908152f35b346101a35760203660031901126101a3576004356001600160401b0381116101a357610ed1903690600401610809565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316330361019157610019906117b1565b9181601f840112156101a3578235916001600160401b0383116101a35760208085019460a085020101116101a357565b346101a35760403660031901126101a3576004356024356001600160401b0381116101a357610f6d903690600401610f0a565b6006546001600160a01b0316330361019157610f8891611a7b565b60055460008282019283129112908015821691151617610fa757600555005b61129d565b346101a35760603660031901126101a3576004356001600160401b0381116101a357610fdc903690600401610f0a565b9060243591610fea836106e8565b6006546001600160a01b03929083163303610191578161101061101d9361101893611a7b565b6005546112b3565b600555565b60405163e69d849d60e01b60208201526001600160a01b038316602482015260448035908201527f00000000000000000000000000000000000000000000000000000000000000009190911691906110788160648101610d3f565b823b156101a3576110a3926000928360405180968195829463a68a299760e01b8452600484016116c7565b03925af18015610c89576110b357005b80610cda61001992610790565b346101a35760803660031901126101a35760405160208101906004356110e5816106e8565b6001600160a01b039081168352806024356110ff816106e8565b166040830152604435611111816106e8565b16606082015260643560808201526080815261112c816107a3565b519020600052600260205260206001600160601b0360406000205416604051908152f35b346101a35760203660031901126101a35760043561116d816106e8565b60018060a01b03166000526001602052602060ff604060002054166040519015158152f35b346101a35760403660031901126101a3576004356111af816106e8565b3033036101915761001990602435907f000000000000000000000000000000000000000000000000000000000000000090611c50565b346101a35760203660031901126101a357600435611202816106e8565b6000805490916001600160a01b039061121e33838516146112cc565b1680916001600160601b0360a01b16178255337f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08380a380f35b346101a35760003660031901126101a3576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b634e487b7160e01b600052601160045260246000fd5b81810392916000138015828513169184121617610fa757565b156112d357565b60405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b6044820152606490fd5b903590601e19813603018212156101a357018035906001600160401b0382116101a357602001918160051b360383136101a357565b903590601e19813603018212156101a357018035906001600160401b0382116101a357602001918160071b360383136101a357565b6001600160401b03811161078b5760051b60200190565b9061139282611371565b6040906113a260405191826107be565b83815280936113b3601f1991611371565b019060009260005b8381106113c9575050505050565b81519060808201918083106001600160401b0384111761078b57602092845286815282878183015287858301526060808301528286010152016113bb565b9061141182611371565b61141e60405191826107be565b828152809261142f601f1991611371565b0190602036910137565b634e487b7160e01b600052603260045260246000fd5b919081101561145f5760051b0190565b611439565b805182101561145f5760209160051b010190565b919081101561145f5760071b0190565b9061149282611371565b6040906114a260405191826107be565b83815280936114b3601f1991611371565b019160009060005b8481106114c9575050505050565b60209082516114d781610770565b8481528285818301528287010152016114bb565b356114f5816106e8565b90565b9060018201809211610fa757565b91908201809211610fa757565b91903033036101915760018060a01b03807f00000000000000000000000000000000000000000000000000000000000000001690602081855116940151823b156101a3576001600160601b039561159f600096928793604051998a9889978896636f4342cb60e01b885216600487015216602485015260448401526080606484015260848301906115bd565b03925af18015610c89576115b05750565b80610cda6107ec92610790565b919082519283825260005b8481106115e9575050826000602080949584010152601f8019910116010190565b6020818301810151848301820152016115c8565b6040513d6000823e3d90fd5b356114f581610749565b903590603e19813603018212156101a3570190565b908060209392818452848401376000828201840152601f01601f1916010190565b6001600160a01b0391821681526001600160601b03909216602083015260606040830152909190813561167b816106e8565b1660608301526020810135601e19823603018112156101a35701602081359101906001600160401b0381116101a35780360382136101a35760a083604060806114f59601520191611628565b6001600160a01b0390911681526040602082018190526114f5929101906115bd565b903590601e19813603018212156101a357018035906001600160401b0382116101a3576020019181360383136101a357565b906114f595936001600160601b0360809460018060a01b0380941685521660208401521660408201528160608201520191611628565b91908203918211610fa757565b91908260409103126101a3576020825192015190565b6001600160a01b039182168152911660208201526060604082018190526114f593910191611628565b9061ffff80921661271003918211610fa757565b6000809160208151910182305af1903d15611814573d916117d1836107ee565b926117df60405194856107be565b83523d6000602085013e5b61181057508051156117fe57602081519101fd5b60405163fe50217960e01b8152600490fd5b9050565b6060916117ea565b60009160005b81811061184d575050506003540361183b576000600355565b60405163be364e3b60e01b8152600490fd5b61185b610bff828486611478565b604080516020810196875280820183905290959061187c8160608101610d3f565b5190209461189a6109c461099d846000526002602052604060002090565b6118a8575050600101611822565b516318fdea5360e21b8152600481019190915260249150fd5b6040516060602082019280356118d6816106e8565b6001600160a01b0390811685528060208301356118f2816106e8565b1660408501526040820135611906816106e8565b1682840152013560808201526080815261191f816107a3565b51902090565b6000906001600160a01b039081169081611940575050503190565b6024602092939460405194859384926370a0823160e01b84521660048301525afa918215610c8957809261197357505090565b9091506020823d60201161199f575b8161198f602093836107be565b8101031261199c57505190565b80fd5b3d9150611982565b6fffffffffffffffffffffffffffffffff811160801b158202156101a35760801b0490565b9061271091816000190481118202158302156101a357020490565b600160601b8110156101a3576001600160601b031690565b611a08906118c1565b60005260026020526040600020906001600160601b0390818084541691169003908111610fa75781546bffffffffffffffffffffffff19166001600160601b03909116179055565b919081101561145f5760a0020190565b9190916001600160601b0380809416911601918211610fa757565b906003549160005b828110611a9257505050600355565b611aa86109c4611aa3838686611a50565b611609565b15611c4857611ab8818484611a50565b60209081810191611ac8836114eb565b92604091611aee83850195611adc876114eb565b6001600160a01b039182169116141590565b8015611c3a575b611b09575b50505050506001905b01611a83565b611b12826118c1565b8351918201998a5260208a018190529890806040830103601f1981018252611b3a90826107be565b51902097611b49868989611a50565b611b5290611609565b90611b67906000526002602052604060002090565b908154611b7a906001600160601b031690565b90611b8491611a60565b81546bffffffffffffffffffffffff19166001600160601b03909116179055611bae858888611a50565b611bb790611609565b90611bc1906114eb565b93611bcb906114eb565b90611bd8606085016114eb565b92516001600160601b039190911681526001600160a01b0391821660208201526080939093013560408401529081169216907fd78bb599a4097286457bdc72d494e5de820aa40e1222bd19b1289440e7fa6cdf90606090a33880808080611afa565b504660808501351415611af5565b600190611b03565b8215611ce3576001600160a01b03818116611c8f57505060008080611c779481945af11590565b611c7d57565b604051633d2cec6f60e21b8152600490fd5b60209260008093611ccb966044946040519463a9059cbb60e01b865216600485015260248401525af1600051600114601f3d11163d1517161590565b611cd157565b604051633c9fd93960e21b8152600490fd5b50505056000000000000000000000000de4d377d8a8d455330edd7c4eb5b284ada1113d8000000000000000000000000e903f5a1d43d93407bcd11c771c03628539414d20000000000000000000000008dd78e46642e14858f25aaa41b2b36c0bd6b444f000000000000000000000000c44f324e5c7606ce5864b253f3eb08be0f27038c000000000000000000000000000000000000000000000000000000000000012c
Deployed Bytecode
0x6080604052600436101561001b575b361561001957600080fd5b005b60003560e01c80630ca3008d1461015b5780632630c12f146101565780633cb747bf146101515780634266d76e1461014c578063474aba6b14610147578063530e784f1461014257806353e1b47a1461013d578063662859671461013857806368d0eb5d1461013357806373af6cda1461012e5780638da5cb5b14610129578063a892ecf614610124578063a8ad4e7a1461011f578063ad102f9b1461011a578063ad175a8b14610115578063d809ad9a14610110578063dd6d77a71461010b578063e69d849d14610106578063f2fde38b146101015763fbfa77cf0361000e57611258565b6111e5565b611192565b611150565b6110c0565b610fac565b610f3a565b610ea1565b610e7c565b610e53565b610dee565b610931565b6108e1565b610850565b6106f9565b61032d565b610205565b6101dc565b6101b3565b346101a35760203660031901126101a3576006546001600160a01b031633036101915761018c6004356005546112b3565b600555005b604051631dd2188d60e31b8152600490fd5b600080fd5b60009103126101a357565b346101a35760003660031901126101a3576007546040516001600160a01b039091168152602090f35b346101a35760003660031901126101a3576006546040516001600160a01b039091168152602090f35b346101a35760203660031901126101a35760043561ffff811681036101a35761023960018060a01b036000541633146112cc565b6007805461ffff60a01b191660a09290921b61ffff60a01b16919091179055005b6020808201908083528351809252604092604081018260408560051b840101960194600080935b86851061029357505050505050505090565b909192939480969798603f1983820301865289519060808360a082840193855181528286015193600180841b03809516848301528a8701518b8301526060809701519682015285518095520193019186915b8882841061030957505050505090806001929a019501950193969594929190610281565b8451805187528701518216878701528c9695019493909301926001909201916102e5565b346101a35760206003196020813601126101a3576004908135916001600160401b0383116101a357828101916060809185360301126101a3576006546001600160a01b031633036106d8576005546106c857602484019361038e8585611307565b905061039a858061133c565b919050036106b4576044906103b86103b2868061133c565b9061181c565b016103cd6103c68286611307565b9050611388565b6000948592600019916103ea6103e3828061133c565b9050611407565b98885b6103f7838061133c565b90508110156106395761042761042161041a836104148688611307565b9061144f565b358d611464565b51151590565b6106285761044561043f61041a836104148688611307565b60019052565b8b610468610453858061133c565b61046185610414888a611307565b3591611478565b8981013546810361047f575b5050506001016103ed565b80888c929e959e03610542575b50610535600194929361052484866000958f8f906105109161050b6104b18e9d6118c1565b986104ee6104c98b6000526004602052604060002090565b5497604090816104d98888611464565b51016104e68b8251611506565b9052016114eb565b906104f76107df565b9788526001600160a01b0390911690870152565b611464565b5101519061051e8383611464565b52611464565b506000526004602052604060002090565b55019990508b3880610474565b90999897919291600181016105c7575b50979896979683918a908982848d8261056b8e8e611307565b610575929161144f565b3561057f90611488565b9261058991611464565b510152610596838d611464565b51528a6105a48683016114eb565b826105af8584611464565b516001600160a01b039092169101525093925061048c565b915080939295979950979395971061061757886105e4848a611464565b51015151036106065787966001909201959194919391926000918d9083610552565b604051631d7194ef60e21b81528990fd5b604051631bf2e81960e21b81528a90fd5b6040516362e4a1c960e11b81528990fd5b88868b8a8a88888551610659575b60405180610655888261025a565b0390f35b9061066391611307565b905061066e826114f8565b106106a05761067d9084611464565b5101515103610690578180808080610647565b50604051631d7194ef60e21b8152fd5b6040516001621398b960e31b031981528590fd5b6040516001621398b960e31b031981528390fd5b506040516332e7879360e01b8152fd5b50604051631dd2188d60e31b8152fd5b6001600160a01b038116036101a357565b346101a35760203660031901126101a357600435610716816106e8565b6000546001600160a01b03919061073090831633146112cc565b166001600160601b0360a01b6007541617600755600080f35b6001600160601b038116036101a357565b634e487b7160e01b600052604160045260246000fd5b604081019081106001600160401b0382111761078b57604052565b61075a565b6001600160401b03811161078b57604052565b60a081019081106001600160401b0382111761078b57604052565b90601f801991011681019081106001600160401b0382111761078b57604052565b604051906107ec82610770565b565b6001600160401b03811161078b57601f01601f191660200190565b81601f820112156101a357803590610820826107ee565b9261082e60405194856107be565b828452602083830101116101a357816000926020809301838601378301015290565b346101a3576003196060368201126101a3576004359061086f826106e8565b60243561087b81610749565b604435926001600160401b03928385116101a35760409085360301126101a357604051926108a884610770565b84600401356108b6816106e8565b845260248501359081116101a3576100199460046108d79236920101610809565b6020840152611513565b346101a35760203660031901126101a3576004356108fe816106e8565b6000546001600160a01b03919061091890831633146112cc565b166001600160601b0360a01b6006541617600655600080f35b346101a3576003196020368201126101a3576004908135916001600160401b0383116101a35760e08382019284360301126101a3573360009081526001602052604090205460ff1615610ddf576109aa61099d61098d846118c1565b6000526002602052604060002090565b546001600160601b031690565b9060848401916001600160601b036109d06109c485611609565b6001600160601b031690565b911610610dd0576064840135461480159190610da9576006546001600160a01b0316905b6109fd856114eb565b95610a297f000000000000000000000000e903f5a1d43d93407bcd11c771c03628539414d28098611925565b90866024820192610a4286610a3d866114eb565b611925565b998715610ce6576001600160a01b038116610a5c846114eb565b90610a668b611609565b90610a93610a8960a48901610a83610a7e828b611613565b6114eb565b98611613565b60208101906116e9565b9390823b156101a3578a610ac060009687936040519b8c9889978896636f4342cb60e01b8852870161171b565b03925af1908115610c8957610ae993610ae392610ccd575b505b610a3d8b6114eb565b90611751565b93610af66109c488611609565b8503610cbc57610b6295969798610b13610b1892610a3d866114eb565b611751565b95610c8e575b60075490610b4160c4610b39610b338c6114eb565b956114eb565b92018a6116e9565b919093604097889384519687948594633de4bb6f60e21b86528a8601611774565b03816001600160a01b0385165afa918215610c8957600090600093610c3e575b50610bbb91610bae610ba761ffff610b9d610bb4958a6119a7565b9360a01c1661179d565b61ffff1690565b906119cc565b91866119a7565b10610c305750610c0a610c047fb38583f2adb435cac858db9d3e8d3ca952ccb32307e2f3d0053b415d2d2934819596610bff610bf9610c2b956119e7565b826119ff565b6118c1565b95611609565b915192839283602090939291936001600160601b0360408201951681520152565b0390a2005b8251638594407b60e01b8152fd5b610b9d9350610bb4915091610bae610ba761ffff610c74610bbb968b3d8d11610c82575b610c6c81836107be565b81019061175e565b979095505050505091610b82565b503d610c62565b6115fd565b610caa610c9a896118c1565b6000526004602052604060002090565b610cb5878254611506565b9055610b1e565b60405163f6afb74760e01b81528490fd5b80610cda610ce092610790565b806101a8565b38610ad8565b6001600160a01b0381169250610cfb856114eb565b8a610d4d8b610d3f610d23610d18610d12866114eb565b93611609565b9460a48b0190611613565b6040516329f0da3d60e11b602082015294859360248501611649565b03601f1981018352826107be565b843b156101a357610d7894600092838a6040519889958694859363a68a299760e01b855284016116c7565b03925af1908115610c8957610ae993610ae392610d96575b50610ada565b80610cda610da392610790565b38610d90565b7f000000000000000000000000e903f5a1d43d93407bcd11c771c03628539414d2906109f4565b6040516338c31d0d60e11b8152fd5b60405163f9b5d12d60e01b8152fd5b346101a35760403660031901126101a357600435610e0b816106e8565b602435908115158092036101a3576000546001600160a01b039190610e3390831633146112cc565b16600052600160205260406000209060ff80198354169116179055600080f35b346101a35760003660031901126101a3576000546040516001600160a01b039091168152602090f35b346101a35760003660031901126101a357602061ffff60075460a01c16604051908152f35b346101a35760203660031901126101a3576004356001600160401b0381116101a357610ed1903690600401610809565b7f000000000000000000000000e903f5a1d43d93407bcd11c771c03628539414d26001600160a01b0316330361019157610019906117b1565b9181601f840112156101a3578235916001600160401b0383116101a35760208085019460a085020101116101a357565b346101a35760403660031901126101a3576004356024356001600160401b0381116101a357610f6d903690600401610f0a565b6006546001600160a01b0316330361019157610f8891611a7b565b60055460008282019283129112908015821691151617610fa757600555005b61129d565b346101a35760603660031901126101a3576004356001600160401b0381116101a357610fdc903690600401610f0a565b9060243591610fea836106e8565b6006546001600160a01b03929083163303610191578161101061101d9361101893611a7b565b6005546112b3565b600555565b60405163e69d849d60e01b60208201526001600160a01b038316602482015260448035908201527f000000000000000000000000e903f5a1d43d93407bcd11c771c03628539414d29190911691906110788160648101610d3f565b823b156101a3576110a3926000928360405180968195829463a68a299760e01b8452600484016116c7565b03925af18015610c89576110b357005b80610cda61001992610790565b346101a35760803660031901126101a35760405160208101906004356110e5816106e8565b6001600160a01b039081168352806024356110ff816106e8565b166040830152604435611111816106e8565b16606082015260643560808201526080815261112c816107a3565b519020600052600260205260206001600160601b0360406000205416604051908152f35b346101a35760203660031901126101a35760043561116d816106e8565b60018060a01b03166000526001602052602060ff604060002054166040519015158152f35b346101a35760403660031901126101a3576004356111af816106e8565b3033036101915761001990602435907f000000000000000000000000e903f5a1d43d93407bcd11c771c03628539414d290611c50565b346101a35760203660031901126101a357600435611202816106e8565b6000805490916001600160a01b039061121e33838516146112cc565b1680916001600160601b0360a01b16178255337f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08380a380f35b346101a35760003660031901126101a3576040517f000000000000000000000000e903f5a1d43d93407bcd11c771c03628539414d26001600160a01b03168152602090f35b634e487b7160e01b600052601160045260246000fd5b81810392916000138015828513169184121617610fa757565b156112d357565b60405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b6044820152606490fd5b903590601e19813603018212156101a357018035906001600160401b0382116101a357602001918160051b360383136101a357565b903590601e19813603018212156101a357018035906001600160401b0382116101a357602001918160071b360383136101a357565b6001600160401b03811161078b5760051b60200190565b9061139282611371565b6040906113a260405191826107be565b83815280936113b3601f1991611371565b019060009260005b8381106113c9575050505050565b81519060808201918083106001600160401b0384111761078b57602092845286815282878183015287858301526060808301528286010152016113bb565b9061141182611371565b61141e60405191826107be565b828152809261142f601f1991611371565b0190602036910137565b634e487b7160e01b600052603260045260246000fd5b919081101561145f5760051b0190565b611439565b805182101561145f5760209160051b010190565b919081101561145f5760071b0190565b9061149282611371565b6040906114a260405191826107be565b83815280936114b3601f1991611371565b019160009060005b8481106114c9575050505050565b60209082516114d781610770565b8481528285818301528287010152016114bb565b356114f5816106e8565b90565b9060018201809211610fa757565b91908201809211610fa757565b91903033036101915760018060a01b03807f000000000000000000000000e903f5a1d43d93407bcd11c771c03628539414d21690602081855116940151823b156101a3576001600160601b039561159f600096928793604051998a9889978896636f4342cb60e01b885216600487015216602485015260448401526080606484015260848301906115bd565b03925af18015610c89576115b05750565b80610cda6107ec92610790565b919082519283825260005b8481106115e9575050826000602080949584010152601f8019910116010190565b6020818301810151848301820152016115c8565b6040513d6000823e3d90fd5b356114f581610749565b903590603e19813603018212156101a3570190565b908060209392818452848401376000828201840152601f01601f1916010190565b6001600160a01b0391821681526001600160601b03909216602083015260606040830152909190813561167b816106e8565b1660608301526020810135601e19823603018112156101a35701602081359101906001600160401b0381116101a35780360382136101a35760a083604060806114f59601520191611628565b6001600160a01b0390911681526040602082018190526114f5929101906115bd565b903590601e19813603018212156101a357018035906001600160401b0382116101a3576020019181360383136101a357565b906114f595936001600160601b0360809460018060a01b0380941685521660208401521660408201528160608201520191611628565b91908203918211610fa757565b91908260409103126101a3576020825192015190565b6001600160a01b039182168152911660208201526060604082018190526114f593910191611628565b9061ffff80921661271003918211610fa757565b6000809160208151910182305af1903d15611814573d916117d1836107ee565b926117df60405194856107be565b83523d6000602085013e5b61181057508051156117fe57602081519101fd5b60405163fe50217960e01b8152600490fd5b9050565b6060916117ea565b60009160005b81811061184d575050506003540361183b576000600355565b60405163be364e3b60e01b8152600490fd5b61185b610bff828486611478565b604080516020810196875280820183905290959061187c8160608101610d3f565b5190209461189a6109c461099d846000526002602052604060002090565b6118a8575050600101611822565b516318fdea5360e21b8152600481019190915260249150fd5b6040516060602082019280356118d6816106e8565b6001600160a01b0390811685528060208301356118f2816106e8565b1660408501526040820135611906816106e8565b1682840152013560808201526080815261191f816107a3565b51902090565b6000906001600160a01b039081169081611940575050503190565b6024602092939460405194859384926370a0823160e01b84521660048301525afa918215610c8957809261197357505090565b9091506020823d60201161199f575b8161198f602093836107be565b8101031261199c57505190565b80fd5b3d9150611982565b6fffffffffffffffffffffffffffffffff811160801b158202156101a35760801b0490565b9061271091816000190481118202158302156101a357020490565b600160601b8110156101a3576001600160601b031690565b611a08906118c1565b60005260026020526040600020906001600160601b0390818084541691169003908111610fa75781546bffffffffffffffffffffffff19166001600160601b03909116179055565b919081101561145f5760a0020190565b9190916001600160601b0380809416911601918211610fa757565b906003549160005b828110611a9257505050600355565b611aa86109c4611aa3838686611a50565b611609565b15611c4857611ab8818484611a50565b60209081810191611ac8836114eb565b92604091611aee83850195611adc876114eb565b6001600160a01b039182169116141590565b8015611c3a575b611b09575b50505050506001905b01611a83565b611b12826118c1565b8351918201998a5260208a018190529890806040830103601f1981018252611b3a90826107be565b51902097611b49868989611a50565b611b5290611609565b90611b67906000526002602052604060002090565b908154611b7a906001600160601b031690565b90611b8491611a60565b81546bffffffffffffffffffffffff19166001600160601b03909116179055611bae858888611a50565b611bb790611609565b90611bc1906114eb565b93611bcb906114eb565b90611bd8606085016114eb565b92516001600160601b039190911681526001600160a01b0391821660208201526080939093013560408401529081169216907fd78bb599a4097286457bdc72d494e5de820aa40e1222bd19b1289440e7fa6cdf90606090a33880808080611afa565b504660808501351415611af5565b600190611b03565b8215611ce3576001600160a01b03818116611c8f57505060008080611c779481945af11590565b611c7d57565b604051633d2cec6f60e21b8152600490fd5b60209260008093611ccb966044946040519463a9059cbb60e01b865216600485015260248401525af1600051600114601f3d11163d1517161590565b611cd157565b604051633c9fd93960e21b8152600490fd5b50505056
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000de4d377d8a8d455330edd7c4eb5b284ada1113d8000000000000000000000000e903f5a1d43d93407bcd11c771c03628539414d20000000000000000000000008dd78e46642e14858f25aaa41b2b36c0bd6b444f000000000000000000000000c44f324e5c7606ce5864b253f3eb08be0f27038c000000000000000000000000000000000000000000000000000000000000012c
-----Decoded View---------------
Arg [0] : _owner (address): 0xdE4D377D8A8d455330edD7C4EB5b284ADA1113d8
Arg [1] : _vault (address): 0xE903F5a1D43d93407Bcd11c771c03628539414d2
Arg [2] : _messenger (address): 0x8dD78e46642e14858F25Aaa41B2B36c0bd6B444F
Arg [3] : _priceOracle (address): 0xC44f324e5c7606Ce5864B253F3EB08be0f27038C
Arg [4] : _maxSlippageInBP (uint16): 300
-----Encoded View---------------
5 Constructor Arguments found :
Arg [0] : 000000000000000000000000de4d377d8a8d455330edd7c4eb5b284ada1113d8
Arg [1] : 000000000000000000000000e903f5a1d43d93407bcd11c771c03628539414d2
Arg [2] : 0000000000000000000000008dd78e46642e14858f25aaa41b2b36c0bd6b444f
Arg [3] : 000000000000000000000000c44f324e5c7606ce5864b253f3eb08be0f27038c
Arg [4] : 000000000000000000000000000000000000000000000000000000000000012c
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.