Overview
ETH Balance
ETH Value
$0.00Latest 25 from a total of 223 transactions
| Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Update Exchange ... | 16082326 | 11 hrs ago | IN | 0 ETH | 0.00000005 | ||||
| Update Exchange ... | 16039127 | 35 hrs ago | IN | 0 ETH | 0.00000005 | ||||
| Update Exchange ... | 15995944 | 2 days ago | IN | 0 ETH | 0.00000005 | ||||
| Update Exchange ... | 15952719 | 3 days ago | IN | 0 ETH | 0.00000005 | ||||
| Update Exchange ... | 15909519 | 4 days ago | IN | 0 ETH | 0.00000005 | ||||
| Update Exchange ... | 15866321 | 5 days ago | IN | 0 ETH | 0.00000005 | ||||
| Update Exchange ... | 15823120 | 6 days ago | IN | 0 ETH | 0.00000005 | ||||
| Update Exchange ... | 15779926 | 7 days ago | IN | 0 ETH | 0.00000005 | ||||
| Update Exchange ... | 15736720 | 8 days ago | IN | 0 ETH | 0.00000005 | ||||
| Update Exchange ... | 15693519 | 9 days ago | IN | 0 ETH | 0.00000005 | ||||
| Update Exchange ... | 15650321 | 10 days ago | IN | 0 ETH | 0.00000005 | ||||
| Update Exchange ... | 15607120 | 11 days ago | IN | 0 ETH | 0.00000005 | ||||
| Update Exchange ... | 15563926 | 12 days ago | IN | 0 ETH | 0.00000005 | ||||
| Update Exchange ... | 15520725 | 13 days ago | IN | 0 ETH | 0.00000005 | ||||
| Update Exchange ... | 15477519 | 14 days ago | IN | 0 ETH | 0.00000005 | ||||
| Update Exchange ... | 15434320 | 15 days ago | IN | 0 ETH | 0.00000005 | ||||
| Update Exchange ... | 15391120 | 16 days ago | IN | 0 ETH | 0.00000005 | ||||
| Update Exchange ... | 15347920 | 17 days ago | IN | 0 ETH | 0.00000005 | ||||
| Update Exchange ... | 15304735 | 18 days ago | IN | 0 ETH | 0.00000005 | ||||
| Update Exchange ... | 15261520 | 19 days ago | IN | 0 ETH | 0.00000005 | ||||
| Update Exchange ... | 15218320 | 20 days ago | IN | 0 ETH | 0.00000005 | ||||
| Update Exchange ... | 15175116 | 21 days ago | IN | 0 ETH | 0.00000005 | ||||
| Update Exchange ... | 15131920 | 22 days ago | IN | 0 ETH | 0.00000005 | ||||
| Update Exchange ... | 15088726 | 23 days ago | IN | 0 ETH | 0.00000005 | ||||
| Update Exchange ... | 15045520 | 24 days ago | IN | 0 ETH | 0.00000005 |
Latest 1 internal transaction
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 507027 | 361 days ago | Contract Creation | 0 ETH |
Cross-Chain Transactions
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity 0.8.21;
import { FixedPointMathLib } from "@solmate/utils/FixedPointMathLib.sol";
import { IRateProvider } from "src/interfaces/IRateProvider.sol";
import { ERC20 } from "@solmate/tokens/ERC20.sol";
import { SafeTransferLib } from "@solmate/utils/SafeTransferLib.sol";
import { BoringVault } from "src/base/BoringVault.sol";
import { Auth, Authority } from "@solmate/auth/Auth.sol";
/**
* @title AccountantWithRateProviders
* @custom:security-contact [email protected]
*/
contract AccountantWithRateProviders is Auth, IRateProvider {
using FixedPointMathLib for uint256;
using SafeTransferLib for ERC20;
// ========================================= STRUCTS =========================================
/**
* @param payoutAddress the address `claimFees` sends fees to
* @param feesOwedInBase total pending fees owed in terms of base
* @param totalSharesLastUpdate total amount of shares the last exchange rate update
* @param exchangeRate the current exchange rate in terms of base
* @param allowedExchangeRateChangeUpper the max allowed change to exchange rate from an update
* @param allowedExchangeRateChangeLower the min allowed change to exchange rate from an update
* @param lastUpdateTimestamp the block timestamp of the last exchange rate update
* @param isPaused whether or not this contract is paused
* @param minimumUpdateDelayInSeconds the minimum amount of time that must pass between
* exchange rate updates, such that the update won't trigger the contract to be paused
* @param managementFee the management fee
*/
struct AccountantState {
address payoutAddress;
uint128 feesOwedInBase;
uint128 totalSharesLastUpdate;
uint96 exchangeRate;
uint16 allowedExchangeRateChangeUpper;
uint16 allowedExchangeRateChangeLower;
uint64 lastUpdateTimestamp;
bool isPaused;
uint32 minimumUpdateDelayInSeconds;
uint16 managementFee;
}
/**
* @param isPeggedToBase whether or not the asset is 1:1 with the base asset
* @param rateProvider the rate provider for this asset if `isPeggedToBase` is false
*/
struct RateProviderData {
bool isPeggedToBase;
IRateProvider rateProvider;
}
// ========================================= STATE =========================================
/**
* @notice Store the accountant state in 3 packed slots.
*/
AccountantState public accountantState;
/**
* @notice Maps ERC20s to their RateProviderData.
*/
mapping(ERC20 => RateProviderData) public rateProviderData;
//============================== ERRORS ===============================
error AccountantWithRateProviders__UpperBoundTooSmall();
error AccountantWithRateProviders__LowerBoundTooLarge();
error AccountantWithRateProviders__ManagementFeeTooLarge();
error AccountantWithRateProviders__Paused();
error AccountantWithRateProviders__ZeroFeesOwed();
error AccountantWithRateProviders__OnlyCallableByBoringVault();
error AccountantWithRateProviders__UpdateDelayTooLarge();
//============================== EVENTS ===============================
event Paused();
event Unpaused();
event DelayInSecondsUpdated(uint32 oldDelay, uint32 newDelay);
event UpperBoundUpdated(uint16 oldBound, uint16 newBound);
event LowerBoundUpdated(uint16 oldBound, uint16 newBound);
event ManagementFeeUpdated(uint16 oldFee, uint16 newFee);
event PayoutAddressUpdated(address oldPayout, address newPayout);
event RateProviderUpdated(address asset, bool isPegged, address rateProvider);
event ExchangeRateUpdated(uint96 oldRate, uint96 newRate, uint64 currentTime);
event FeesClaimed(address indexed feeAsset, uint256 amount);
//============================== IMMUTABLES ===============================
/**
* @notice The base asset rates are provided in.
*/
ERC20 public immutable base;
/**
* @notice The decimals rates are provided in.
*/
uint8 public immutable decimals;
/**
* @notice The BoringVault this accountant is working with.
* Used to determine share supply for fee calculation.
*/
BoringVault public immutable vault;
/**
* @notice One share of the BoringVault.
*/
uint256 internal immutable ONE_SHARE;
constructor(
address _owner,
address _vault,
address payoutAddress,
uint96 startingExchangeRate,
address _base,
uint16 allowedExchangeRateChangeUpper,
uint16 allowedExchangeRateChangeLower,
uint32 minimumUpdateDelayInSeconds,
uint16 managementFee
)
Auth(_owner, Authority(address(0)))
{
base = ERC20(_base);
decimals = ERC20(_base).decimals();
vault = BoringVault(payable(_vault));
ONE_SHARE = 10 ** vault.decimals();
accountantState = AccountantState({
payoutAddress: payoutAddress,
feesOwedInBase: 0,
totalSharesLastUpdate: uint128(vault.totalSupply()),
exchangeRate: startingExchangeRate,
allowedExchangeRateChangeUpper: allowedExchangeRateChangeUpper,
allowedExchangeRateChangeLower: allowedExchangeRateChangeLower,
lastUpdateTimestamp: uint64(block.timestamp),
isPaused: false,
minimumUpdateDelayInSeconds: minimumUpdateDelayInSeconds,
managementFee: managementFee
});
}
// ========================================= ADMIN FUNCTIONS =========================================
/**
* @notice Pause this contract, which prevents future calls to `updateExchangeRate`, and any safe rate
* calls will revert.
* @dev Callable by MULTISIG_ROLE.
*/
function pause() external requiresAuth {
accountantState.isPaused = true;
emit Paused();
}
/**
* @notice Unpause this contract, which allows future calls to `updateExchangeRate`, and any safe rate
* calls will stop reverting.
* @dev Callable by MULTISIG_ROLE.
*/
function unpause() external requiresAuth {
accountantState.isPaused = false;
emit Unpaused();
}
/**
* @notice Update the minimum time delay between `updateExchangeRate` calls.
* @dev There are no input requirements, as it is possible the admin would want
* the exchange rate updated as frequently as needed.
* @dev Callable by OWNER_ROLE.
*/
function updateDelay(uint32 minimumUpdateDelayInSeconds) external requiresAuth {
if (minimumUpdateDelayInSeconds > 14 days) revert AccountantWithRateProviders__UpdateDelayTooLarge();
uint32 oldDelay = accountantState.minimumUpdateDelayInSeconds;
accountantState.minimumUpdateDelayInSeconds = minimumUpdateDelayInSeconds;
emit DelayInSecondsUpdated(oldDelay, minimumUpdateDelayInSeconds);
}
/**
* @notice Update the allowed upper bound change of exchange rate between `updateExchangeRateCalls`.
* @dev Callable by OWNER_ROLE.
*/
function updateUpper(uint16 allowedExchangeRateChangeUpper) external requiresAuth {
if (allowedExchangeRateChangeUpper < 1e4) revert AccountantWithRateProviders__UpperBoundTooSmall();
uint16 oldBound = accountantState.allowedExchangeRateChangeUpper;
accountantState.allowedExchangeRateChangeUpper = allowedExchangeRateChangeUpper;
emit UpperBoundUpdated(oldBound, allowedExchangeRateChangeUpper);
}
/**
* @notice Update the allowed lower bound change of exchange rate between `updateExchangeRateCalls`.
* @dev Callable by OWNER_ROLE.
*/
function updateLower(uint16 allowedExchangeRateChangeLower) external requiresAuth {
if (allowedExchangeRateChangeLower > 1e4) revert AccountantWithRateProviders__LowerBoundTooLarge();
uint16 oldBound = accountantState.allowedExchangeRateChangeLower;
accountantState.allowedExchangeRateChangeLower = allowedExchangeRateChangeLower;
emit LowerBoundUpdated(oldBound, allowedExchangeRateChangeLower);
}
/**
* @notice Update the management fee to a new value.
* @dev Callable by OWNER_ROLE.
*/
function updateManagementFee(uint16 managementFee) external requiresAuth {
if (managementFee > 0.2e4) revert AccountantWithRateProviders__ManagementFeeTooLarge();
uint16 oldFee = accountantState.managementFee;
accountantState.managementFee = managementFee;
emit ManagementFeeUpdated(oldFee, managementFee);
}
/**
* @notice Update the payout address fees are sent to.
* @dev Callable by OWNER_ROLE.
*/
function updatePayoutAddress(address payoutAddress) external requiresAuth {
address oldPayout = accountantState.payoutAddress;
accountantState.payoutAddress = payoutAddress;
emit PayoutAddressUpdated(oldPayout, payoutAddress);
}
/**
* @notice Update the rate provider data for a specific `asset`.
* @dev Rate providers must return rates in terms of `base` or
* an asset pegged to base and they must use the same decimals
* as `asset`.
* @dev Callable by OWNER_ROLE.
*/
function setRateProviderData(ERC20 asset, bool isPeggedToBase, address rateProvider) external requiresAuth {
rateProviderData[asset] =
RateProviderData({ isPeggedToBase: isPeggedToBase, rateProvider: IRateProvider(rateProvider) });
emit RateProviderUpdated(address(asset), isPeggedToBase, rateProvider);
}
// ========================================= UPDATE EXCHANGE RATE/FEES FUNCTIONS
// =========================================
/**
* @notice Updates this contract exchangeRate.
* @dev If new exchange rate is outside of accepted bounds, or if not enough time has passed, this
* will pause the contract, and this function will NOT calculate fees owed.
* @dev Callable by UPDATE_EXCHANGE_RATE_ROLE.
*/
function updateExchangeRate(uint96 newExchangeRate) external requiresAuth {
AccountantState storage state = accountantState;
if (state.isPaused) revert AccountantWithRateProviders__Paused();
uint64 currentTime = uint64(block.timestamp);
uint256 currentExchangeRate = state.exchangeRate;
uint256 currentTotalShares = vault.totalSupply();
if (
currentTime < state.lastUpdateTimestamp + state.minimumUpdateDelayInSeconds
|| newExchangeRate > currentExchangeRate.mulDivDown(state.allowedExchangeRateChangeUpper, 1e4)
|| newExchangeRate < currentExchangeRate.mulDivDown(state.allowedExchangeRateChangeLower, 1e4)
) {
// Instead of reverting, pause the contract. This way the exchange rate updater is able to update the
// exchange rate
// to a better value, and pause it.
state.isPaused = true;
} else {
// Only update fees if we are not paused.
// Update fee accounting.
uint256 shareSupplyToUse = currentTotalShares;
// Use the minimum between current total supply and total supply for last update.
if (state.totalSharesLastUpdate < shareSupplyToUse) {
shareSupplyToUse = state.totalSharesLastUpdate;
}
// Determine management fees owned.
uint256 timeDelta = currentTime - state.lastUpdateTimestamp;
uint256 minimumAssets = newExchangeRate > currentExchangeRate
? shareSupplyToUse.mulDivDown(currentExchangeRate, ONE_SHARE)
: shareSupplyToUse.mulDivDown(newExchangeRate, ONE_SHARE);
uint256 managementFeesAnnual = minimumAssets.mulDivDown(state.managementFee, 1e4);
uint256 newFeesOwedInBase = managementFeesAnnual.mulDivDown(timeDelta, 365 days);
state.feesOwedInBase += uint128(newFeesOwedInBase);
}
state.exchangeRate = newExchangeRate;
state.totalSharesLastUpdate = uint128(currentTotalShares);
state.lastUpdateTimestamp = currentTime;
emit ExchangeRateUpdated(uint96(currentExchangeRate), newExchangeRate, currentTime);
}
/**
* @notice Claim pending fees.
* @dev This function must be called by the BoringVault.
* @dev This function will lose precision if the exchange rate
* decimals is greater than the feeAsset's decimals.
*/
function claimFees(ERC20 feeAsset) external {
if (msg.sender != address(vault)) revert AccountantWithRateProviders__OnlyCallableByBoringVault();
AccountantState storage state = accountantState;
if (state.isPaused) revert AccountantWithRateProviders__Paused();
if (state.feesOwedInBase == 0) revert AccountantWithRateProviders__ZeroFeesOwed();
// Determine amount of fees owed in feeAsset.
uint256 feesOwedInFeeAsset;
RateProviderData memory data = rateProviderData[feeAsset];
if (address(feeAsset) == address(base)) {
feesOwedInFeeAsset = state.feesOwedInBase;
} else {
uint8 feeAssetDecimals = ERC20(feeAsset).decimals();
uint256 feesOwedInBaseUsingFeeAssetDecimals =
changeDecimals(state.feesOwedInBase, decimals, feeAssetDecimals);
if (data.isPeggedToBase) {
feesOwedInFeeAsset = feesOwedInBaseUsingFeeAssetDecimals;
} else {
uint256 rate = data.rateProvider.getRate();
feesOwedInFeeAsset = feesOwedInBaseUsingFeeAssetDecimals.mulDivDown(10 ** feeAssetDecimals, rate);
}
}
// Zero out fees owed.
state.feesOwedInBase = 0;
// Transfer fee asset to payout address.
feeAsset.safeTransferFrom(msg.sender, state.payoutAddress, feesOwedInFeeAsset);
emit FeesClaimed(address(feeAsset), feesOwedInFeeAsset);
}
// ========================================= RATE FUNCTIONS =========================================
/**
* @notice Get this BoringVault's current rate in the base.
*/
function getRate() public view returns (uint256 rate) {
rate = accountantState.exchangeRate;
}
/**
* @notice Get this BoringVault's current rate in the base.
* @dev Revert if paused.
*/
function getRateSafe() external view returns (uint256 rate) {
if (accountantState.isPaused) revert AccountantWithRateProviders__Paused();
rate = getRate();
}
/**
* @notice Get this BoringVault's current rate in the provided quote.
* @dev `quote` must have its RateProviderData set, else this will revert.
* @dev This function will lose precision if the exchange rate
* decimals is greater than the quote's decimals.
*/
function getRateInQuote(ERC20 quote) public view returns (uint256 rateInQuote) {
if (address(quote) == address(base)) {
rateInQuote = accountantState.exchangeRate;
} else {
RateProviderData memory data = rateProviderData[quote];
uint8 quoteDecimals = ERC20(quote).decimals();
uint256 exchangeRateInQuoteDecimals = changeDecimals(accountantState.exchangeRate, decimals, quoteDecimals);
if (data.isPeggedToBase) {
rateInQuote = exchangeRateInQuoteDecimals;
} else {
uint256 quoteRate = data.rateProvider.getRate();
uint256 oneQuote = 10 ** quoteDecimals;
rateInQuote = oneQuote.mulDivDown(exchangeRateInQuoteDecimals, quoteRate);
}
}
}
/**
* @notice Get this BoringVault's current rate in the provided quote.
* @dev `quote` must have its RateProviderData set, else this will revert.
* @dev Revert if paused.
*/
function getRateInQuoteSafe(ERC20 quote) external view returns (uint256 rateInQuote) {
if (accountantState.isPaused) revert AccountantWithRateProviders__Paused();
rateInQuote = getRateInQuote(quote);
}
// ========================================= INTERNAL HELPER FUNCTIONS =========================================
/**
* @notice Used to change the decimals of precision used for an amount.
*/
function changeDecimals(uint256 amount, uint8 fromDecimals, uint8 toDecimals) internal pure returns (uint256) {
if (fromDecimals == toDecimals) {
return amount;
} else if (fromDecimals < toDecimals) {
return amount * 10 ** (toDecimals - fromDecimals);
} else {
return amount / 10 ** (fromDecimals - toDecimals);
}
}
}// 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: GPL-3.0-or-later
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
pragma solidity ^0.8.0;
interface IRateProvider {
function getRate() external view returns (uint256);
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol)
/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)
/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.
abstract contract ERC20 {
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/
event Transfer(address indexed from, address indexed to, uint256 amount);
event Approval(address indexed owner, address indexed spender, uint256 amount);
/*//////////////////////////////////////////////////////////////
METADATA STORAGE
//////////////////////////////////////////////////////////////*/
string public name;
string public symbol;
uint8 public immutable decimals;
/*//////////////////////////////////////////////////////////////
ERC20 STORAGE
//////////////////////////////////////////////////////////////*/
uint256 public totalSupply;
mapping(address => uint256) public balanceOf;
mapping(address => mapping(address => uint256)) public allowance;
/*//////////////////////////////////////////////////////////////
EIP-2612 STORAGE
//////////////////////////////////////////////////////////////*/
uint256 internal immutable INITIAL_CHAIN_ID;
bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;
mapping(address => uint256) public nonces;
/*//////////////////////////////////////////////////////////////
CONSTRUCTOR
//////////////////////////////////////////////////////////////*/
constructor(
string memory _name,
string memory _symbol,
uint8 _decimals
) {
name = _name;
symbol = _symbol;
decimals = _decimals;
INITIAL_CHAIN_ID = block.chainid;
INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
}
/*//////////////////////////////////////////////////////////////
ERC20 LOGIC
//////////////////////////////////////////////////////////////*/
function approve(address spender, uint256 amount) public virtual returns (bool) {
allowance[msg.sender][spender] = amount;
emit Approval(msg.sender, spender, amount);
return true;
}
function transfer(address to, uint256 amount) public virtual returns (bool) {
balanceOf[msg.sender] -= amount;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += amount;
}
emit Transfer(msg.sender, to, amount);
return true;
}
function transferFrom(
address from,
address to,
uint256 amount
) public virtual returns (bool) {
uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.
if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;
balanceOf[from] -= amount;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += amount;
}
emit Transfer(from, to, amount);
return true;
}
/*//////////////////////////////////////////////////////////////
EIP-2612 LOGIC
//////////////////////////////////////////////////////////////*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) public virtual {
require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED");
// Unchecked because the only math done is incrementing
// the owner's nonce which cannot realistically overflow.
unchecked {
address recoveredAddress = ecrecover(
keccak256(
abi.encodePacked(
"\x19\x01",
DOMAIN_SEPARATOR(),
keccak256(
abi.encode(
keccak256(
"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
),
owner,
spender,
value,
nonces[owner]++,
deadline
)
)
)
),
v,
r,
s
);
require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER");
allowance[recoveredAddress][spender] = value;
}
emit Approval(owner, spender, value);
}
function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();
}
function computeDomainSeparator() internal view virtual returns (bytes32) {
return
keccak256(
abi.encode(
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
keccak256(bytes(name)),
keccak256("1"),
block.chainid,
address(this)
)
);
}
/*//////////////////////////////////////////////////////////////
INTERNAL MINT/BURN LOGIC
//////////////////////////////////////////////////////////////*/
function _mint(address to, uint256 amount) internal virtual {
totalSupply += amount;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += amount;
}
emit Transfer(address(0), to, amount);
}
function _burn(address from, uint256 amount) internal virtual {
balanceOf[from] -= amount;
// Cannot underflow because a user's balance
// will never be larger than the total supply.
unchecked {
totalSupply -= amount;
}
emit Transfer(from, address(0), amount);
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
import {ERC20} from "../tokens/ERC20.sol";
/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)
/// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer.
/// @dev Note that none of the functions in this library check that a token has code at all! That responsibility is delegated to the caller.
library SafeTransferLib {
/*//////////////////////////////////////////////////////////////
ETH OPERATIONS
//////////////////////////////////////////////////////////////*/
function safeTransferETH(address to, uint256 amount) internal {
bool success;
/// @solidity memory-safe-assembly
assembly {
// Transfer the ETH and store if it succeeded or not.
success := call(gas(), to, amount, 0, 0, 0, 0)
}
require(success, "ETH_TRANSFER_FAILED");
}
/*//////////////////////////////////////////////////////////////
ERC20 OPERATIONS
//////////////////////////////////////////////////////////////*/
function safeTransferFrom(
ERC20 token,
address from,
address to,
uint256 amount
) internal {
bool success;
/// @solidity memory-safe-assembly
assembly {
// Get a pointer to some free memory.
let freeMemoryPointer := mload(0x40)
// Write the abi-encoded calldata into memory, beginning with the function selector.
mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
mstore(add(freeMemoryPointer, 4), and(from, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "from" argument.
mstore(add(freeMemoryPointer, 36), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.
mstore(add(freeMemoryPointer, 68), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.
success := and(
// Set success to whether the call reverted, if not we check it either
// returned exactly 1 (can't just be non-zero data), or had no return data.
or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
// We use 100 because the length of our calldata totals up like so: 4 + 32 * 3.
// We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
// Counterintuitively, this call must be positioned second to the or() call in the
// surrounding and() call or else returndatasize() will be zero during the computation.
call(gas(), token, 0, freeMemoryPointer, 100, 0, 32)
)
}
require(success, "TRANSFER_FROM_FAILED");
}
function safeTransfer(
ERC20 token,
address to,
uint256 amount
) internal {
bool success;
/// @solidity memory-safe-assembly
assembly {
// Get a pointer to some free memory.
let freeMemoryPointer := mload(0x40)
// Write the abi-encoded calldata into memory, beginning with the function selector.
mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)
mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.
mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.
success := and(
// Set success to whether the call reverted, if not we check it either
// returned exactly 1 (can't just be non-zero data), or had no return data.
or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
// We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
// We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
// Counterintuitively, this call must be positioned second to the or() call in the
// surrounding and() call or else returndatasize() will be zero during the computation.
call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
)
}
require(success, "TRANSFER_FAILED");
}
function safeApprove(
ERC20 token,
address to,
uint256 amount
) internal {
bool success;
/// @solidity memory-safe-assembly
assembly {
// Get a pointer to some free memory.
let freeMemoryPointer := mload(0x40)
// Write the abi-encoded calldata into memory, beginning with the function selector.
mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000)
mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.
mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.
success := and(
// Set success to whether the call reverted, if not we check it either
// returned exactly 1 (can't just be non-zero data), or had no return data.
or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
// We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
// We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
// Counterintuitively, this call must be positioned second to the or() call in the
// surrounding and() call or else returndatasize() will be zero during the computation.
call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
)
}
require(success, "APPROVE_FAILED");
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.21;
import { Address } from "@openzeppelin/contracts/utils/Address.sol";
import { ERC721Holder } from "@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol";
import { ERC1155Holder } from "@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol";
import { FixedPointMathLib } from "@solmate/utils/FixedPointMathLib.sol";
import { SafeTransferLib } from "@solmate/utils/SafeTransferLib.sol";
import { ERC20 } from "@solmate/tokens/ERC20.sol";
import { BeforeTransferHook } from "src/interfaces/BeforeTransferHook.sol";
import { Auth, Authority } from "@solmate/auth/Auth.sol";
/**
* @title BoringVault
* @custom:security-contact [email protected]
*/
contract BoringVault is ERC20, Auth, ERC721Holder, ERC1155Holder {
using Address for address;
using SafeTransferLib for ERC20;
using FixedPointMathLib for uint256;
// ========================================= STATE =========================================
/**
* @notice Contract responsible for implementing `beforeTransfer`.
*/
BeforeTransferHook public hook;
//============================== EVENTS ===============================
event Enter(address indexed from, address indexed asset, uint256 amount, address indexed to, uint256 shares);
event Exit(address indexed to, address indexed asset, uint256 amount, address indexed from, uint256 shares);
//============================== CONSTRUCTOR ===============================
constructor(
address _owner,
string memory _name,
string memory _symbol,
uint8 _decimals
)
ERC20(_name, _symbol, _decimals)
Auth(_owner, Authority(address(0)))
{ }
//============================== MANAGE ===============================
/**
* @notice Allows manager to make an arbitrary function call from this contract.
* @dev Callable by MANAGER_ROLE.
*/
function manage(
address target,
bytes calldata data,
uint256 value
)
external
requiresAuth
returns (bytes memory result)
{
result = target.functionCallWithValue(data, value);
}
/**
* @notice Allows manager to make arbitrary function calls from this contract.
* @dev Callable by MANAGER_ROLE.
*/
function manage(
address[] calldata targets,
bytes[] calldata data,
uint256[] calldata values
)
external
requiresAuth
returns (bytes[] memory results)
{
uint256 targetsLength = targets.length;
results = new bytes[](targetsLength);
for (uint256 i; i < targetsLength; ++i) {
results[i] = targets[i].functionCallWithValue(data[i], values[i]);
}
}
//============================== ENTER ===============================
/**
* @notice Allows minter to mint shares, in exchange for assets.
* @dev If assetAmount is zero, no assets are transferred in.
* @dev Callable by MINTER_ROLE.
*/
function enter(
address from,
ERC20 asset,
uint256 assetAmount,
address to,
uint256 shareAmount
)
external
requiresAuth
{
// Transfer assets in
if (assetAmount > 0) asset.safeTransferFrom(from, address(this), assetAmount);
// Mint shares.
_mint(to, shareAmount);
emit Enter(from, address(asset), assetAmount, to, shareAmount);
}
//============================== EXIT ===============================
/**
* @notice Allows burner to burn shares, in exchange for assets.
* @dev If assetAmount is zero, no assets are transferred out.
* @dev Callable by BURNER_ROLE.
*/
function exit(
address to,
ERC20 asset,
uint256 assetAmount,
address from,
uint256 shareAmount
)
external
requiresAuth
{
// Burn shares.
_burn(from, shareAmount);
// Transfer assets out.
if (assetAmount > 0) asset.safeTransfer(to, assetAmount);
emit Exit(to, address(asset), assetAmount, from, shareAmount);
}
//============================== BEFORE TRANSFER HOOK ===============================
/**
* @notice Sets the share locker.
* @notice If set to zero address, the share locker logic is disabled.
* @dev Callable by OWNER_ROLE.
*/
function setBeforeTransferHook(address _hook) external requiresAuth {
hook = BeforeTransferHook(_hook);
}
/**
* @notice Check if from addresses shares are locked, reverting if so.
*/
function _callBeforeTransfer(address from) internal view {
if (address(hook) != address(0)) hook.beforeTransfer(from);
}
function transfer(address to, uint256 amount) public override returns (bool) {
_callBeforeTransfer(msg.sender);
return super.transfer(to, amount);
}
function transferFrom(address from, address to, uint256 amount) public override returns (bool) {
_callBeforeTransfer(from);
return super.transferFrom(from, to, amount);
}
//============================== RECEIVE ===============================
receive() external payable { }
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
/// @notice Provides a flexible and updatable auth pattern which is completely separate from application logic.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/auth/Auth.sol)
/// @author Modified from Dappsys (https://github.com/dapphub/ds-auth/blob/master/src/auth.sol)
abstract contract Auth {
event OwnershipTransferred(address indexed user, address indexed newOwner);
event AuthorityUpdated(address indexed user, Authority indexed newAuthority);
address public owner;
Authority public authority;
constructor(address _owner, Authority _authority) {
owner = _owner;
authority = _authority;
emit OwnershipTransferred(msg.sender, _owner);
emit AuthorityUpdated(msg.sender, _authority);
}
modifier requiresAuth() virtual {
require(isAuthorized(msg.sender, msg.sig), "UNAUTHORIZED");
_;
}
function isAuthorized(address user, bytes4 functionSig) internal view virtual returns (bool) {
Authority auth = authority; // Memoizing authority saves us a warm SLOAD, around 100 gas.
// Checking if the caller is the owner only after calling the authority saves gas in most cases, but be
// aware that this makes protected functions uncallable even to the owner if the authority is out of order.
return (address(auth) != address(0) && auth.canCall(user, address(this), functionSig)) || user == owner;
}
function setAuthority(Authority newAuthority) public virtual {
// We check if the caller is the owner first because we want to ensure they can
// always swap out the authority even if it's reverting or using up a lot of gas.
require(msg.sender == owner || authority.canCall(msg.sender, address(this), msg.sig));
authority = newAuthority;
emit AuthorityUpdated(msg.sender, newAuthority);
}
function transferOwnership(address newOwner) public virtual requiresAuth {
owner = newOwner;
emit OwnershipTransferred(msg.sender, newOwner);
}
}
/// @notice A generic interface for a contract which provides authorization data to an Auth instance.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/auth/Auth.sol)
/// @author Modified from Dappsys (https://github.com/dapphub/ds-auth/blob/master/src/auth.sol)
interface Authority {
function canCall(
address user,
address target,
bytes4 functionSig
) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)
pragma solidity ^0.8.20;
import {Errors} from "./Errors.sol";
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev There's no code at `target` (it is not a contract).
*/
error AddressEmptyCode(address target);
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert Errors.InsufficientBalance(address(this).balance, amount);
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert Errors.FailedCall();
}
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason or custom error, it is bubbled
* up by this function (like regular Solidity function calls). However, if
* the call reverted with no returned reason, this function reverts with a
* {Errors.FailedCall} error.
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert Errors.InsufficientBalance(address(this).balance, value);
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
* was not a contract or bubbling up the revert reason (falling back to {Errors.FailedCall}) in case
* of an unsuccessful call.
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
// only check if target is a contract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
/**
* @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
* revert reason or with a default {Errors.FailedCall} error.
*/
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
/**
* @dev Reverts with returndata if present. Otherwise reverts with {Errors.FailedCall}.
*/
function _revert(bytes memory returndata) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert Errors.FailedCall();
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/utils/ERC721Holder.sol)
pragma solidity ^0.8.20;
import {IERC721Receiver} from "../IERC721Receiver.sol";
/**
* @dev Implementation of the {IERC721Receiver} interface.
*
* Accepts all token transfers.
* Make sure the contract is able to use its token with {IERC721-safeTransferFrom}, {IERC721-approve} or
* {IERC721-setApprovalForAll}.
*/
abstract contract ERC721Holder is IERC721Receiver {
/**
* @dev See {IERC721Receiver-onERC721Received}.
*
* Always returns `IERC721Receiver.onERC721Received.selector`.
*/
function onERC721Received(address, address, uint256, bytes memory) public virtual returns (bytes4) {
return this.onERC721Received.selector;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/utils/ERC1155Holder.sol)
pragma solidity ^0.8.20;
import {IERC165, ERC165} from "../../../utils/introspection/ERC165.sol";
import {IERC1155Receiver} from "../IERC1155Receiver.sol";
/**
* @dev Simple implementation of `IERC1155Receiver` that will allow a contract to hold ERC-1155 tokens.
*
* IMPORTANT: When inheriting this contract, you must include a way to use the received tokens, otherwise they will be
* stuck.
*/
abstract contract ERC1155Holder is ERC165, IERC1155Receiver {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
return interfaceId == type(IERC1155Receiver).interfaceId || super.supportsInterface(interfaceId);
}
function onERC1155Received(
address,
address,
uint256,
uint256,
bytes memory
) public virtual override returns (bytes4) {
return this.onERC1155Received.selector;
}
function onERC1155BatchReceived(
address,
address,
uint256[] memory,
uint256[] memory,
bytes memory
) public virtual override returns (bytes4) {
return this.onERC1155BatchReceived.selector;
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.21;
interface BeforeTransferHook {
function beforeTransfer(address from) external view;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/**
* @dev Collection of common custom errors used in multiple contracts
*
* IMPORTANT: Backwards compatibility is not guaranteed in future versions of the library.
* It is recommended to avoid relying on the error API for critical functionality.
*/
library Errors {
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/
error InsufficientBalance(uint256 balance, uint256 needed);
/**
* @dev A call to an address target failed. The target may have reverted.
*/
error FailedCall();
/**
* @dev The deployment failed.
*/
error FailedDeployment();
/**
* @dev A necessary precompile is missing.
*/
error MissingPrecompile(address);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721Receiver.sol)
pragma solidity ^0.8.20;
/**
* @title ERC-721 token receiver interface
* @dev Interface for any contract that wants to support safeTransfers
* from ERC-721 asset contracts.
*/
interface IERC721Receiver {
/**
* @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
* by `operator` from `from`, this function is called.
*
* It must return its Solidity selector to confirm the token transfer.
* If any other value is returned or the interface is not implemented by the recipient, the transfer will be
* reverted.
*
* The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
*/
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC-165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/IERC1155Receiver.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../../utils/introspection/IERC165.sol";
/**
* @dev Interface that must be implemented by smart contracts in order to receive
* ERC-1155 token transfers.
*/
interface IERC1155Receiver is IERC165 {
/**
* @dev Handles the receipt of a single ERC-1155 token type. This function is
* called at the end of a `safeTransferFrom` after the balance has been updated.
*
* NOTE: To accept the transfer, this must return
* `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
* (i.e. 0xf23a6e61, or its own function selector).
*
* @param operator The address which initiated the transfer (i.e. msg.sender)
* @param from The address which previously owned the token
* @param id The ID of the token being transferred
* @param value The amount of tokens being transferred
* @param data Additional data with no specified format
* @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed
*/
function onERC1155Received(
address operator,
address from,
uint256 id,
uint256 value,
bytes calldata data
) external returns (bytes4);
/**
* @dev Handles the receipt of a multiple ERC-1155 token types. This function
* is called at the end of a `safeBatchTransferFrom` after the balances have
* been updated.
*
* NOTE: To accept the transfer(s), this must return
* `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
* (i.e. 0xbc197c81, or its own function selector).
*
* @param operator The address which initiated the batch transfer (i.e. msg.sender)
* @param from The address which previously owned the token
* @param ids An array containing ids of each token being transferred (order and length must match values array)
* @param values An array containing amounts of each token being transferred (order and length must match ids array)
* @param data Additional data with no specified format
* @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed
*/
function onERC1155BatchReceived(
address operator,
address from,
uint256[] calldata ids,
uint256[] calldata values,
bytes calldata data
) external returns (bytes4);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC-165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[ERC].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}{
"remappings": [
"@solmate/=lib/solmate/src/",
"@forge-std/=lib/forge-std/src/",
"forge-std/=lib/forge-std/src/",
"@ds-test/=lib/forge-std/lib/ds-test/src/",
"ds-test/=lib/forge-std/lib/ds-test/src/",
"@openzeppelin/=lib/openzeppelin-contracts/",
"@ion-protocol/=lib/ion-protocol/src/",
"@layerzerolabs/=node_modules/@layerzerolabs/",
"@axelar-network/=node_modules/@axelar-network/",
"@balancer-labs/v2-interfaces/=lib/ion-protocol/lib/balancer-v2-monorepo/pkg/interfaces/",
"@balancer-labs/v2-pool-stable/=lib/ion-protocol/lib/balancer-v2-monorepo/pkg/pool-stable/",
"@chainlink/=node_modules/@chainlink/",
"@eth-optimism/=node_modules/@eth-optimism/",
"@uniswap/v3-core/=lib/ion-protocol/lib/v3-core/",
"@uniswap/v3-periphery/=lib/ion-protocol/lib/v3-periphery/",
"balancer-v2-monorepo/=lib/ion-protocol/lib/",
"chainlink/=lib/ion-protocol/lib/chainlink/",
"createx/=lib/createx/src/",
"erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
"forge-safe/=lib/ion-protocol/lib/forge-safe/",
"halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/",
"hardhat-deploy/=node_modules/hardhat-deploy/",
"ion-protocol/=lib/ion-protocol/",
"openzeppelin-contracts-upgradeable/=lib/ion-protocol/lib/openzeppelin-contracts-upgradeable/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/",
"openzeppelin/=lib/createx/lib/openzeppelin-contracts/contracts/",
"pendle-core-v2-public/=lib/ion-protocol/lib/pendle-core-v2-public/contracts/",
"solady/=lib/ion-protocol/lib/solady/",
"solarray/=lib/ion-protocol/lib/solarray/src/",
"solidity-bytes-utils/=node_modules/solidity-bytes-utils/",
"solidity-stringutils/=lib/ion-protocol/lib/forge-safe/lib/surl/lib/solidity-stringutils/",
"solmate/=lib/solmate/src/",
"surl/=lib/ion-protocol/lib/forge-safe/lib/surl/",
"v3-core/=lib/ion-protocol/lib/v3-core/",
"v3-periphery/=lib/v3-periphery/contracts/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"abi"
]
}
},
"evmVersion": "shanghai",
"viaIR": false
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_vault","type":"address"},{"internalType":"address","name":"payoutAddress","type":"address"},{"internalType":"uint96","name":"startingExchangeRate","type":"uint96"},{"internalType":"address","name":"_base","type":"address"},{"internalType":"uint16","name":"allowedExchangeRateChangeUpper","type":"uint16"},{"internalType":"uint16","name":"allowedExchangeRateChangeLower","type":"uint16"},{"internalType":"uint32","name":"minimumUpdateDelayInSeconds","type":"uint32"},{"internalType":"uint16","name":"managementFee","type":"uint16"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccountantWithRateProviders__LowerBoundTooLarge","type":"error"},{"inputs":[],"name":"AccountantWithRateProviders__ManagementFeeTooLarge","type":"error"},{"inputs":[],"name":"AccountantWithRateProviders__OnlyCallableByBoringVault","type":"error"},{"inputs":[],"name":"AccountantWithRateProviders__Paused","type":"error"},{"inputs":[],"name":"AccountantWithRateProviders__UpdateDelayTooLarge","type":"error"},{"inputs":[],"name":"AccountantWithRateProviders__UpperBoundTooSmall","type":"error"},{"inputs":[],"name":"AccountantWithRateProviders__ZeroFeesOwed","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"contract Authority","name":"newAuthority","type":"address"}],"name":"AuthorityUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"oldDelay","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"newDelay","type":"uint32"}],"name":"DelayInSecondsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint96","name":"oldRate","type":"uint96"},{"indexed":false,"internalType":"uint96","name":"newRate","type":"uint96"},{"indexed":false,"internalType":"uint64","name":"currentTime","type":"uint64"}],"name":"ExchangeRateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"feeAsset","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FeesClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"oldBound","type":"uint16"},{"indexed":false,"internalType":"uint16","name":"newBound","type":"uint16"}],"name":"LowerBoundUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"oldFee","type":"uint16"},{"indexed":false,"internalType":"uint16","name":"newFee","type":"uint16"}],"name":"ManagementFeeUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldPayout","type":"address"},{"indexed":false,"internalType":"address","name":"newPayout","type":"address"}],"name":"PayoutAddressUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"bool","name":"isPegged","type":"bool"},{"indexed":false,"internalType":"address","name":"rateProvider","type":"address"}],"name":"RateProviderUpdated","type":"event"},{"anonymous":false,"inputs":[],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"oldBound","type":"uint16"},{"indexed":false,"internalType":"uint16","name":"newBound","type":"uint16"}],"name":"UpperBoundUpdated","type":"event"},{"inputs":[],"name":"accountantState","outputs":[{"internalType":"address","name":"payoutAddress","type":"address"},{"internalType":"uint128","name":"feesOwedInBase","type":"uint128"},{"internalType":"uint128","name":"totalSharesLastUpdate","type":"uint128"},{"internalType":"uint96","name":"exchangeRate","type":"uint96"},{"internalType":"uint16","name":"allowedExchangeRateChangeUpper","type":"uint16"},{"internalType":"uint16","name":"allowedExchangeRateChangeLower","type":"uint16"},{"internalType":"uint64","name":"lastUpdateTimestamp","type":"uint64"},{"internalType":"bool","name":"isPaused","type":"bool"},{"internalType":"uint32","name":"minimumUpdateDelayInSeconds","type":"uint32"},{"internalType":"uint16","name":"managementFee","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"authority","outputs":[{"internalType":"contract Authority","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"base","outputs":[{"internalType":"contract ERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ERC20","name":"feeAsset","type":"address"}],"name":"claimFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRate","outputs":[{"internalType":"uint256","name":"rate","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ERC20","name":"quote","type":"address"}],"name":"getRateInQuote","outputs":[{"internalType":"uint256","name":"rateInQuote","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ERC20","name":"quote","type":"address"}],"name":"getRateInQuoteSafe","outputs":[{"internalType":"uint256","name":"rateInQuote","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRateSafe","outputs":[{"internalType":"uint256","name":"rate","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ERC20","name":"","type":"address"}],"name":"rateProviderData","outputs":[{"internalType":"bool","name":"isPeggedToBase","type":"bool"},{"internalType":"contract IRateProvider","name":"rateProvider","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract Authority","name":"newAuthority","type":"address"}],"name":"setAuthority","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ERC20","name":"asset","type":"address"},{"internalType":"bool","name":"isPeggedToBase","type":"bool"},{"internalType":"address","name":"rateProvider","type":"address"}],"name":"setRateProviderData","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"minimumUpdateDelayInSeconds","type":"uint32"}],"name":"updateDelay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint96","name":"newExchangeRate","type":"uint96"}],"name":"updateExchangeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"allowedExchangeRateChangeLower","type":"uint16"}],"name":"updateLower","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"managementFee","type":"uint16"}],"name":"updateManagementFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"payoutAddress","type":"address"}],"name":"updatePayoutAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"allowedExchangeRateChangeUpper","type":"uint16"}],"name":"updateUpper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"vault","outputs":[{"internalType":"contract BoringVault","name":"","type":"address"}],"stateMutability":"view","type":"function"}]Contract Creation Code
61010060405234801562000011575f80fd5b5060405162001fb838038062001fb8833981016040819052620000349162000400565b5f80546001600160a01b038b166001600160a01b031991821681178355600180549092169091556040518b92919033907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908490a36040516001600160a01b0382169033907fa3396fd7f6e0a21b50e5089d2da70d5ac0a3bbbd1f617a93f134b76389980198905f90a350506001600160a01b03851660808190526040805163313ce56760e01b8152905163313ce567916004808201926020929091908290030181865afa15801562000109573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906200012f9190620004cb565b60ff1660a0526001600160a01b03881660c08190526040805163313ce56760e01b8152905163313ce567916004808201926020929091908290030181865afa1580156200017e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190620001a49190620004cb565b620001b190600a62000603565b60e08181525050604051806101400160405280886001600160a01b031681526020015f6001600160801b0316815260200160c0516001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000221573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019062000247919062000613565b6001600160801b0390811682526001600160601b0398891660208084019190915261ffff9788166040808501919091529688166060808501919091526001600160401b034281166080808701919091525f60a08088019190915263ffffffff998a1660c080890191909152988c1660e0978801528751600280546001600160a01b039092166001600160a01b031990921691909117905593870151998701518516600160801b9081029a90951699909917600355908501516004805499870151938701519787015195870151610100880151610120909801518c16600160e81b0261ffff60e81b1998909a16600160c81b0263ffffffff60c81b19911515600160c01b029190911664ffffffffff60c01b1997909416909502600160801b600160c01b0319988c16600160701b0298909816600160701b600160c01b031994909b166c01000000000000000000000000026001600160701b0319909a1691909c1617979097171696909617929092179190911692909217929092171617909155506200062b92505050565b80516001600160a01b0381168114620003e9575f80fd5b919050565b805161ffff81168114620003e9575f80fd5b5f805f805f805f805f6101208a8c0312156200041a575f80fd5b620004258a620003d2565b98506200043560208b01620003d2565b97506200044560408b01620003d2565b60608b01519097506001600160601b038116811462000462575f80fd5b95506200047260808b01620003d2565b94506200048260a08b01620003ee565b93506200049260c08b01620003ee565b925060e08a015163ffffffff81168114620004ab575f80fd5b9150620004bc6101008b01620003ee565b90509295985092959850929598565b5f60208284031215620004dc575f80fd5b815160ff81168114620004ed575f80fd5b9392505050565b634e487b7160e01b5f52601160045260245ffd5b600181815b808511156200054857815f19048211156200052c576200052c620004f4565b808516156200053a57918102915b93841c93908002906200050d565b509250929050565b5f826200056057506001620005fd565b816200056e57505f620005fd565b81600181146200058757600281146200059257620005b2565b6001915050620005fd565b60ff841115620005a657620005a6620004f4565b50506001821b620005fd565b5060208310610133831016604e8410600b8410161715620005d7575081810a620005fd565b620005e3838362000508565b805f1904821115620005f957620005f9620004f4565b0290505b92915050565b5f620004ed60ff84168362000550565b5f6020828403121562000624575f80fd5b5051919050565b60805160a05160c05160e051611928620006905f395f8181610c610152610c9101525f818161046b015281816104980152610aab01525f81816101f801528181610628015261085701525f818161036901528181610571015261076501526119285ff3fe608060405234801561000f575f80fd5b5060043610610148575f3560e01c806356200819116100bf5780638da5cb5b116100795780638da5cb5b14610408578063bdca5fbd1461041a578063bf7e214f1461042d578063c10af4c714610440578063f2fde38b14610453578063fbfa77cf14610466575f80fd5b806356200819146103a3578063634da58f146103b6578063679aefce146103c95780637a9e5e4b146103da578063820973da146103ed5780638456cb5914610400575f80fd5b8063313ce56711610110578063313ce567146101f35780633458113d1461022c5780633f4ba83a1461023f578063433255de146102475780634d8be07e146103515780635001f3b514610364575f80fd5b806312e2d8f31461014c57806315a0ea6a146101a25780631dcbb110146101b7578063207ec0e7146101d8578063282a8700146101eb575b5f80fd5b61017e61015a3660046115b9565b60056020525f908152604090205460ff81169061010090046001600160a01b031682565b6040805192151583526001600160a01b039091166020830152015b60405180910390f35b6101b56101b03660046115b9565b61048d565b005b6101ca6101c53660046115b9565b610762565b604051908152602001610199565b6101b56101e63660046115d4565b61091b565b6101ca6109e2565b61021a7f000000000000000000000000000000000000000000000000000000000000000081565b60405160ff9091168152602001610199565b6101b561023a3660046115f5565b610a1f565b6101b5610ddf565b6002546003546004546102cd926001600160a01b0316916001600160801b0380821692600160801b92839004909116916001600160601b03821691600160601b810461ffff90811692600160701b830482169290810467ffffffffffffffff1691600160c01b820460ff1691600160c81b810463ffffffff1691600160e81b909104168a565b604080516001600160a01b03909b168b526001600160801b03998a1660208c015298909716978901979097526001600160601b03909416606088015261ffff928316608088015290821660a087015267ffffffffffffffff1660c086015290151560e085015263ffffffff9092166101008401521661012082015261014001610199565b6101b561035f366004611628565b610e47565b61038b7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610199565b6101b56103b13660046115b9565b610f1d565b6101b56103c43660046115d4565b610fa8565b6004546001600160601b03166101ca565b6101b56103e83660046115b9565b61105e565b6101ca6103fb3660046115b9565b611142565b6101b561117e565b5f5461038b906001600160a01b031681565b6101b5610428366004611670565b6111ec565b60015461038b906001600160a01b031681565b6101b561044e3660046115d4565b6112a9565b6101b56104613660046115b9565b61135f565b61038b7f000000000000000000000000000000000000000000000000000000000000000081565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146104d657604051637e3db46f60e01b815260040160405180910390fd5b600454600290600160c01b900460ff161561050457604051631d98997b60e11b815260040160405180910390fd5b60018101546001600160801b03165f036105315760405163115b9d8b60e21b815260040160405180910390fd5b6001600160a01b038083165f81815260056020908152604080832081518083019092525460ff8116151582526101009004851691810191909152909290917f000000000000000000000000000000000000000000000000000000000000000090911690036105ae5760018301546001600160801b031691506106e3565b5f846001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156105eb573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061060f9190611693565b60018501549091505f9061064d906001600160801b03167f0000000000000000000000000000000000000000000000000000000000000000846113da565b83519091501561065f578093506106e0565b5f83602001516001600160a01b031663679aefce6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156106a0573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106c491906116b3565b90506106dc6106d484600a6117be565b839083611449565b9450505b50505b6001830180546fffffffffffffffffffffffffffffffff191690558254610719906001600160a01b038681169133911685611464565b836001600160a01b03167f9493e5bbe4e8e0ac67284469a2d677403d0378a85a59e341d3abc433d0d9a2098360405161075491815260200190565b60405180910390a250505050565b5f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316036107ad5750506004546001600160601b031690565b6001600160a01b038083165f81815260056020908152604080832081518083018352905460ff811615158252610100900490951685830152805163313ce56760e01b8152905192939263313ce567926004808401939192918290030181865afa15801561081c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906108409190611693565b6004549091505f9061087c906001600160601b03167f0000000000000000000000000000000000000000000000000000000000000000846113da565b83519091501561088e57809350610913565b5f83602001516001600160a01b031663679aefce6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108cf573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906108f391906116b3565b90505f61090184600a6117be565b905061090e818484611449565b955050505b505050919050565b610930335f356001600160e01b0319166114fc565b6109555760405162461bcd60e51b815260040161094c906117cc565b60405180910390fd5b6127108161ffff16111561097c57604051637375d3bf60e01b815260040160405180910390fd5b6004805461ffff838116600160701b81810261ffff60701b1985161790945560408051949093049091168084526020840191909152917f76fe3c3557dd03afa5caf76f66f4019444ef3999e784ba08f47a33428fcc64d591015b60405180910390a15050565b6004545f90600160c01b900460ff1615610a0f57604051631d98997b60e11b815260040160405180910390fd5b506004546001600160601b031690565b610a34335f356001600160e01b0319166114fc565b610a505760405162461bcd60e51b815260040161094c906117cc565b600454600290600160c01b900460ff1615610a7e57604051631d98997b60e11b815260040160405180910390fd5b6002810154604080516318160ddd60e01b8152905142926001600160601b0316915f916001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016916318160ddd9160048083019260209291908290030181865afa158015610af4573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b1891906116b3565b6002850154909150610b4890600160c81b810463ffffffff1690600160801b900467ffffffffffffffff166117f2565b67ffffffffffffffff168367ffffffffffffffff161080610b8e57506002840154610b82908390600160601b900461ffff16612710611449565b856001600160601b0316115b80610bbe57506002840154610bb2908390600160701b900461ffff16612710611449565b856001600160601b0316105b15610bdd5760028401805460ff60c01b1916600160c01b179055610d35565b60018401548190600160801b90046001600160801b0316811115610c1257506001840154600160801b90046001600160801b03165b60028501545f90610c3490600160801b900467ffffffffffffffff168661181a565b67ffffffffffffffff1690505f84886001600160601b031611610c8a57610c85836001600160601b038a167f0000000000000000000000000000000000000000000000000000000000000000611449565b610cb5565b610cb583867f0000000000000000000000000000000000000000000000000000000000000000611449565b60028801549091505f90610cd8908390600160e81b900461ffff16612710611449565b90505f610cea82856301e13380611449565b60018a01805491925082915f90610d0b9084906001600160801b031661183b565b92506101000a8154816001600160801b0302191690836001600160801b0316021790555050505050505b6002840180546001860180546001600160801b03908116600160801b9186168202179091556001600160601b0388811677ffffffffffffffff00000000ffffffffffffffffffffffff19909316831767ffffffffffffffff8816928302179093556040805193861684526020840192909252908201527fa95bc6aba40bbc4d95fc35f118c4cd8b53fc5d5b89ed264002af03503a7a94399060600160405180910390a15050505050565b610df4335f356001600160e01b0319166114fc565b610e105760405162461bcd60e51b815260040161094c906117cc565b6004805460ff60c01b191690556040517fa45f47fdea8a1efdd9029a5691c7f759c32b7c698632b563573e155625d16933905f90a1565b610e5c335f356001600160e01b0319166114fc565b610e785760405162461bcd60e51b815260040161094c906117cc565b6040805180820182528315158082526001600160a01b0384811660208085018281528984165f818152600584528890209651875492516001600160a81b0319909316901515610100600160a81b03191617610100929095169190910293909317909455845191825292810191909152918201527f59f9adfe8cf4c9d4b77fb03aa2ae5f373632c97cb8caf6b61f0643d3d170a8fe9060600160405180910390a1505050565b610f32335f356001600160e01b0319166114fc565b610f4e5760405162461bcd60e51b815260040161094c906117cc565b600280546001600160a01b038381166001600160a01b031983168117909355604080519190921680825260208201939093527fba2be5e898fed1646bc0814dee1cc9a2aee98f51fced7d5fc4699c47d990775391016109d6565b610fbd335f356001600160e01b0319166114fc565b610fd95760405162461bcd60e51b815260040161094c906117cc565b6127108161ffff1610156110005760405163a4ec27a960e01b815260040160405180910390fd5b6004805461ffff838116600160601b81810261ffff60601b1985161790945560408051949093049091168084526020840191909152917f67d3a3f6bebb5b894324217d5224ff719d5d95dfc67f1bb2645dddbfcd43cadb91016109d6565b5f546001600160a01b03163314806110ef575060015460405163b700961360e01b81526001600160a01b039091169063b7009613906110b090339030906001600160e01b03195f35169060040161185b565b602060405180830381865afa1580156110cb573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110ef9190611888565b6110f7575f80fd5b600180546001600160a01b0319166001600160a01b03831690811790915560405133907fa3396fd7f6e0a21b50e5089d2da70d5ac0a3bbbd1f617a93f134b76389980198905f90a350565b6004545f90600160c01b900460ff161561116f57604051631d98997b60e11b815260040160405180910390fd5b61117882610762565b92915050565b611193335f356001600160e01b0319166114fc565b6111af5760405162461bcd60e51b815260040161094c906117cc565b6004805460ff60c01b1916600160c01b1790556040517f9e87fac88ff661f02d44f95383c817fece4bce600a3dab7a54406878b965e752905f90a1565b611201335f356001600160e01b0319166114fc565b61121d5760405162461bcd60e51b815260040161094c906117cc565b621275008163ffffffff16111561124757604051635badbfbb60e01b815260040160405180910390fd5b6004805463ffffffff838116600160c81b81810263ffffffff60c81b1985161790945560408051949093049091168084526020840191909152917fcccad74cc0fcc3b3393386e7a89107fb131535e983a342329b52c667dafe9cf491016109d6565b6112be335f356001600160e01b0319166114fc565b6112da5760405162461bcd60e51b815260040161094c906117cc565b6107d08161ffff161115611301576040516310146b3760e01b815260040160405180910390fd5b6004805461ffff838116600160e81b81810261ffff60e81b1985161790945560408051949093049091168084526020840191909152917f7fa71bc8199b41215c8786fc03983be5a27180965feae35db511cd958631826f91016109d6565b611374335f356001600160e01b0319166114fc565b6113905760405162461bcd60e51b815260040161094c906117cc565b5f80546001600160a01b0319166001600160a01b0383169081178255604051909133917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a350565b5f8160ff168360ff16036113ef575082611442565b8160ff168360ff1610156114235761140783836118a3565b61141290600a6117be565b61141c90856118bc565b9050611442565b61142d82846118a3565b61143890600a6117be565b61141c90856118d3565b9392505050565b5f825f19048411830215820261145d575f80fd5b5091020490565b5f6040516323b872dd60e01b81526001600160a01b03851660048201526001600160a01b038416602482015282604482015260205f6064835f8a5af13d15601f3d1160015f5114161716915050806114f55760405162461bcd60e51b81526020600482015260146024820152731514905394d1915497d19493d357d1905253115160621b604482015260640161094c565b5050505050565b6001545f906001600160a01b03168015801590611583575060405163b700961360e01b81526001600160a01b0382169063b7009613906115449087903090889060040161185b565b602060405180830381865afa15801561155f573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115839190611888565b8061159a57505f546001600160a01b038581169116145b949350505050565b6001600160a01b03811681146115b6575f80fd5b50565b5f602082840312156115c9575f80fd5b8135611442816115a2565b5f602082840312156115e4575f80fd5b813561ffff81168114611442575f80fd5b5f60208284031215611605575f80fd5b81356001600160601b0381168114611442575f80fd5b80151581146115b6575f80fd5b5f805f6060848603121561163a575f80fd5b8335611645816115a2565b925060208401356116558161161b565b91506040840135611665816115a2565b809150509250925092565b5f60208284031215611680575f80fd5b813563ffffffff81168114611442575f80fd5b5f602082840312156116a3575f80fd5b815160ff81168114611442575f80fd5b5f602082840312156116c3575f80fd5b5051919050565b634e487b7160e01b5f52601160045260245ffd5b600181815b8085111561171857815f19048211156116fe576116fe6116ca565b8085161561170b57918102915b93841c93908002906116e3565b509250929050565b5f8261172e57506001611178565b8161173a57505f611178565b8160018114611750576002811461175a57611776565b6001915050611178565b60ff84111561176b5761176b6116ca565b50506001821b611178565b5060208310610133831016604e8410600b8410161715611799575081810a611178565b6117a383836116de565b805f19048211156117b6576117b66116ca565b029392505050565b5f61144260ff841683611720565b6020808252600c908201526b15539055551213d49256915160a21b604082015260600190565b67ffffffffffffffff818116838216019080821115611813576118136116ca565b5092915050565b67ffffffffffffffff828116828216039080821115611813576118136116ca565b6001600160801b03818116838216019080821115611813576118136116ca565b6001600160a01b0393841681529190921660208201526001600160e01b0319909116604082015260600190565b5f60208284031215611898575f80fd5b81516114428161161b565b60ff8281168282160390811115611178576111786116ca565b8082028115828204841417611178576111786116ca565b5f826118ed57634e487b7160e01b5f52601260045260245ffd5b50049056fea2646970667358221220b21874ef9576b770ee2df9ead812bb6e0a9d5af7e167ad80e1102c86e23a53e864736f6c6343000815003300000000000000000000000094544835cf97c631f101c5f538787fe14e2e04f60000000000000000000000009ed15383940cc380faef0a75edace507cc775f22000000000000000000000000c6cc90808a3434df28028824fd3cefcae4a93a880000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000004200000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000271300000000000000000000000000000000000000000000000000000000000027100000000000000000000000000000000000000000000000000000000000000e100000000000000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x608060405234801561000f575f80fd5b5060043610610148575f3560e01c806356200819116100bf5780638da5cb5b116100795780638da5cb5b14610408578063bdca5fbd1461041a578063bf7e214f1461042d578063c10af4c714610440578063f2fde38b14610453578063fbfa77cf14610466575f80fd5b806356200819146103a3578063634da58f146103b6578063679aefce146103c95780637a9e5e4b146103da578063820973da146103ed5780638456cb5914610400575f80fd5b8063313ce56711610110578063313ce567146101f35780633458113d1461022c5780633f4ba83a1461023f578063433255de146102475780634d8be07e146103515780635001f3b514610364575f80fd5b806312e2d8f31461014c57806315a0ea6a146101a25780631dcbb110146101b7578063207ec0e7146101d8578063282a8700146101eb575b5f80fd5b61017e61015a3660046115b9565b60056020525f908152604090205460ff81169061010090046001600160a01b031682565b6040805192151583526001600160a01b039091166020830152015b60405180910390f35b6101b56101b03660046115b9565b61048d565b005b6101ca6101c53660046115b9565b610762565b604051908152602001610199565b6101b56101e63660046115d4565b61091b565b6101ca6109e2565b61021a7f000000000000000000000000000000000000000000000000000000000000001281565b60405160ff9091168152602001610199565b6101b561023a3660046115f5565b610a1f565b6101b5610ddf565b6002546003546004546102cd926001600160a01b0316916001600160801b0380821692600160801b92839004909116916001600160601b03821691600160601b810461ffff90811692600160701b830482169290810467ffffffffffffffff1691600160c01b820460ff1691600160c81b810463ffffffff1691600160e81b909104168a565b604080516001600160a01b03909b168b526001600160801b03998a1660208c015298909716978901979097526001600160601b03909416606088015261ffff928316608088015290821660a087015267ffffffffffffffff1660c086015290151560e085015263ffffffff9092166101008401521661012082015261014001610199565b6101b561035f366004611628565b610e47565b61038b7f000000000000000000000000420000000000000000000000000000000000000681565b6040516001600160a01b039091168152602001610199565b6101b56103b13660046115b9565b610f1d565b6101b56103c43660046115d4565b610fa8565b6004546001600160601b03166101ca565b6101b56103e83660046115b9565b61105e565b6101ca6103fb3660046115b9565b611142565b6101b561117e565b5f5461038b906001600160a01b031681565b6101b5610428366004611670565b6111ec565b60015461038b906001600160a01b031681565b6101b561044e3660046115d4565b6112a9565b6101b56104613660046115b9565b61135f565b61038b7f0000000000000000000000009ed15383940cc380faef0a75edace507cc775f2281565b336001600160a01b037f0000000000000000000000009ed15383940cc380faef0a75edace507cc775f2216146104d657604051637e3db46f60e01b815260040160405180910390fd5b600454600290600160c01b900460ff161561050457604051631d98997b60e11b815260040160405180910390fd5b60018101546001600160801b03165f036105315760405163115b9d8b60e21b815260040160405180910390fd5b6001600160a01b038083165f81815260056020908152604080832081518083019092525460ff8116151582526101009004851691810191909152909290917f000000000000000000000000420000000000000000000000000000000000000690911690036105ae5760018301546001600160801b031691506106e3565b5f846001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156105eb573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061060f9190611693565b60018501549091505f9061064d906001600160801b03167f0000000000000000000000000000000000000000000000000000000000000012846113da565b83519091501561065f578093506106e0565b5f83602001516001600160a01b031663679aefce6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156106a0573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106c491906116b3565b90506106dc6106d484600a6117be565b839083611449565b9450505b50505b6001830180546fffffffffffffffffffffffffffffffff191690558254610719906001600160a01b038681169133911685611464565b836001600160a01b03167f9493e5bbe4e8e0ac67284469a2d677403d0378a85a59e341d3abc433d0d9a2098360405161075491815260200190565b60405180910390a250505050565b5f7f00000000000000000000000042000000000000000000000000000000000000066001600160a01b0316826001600160a01b0316036107ad5750506004546001600160601b031690565b6001600160a01b038083165f81815260056020908152604080832081518083018352905460ff811615158252610100900490951685830152805163313ce56760e01b8152905192939263313ce567926004808401939192918290030181865afa15801561081c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906108409190611693565b6004549091505f9061087c906001600160601b03167f0000000000000000000000000000000000000000000000000000000000000012846113da565b83519091501561088e57809350610913565b5f83602001516001600160a01b031663679aefce6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108cf573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906108f391906116b3565b90505f61090184600a6117be565b905061090e818484611449565b955050505b505050919050565b610930335f356001600160e01b0319166114fc565b6109555760405162461bcd60e51b815260040161094c906117cc565b60405180910390fd5b6127108161ffff16111561097c57604051637375d3bf60e01b815260040160405180910390fd5b6004805461ffff838116600160701b81810261ffff60701b1985161790945560408051949093049091168084526020840191909152917f76fe3c3557dd03afa5caf76f66f4019444ef3999e784ba08f47a33428fcc64d591015b60405180910390a15050565b6004545f90600160c01b900460ff1615610a0f57604051631d98997b60e11b815260040160405180910390fd5b506004546001600160601b031690565b610a34335f356001600160e01b0319166114fc565b610a505760405162461bcd60e51b815260040161094c906117cc565b600454600290600160c01b900460ff1615610a7e57604051631d98997b60e11b815260040160405180910390fd5b6002810154604080516318160ddd60e01b8152905142926001600160601b0316915f916001600160a01b037f0000000000000000000000009ed15383940cc380faef0a75edace507cc775f2216916318160ddd9160048083019260209291908290030181865afa158015610af4573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b1891906116b3565b6002850154909150610b4890600160c81b810463ffffffff1690600160801b900467ffffffffffffffff166117f2565b67ffffffffffffffff168367ffffffffffffffff161080610b8e57506002840154610b82908390600160601b900461ffff16612710611449565b856001600160601b0316115b80610bbe57506002840154610bb2908390600160701b900461ffff16612710611449565b856001600160601b0316105b15610bdd5760028401805460ff60c01b1916600160c01b179055610d35565b60018401548190600160801b90046001600160801b0316811115610c1257506001840154600160801b90046001600160801b03165b60028501545f90610c3490600160801b900467ffffffffffffffff168661181a565b67ffffffffffffffff1690505f84886001600160601b031611610c8a57610c85836001600160601b038a167f0000000000000000000000000000000000000000000000000de0b6b3a7640000611449565b610cb5565b610cb583867f0000000000000000000000000000000000000000000000000de0b6b3a7640000611449565b60028801549091505f90610cd8908390600160e81b900461ffff16612710611449565b90505f610cea82856301e13380611449565b60018a01805491925082915f90610d0b9084906001600160801b031661183b565b92506101000a8154816001600160801b0302191690836001600160801b0316021790555050505050505b6002840180546001860180546001600160801b03908116600160801b9186168202179091556001600160601b0388811677ffffffffffffffff00000000ffffffffffffffffffffffff19909316831767ffffffffffffffff8816928302179093556040805193861684526020840192909252908201527fa95bc6aba40bbc4d95fc35f118c4cd8b53fc5d5b89ed264002af03503a7a94399060600160405180910390a15050505050565b610df4335f356001600160e01b0319166114fc565b610e105760405162461bcd60e51b815260040161094c906117cc565b6004805460ff60c01b191690556040517fa45f47fdea8a1efdd9029a5691c7f759c32b7c698632b563573e155625d16933905f90a1565b610e5c335f356001600160e01b0319166114fc565b610e785760405162461bcd60e51b815260040161094c906117cc565b6040805180820182528315158082526001600160a01b0384811660208085018281528984165f818152600584528890209651875492516001600160a81b0319909316901515610100600160a81b03191617610100929095169190910293909317909455845191825292810191909152918201527f59f9adfe8cf4c9d4b77fb03aa2ae5f373632c97cb8caf6b61f0643d3d170a8fe9060600160405180910390a1505050565b610f32335f356001600160e01b0319166114fc565b610f4e5760405162461bcd60e51b815260040161094c906117cc565b600280546001600160a01b038381166001600160a01b031983168117909355604080519190921680825260208201939093527fba2be5e898fed1646bc0814dee1cc9a2aee98f51fced7d5fc4699c47d990775391016109d6565b610fbd335f356001600160e01b0319166114fc565b610fd95760405162461bcd60e51b815260040161094c906117cc565b6127108161ffff1610156110005760405163a4ec27a960e01b815260040160405180910390fd5b6004805461ffff838116600160601b81810261ffff60601b1985161790945560408051949093049091168084526020840191909152917f67d3a3f6bebb5b894324217d5224ff719d5d95dfc67f1bb2645dddbfcd43cadb91016109d6565b5f546001600160a01b03163314806110ef575060015460405163b700961360e01b81526001600160a01b039091169063b7009613906110b090339030906001600160e01b03195f35169060040161185b565b602060405180830381865afa1580156110cb573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110ef9190611888565b6110f7575f80fd5b600180546001600160a01b0319166001600160a01b03831690811790915560405133907fa3396fd7f6e0a21b50e5089d2da70d5ac0a3bbbd1f617a93f134b76389980198905f90a350565b6004545f90600160c01b900460ff161561116f57604051631d98997b60e11b815260040160405180910390fd5b61117882610762565b92915050565b611193335f356001600160e01b0319166114fc565b6111af5760405162461bcd60e51b815260040161094c906117cc565b6004805460ff60c01b1916600160c01b1790556040517f9e87fac88ff661f02d44f95383c817fece4bce600a3dab7a54406878b965e752905f90a1565b611201335f356001600160e01b0319166114fc565b61121d5760405162461bcd60e51b815260040161094c906117cc565b621275008163ffffffff16111561124757604051635badbfbb60e01b815260040160405180910390fd5b6004805463ffffffff838116600160c81b81810263ffffffff60c81b1985161790945560408051949093049091168084526020840191909152917fcccad74cc0fcc3b3393386e7a89107fb131535e983a342329b52c667dafe9cf491016109d6565b6112be335f356001600160e01b0319166114fc565b6112da5760405162461bcd60e51b815260040161094c906117cc565b6107d08161ffff161115611301576040516310146b3760e01b815260040160405180910390fd5b6004805461ffff838116600160e81b81810261ffff60e81b1985161790945560408051949093049091168084526020840191909152917f7fa71bc8199b41215c8786fc03983be5a27180965feae35db511cd958631826f91016109d6565b611374335f356001600160e01b0319166114fc565b6113905760405162461bcd60e51b815260040161094c906117cc565b5f80546001600160a01b0319166001600160a01b0383169081178255604051909133917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a350565b5f8160ff168360ff16036113ef575082611442565b8160ff168360ff1610156114235761140783836118a3565b61141290600a6117be565b61141c90856118bc565b9050611442565b61142d82846118a3565b61143890600a6117be565b61141c90856118d3565b9392505050565b5f825f19048411830215820261145d575f80fd5b5091020490565b5f6040516323b872dd60e01b81526001600160a01b03851660048201526001600160a01b038416602482015282604482015260205f6064835f8a5af13d15601f3d1160015f5114161716915050806114f55760405162461bcd60e51b81526020600482015260146024820152731514905394d1915497d19493d357d1905253115160621b604482015260640161094c565b5050505050565b6001545f906001600160a01b03168015801590611583575060405163b700961360e01b81526001600160a01b0382169063b7009613906115449087903090889060040161185b565b602060405180830381865afa15801561155f573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115839190611888565b8061159a57505f546001600160a01b038581169116145b949350505050565b6001600160a01b03811681146115b6575f80fd5b50565b5f602082840312156115c9575f80fd5b8135611442816115a2565b5f602082840312156115e4575f80fd5b813561ffff81168114611442575f80fd5b5f60208284031215611605575f80fd5b81356001600160601b0381168114611442575f80fd5b80151581146115b6575f80fd5b5f805f6060848603121561163a575f80fd5b8335611645816115a2565b925060208401356116558161161b565b91506040840135611665816115a2565b809150509250925092565b5f60208284031215611680575f80fd5b813563ffffffff81168114611442575f80fd5b5f602082840312156116a3575f80fd5b815160ff81168114611442575f80fd5b5f602082840312156116c3575f80fd5b5051919050565b634e487b7160e01b5f52601160045260245ffd5b600181815b8085111561171857815f19048211156116fe576116fe6116ca565b8085161561170b57918102915b93841c93908002906116e3565b509250929050565b5f8261172e57506001611178565b8161173a57505f611178565b8160018114611750576002811461175a57611776565b6001915050611178565b60ff84111561176b5761176b6116ca565b50506001821b611178565b5060208310610133831016604e8410600b8410161715611799575081810a611178565b6117a383836116de565b805f19048211156117b6576117b66116ca565b029392505050565b5f61144260ff841683611720565b6020808252600c908201526b15539055551213d49256915160a21b604082015260600190565b67ffffffffffffffff818116838216019080821115611813576118136116ca565b5092915050565b67ffffffffffffffff828116828216039080821115611813576118136116ca565b6001600160801b03818116838216019080821115611813576118136116ca565b6001600160a01b0393841681529190921660208201526001600160e01b0319909116604082015260600190565b5f60208284031215611898575f80fd5b81516114428161161b565b60ff8281168282160390811115611178576111786116ca565b8082028115828204841417611178576111786116ca565b5f826118ed57634e487b7160e01b5f52601260045260245ffd5b50049056fea2646970667358221220b21874ef9576b770ee2df9ead812bb6e0a9d5af7e167ad80e1102c86e23a53e864736f6c63430008150033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000094544835cf97c631f101c5f538787fe14e2e04f60000000000000000000000009ed15383940cc380faef0a75edace507cc775f22000000000000000000000000c6cc90808a3434df28028824fd3cefcae4a93a880000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000004200000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000271300000000000000000000000000000000000000000000000000000000000027100000000000000000000000000000000000000000000000000000000000000e100000000000000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : _owner (address): 0x94544835Cf97c631f101c5f538787fE14E2E04f6
Arg [1] : _vault (address): 0x9Ed15383940CC380fAEF0a75edacE507cC775f22
Arg [2] : payoutAddress (address): 0xc6cC90808A3434DF28028824Fd3cefcaE4A93A88
Arg [3] : startingExchangeRate (uint96): 1000000000000000000
Arg [4] : _base (address): 0x4200000000000000000000000000000000000006
Arg [5] : allowedExchangeRateChangeUpper (uint16): 10003
Arg [6] : allowedExchangeRateChangeLower (uint16): 10000
Arg [7] : minimumUpdateDelayInSeconds (uint32): 3600
Arg [8] : managementFee (uint16): 0
-----Encoded View---------------
9 Constructor Arguments found :
Arg [0] : 00000000000000000000000094544835cf97c631f101c5f538787fe14e2e04f6
Arg [1] : 0000000000000000000000009ed15383940cc380faef0a75edace507cc775f22
Arg [2] : 000000000000000000000000c6cc90808a3434df28028824fd3cefcae4a93a88
Arg [3] : 0000000000000000000000000000000000000000000000000de0b6b3a7640000
Arg [4] : 0000000000000000000000004200000000000000000000000000000000000006
Arg [5] : 0000000000000000000000000000000000000000000000000000000000002713
Arg [6] : 0000000000000000000000000000000000000000000000000000000000002710
Arg [7] : 0000000000000000000000000000000000000000000000000000000000000e10
Arg [8] : 0000000000000000000000000000000000000000000000000000000000000000
Deployed Bytecode Sourcemap
533:16279:13:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2647:58;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;2647:58:13;;;;;;;645:14:16;;638:22;620:41;;-1:-1:-1;;;;;697:32:16;;;692:2;677:18;;670:60;593:18;2647:58:13;;;;;;;;12613:1467;;;;;;:::i;:::-;;:::i;:::-;;14973:809;;;;;;:::i;:::-;;:::i;:::-;;;887:25:16;;;875:2;860:18;14973:809:13;741:177:16;7817:434:13;;;;;;:::i;:::-;;:::i;14495:177::-;;;:::i;4137:31::-;;;;;;;;1372:4:16;1360:17;;;1342:36;;1330:2;1315:18;4137:31:13;1200:184:16;10147:2219:13;;;;;;:::i;:::-;;:::i;6231:115::-;;;:::i;2532:38::-;;;;;;;;;-1:-1:-1;;;;;2532:38:13;;-1:-1:-1;;;;;2532:38:13;;;;-1:-1:-1;;;2532:38:13;;;;;;;;-1:-1:-1;;;;;2532:38:13;;;-1:-1:-1;;;2532:38:13;;;;;;;-1:-1:-1;;;2532:38:13;;;;;;;;;;;-1:-1:-1;;;2532:38:13;;;;;-1:-1:-1;;;2532:38:13;;;;;-1:-1:-1;;;2532:38:13;;;;;;;;;;-1:-1:-1;;;;;2180:32:16;;;2162:51;;-1:-1:-1;;;;;2302:15:16;;;2297:2;2282:18;;2275:43;2354:15;;;;2334:18;;;2327:43;;;;-1:-1:-1;;;;;2406:39:16;;;2401:2;2386:18;;2379:67;2465:6;2508:15;;;2502:3;2487:19;;2480:44;2561:15;;;2200:3;2540:19;;2533:44;2626:18;2614:31;2608:3;2593:19;;2586:60;2690:14;;2683:22;2677:3;2662:19;;2655:51;2755:10;2743:23;;;2737:3;2722:19;;2715:52;1751:18;2817:3;2802:19;;1739:31;2149:3;2134:19;2532:38:13;1781:1047:16;9363:337:13;;;;;;:::i;:::-;;:::i;4036:27::-;;;;;;;;-1:-1:-1;;;;;3690:32:16;;;3672:51;;3660:2;3645:18;4036:27:13;3512:217:16;8827:256:13;;;;;;:::i;:::-;;:::i;7220:434::-;;;;;;:::i;:::-;;:::i;14273:106::-;14344:28;;-1:-1:-1;;;;;14344:28:13;14273:106;;1523:434:8;;;;;;:::i;:::-;;:::i;15987:221:13:-;;;;;;:::i;:::-;;:::i;5911:110::-;;;:::i;562:20:8:-;;;;;-1:-1:-1;;;;;562:20:8;;;6632:425:13;;;;;;:::i;:::-;;:::i;589:26:8:-;;;;;-1:-1:-1;;;;;589:26:8;;;8366:344:13;;;;;;:::i;:::-;;:::i;1963:164:8:-;;;;;;:::i;:::-;;:::i;4322:34:13:-;;;;;12613:1467;12671:10;-1:-1:-1;;;;;12693:5:13;12671:28;;12667:97;;12708:56;;-1:-1:-1;;;12708:56:13;;;;;;;;;;;12667:97;12836:14;;12807:15;;-1:-1:-1;;;12836:14:13;;;;12832:64;;;12859:37;;-1:-1:-1;;;12859:37:13;;;;;;;;;;;12832:64;12910:20;;;;-1:-1:-1;;;;;12910:20:13;;:25;12906:81;;12944:43;;-1:-1:-1;;;12944:43:13;;;;;;;;;;;12906:81;-1:-1:-1;;;;;13119:26:13;;;13052;13119;;;:16;:26;;;;;;;;13088:57;;;;;;;;;;;;;;;;;;;;;;;;;;;;13052:26;;13088:57;;13188:4;13159:34;;;;;13155:651;;13230:20;;;;-1:-1:-1;;;;;13230:20:13;;-1:-1:-1;13155:651:13;;;13281:22;13312:8;-1:-1:-1;;;;;13306:24:13;;:26;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;13423:20;;;;13281:51;;-1:-1:-1;13346:43:13;;13408:64;;-1:-1:-1;;;;;13423:20:13;13445:8;13281:51;13408:14;:64::i;:::-;13490:19;;13346:126;;-1:-1:-1;13486:310:13;;;13550:35;13529:56;;13486:310;;;13624:12;13639:4;:17;;;-1:-1:-1;;;;;13639:25:13;;:27;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;13624:42;-1:-1:-1;13705:76:13;13752:22;13758:16;13752:2;:22;:::i;:::-;13705:35;;13776:4;13705:46;:76::i;:::-;13684:97;;13606:190;13486:310;13267:539;;13155:651;13846:20;;;:24;;-1:-1:-1;;13846:24:13;;;13967:19;;13929:78;;-1:-1:-1;;;;;13929:25:13;;;;13955:10;;13967:19;13988:18;13929:25;:78::i;:::-;14043:8;-1:-1:-1;;;;;14023:50:13;;14054:18;14023:50;;;;887:25:16;;875:2;860:18;;741:177;14023:50:13;;;;;;;;12657:1423;;;12613:1467;:::o;14973:809::-;15031:19;15092:4;-1:-1:-1;;;;;15066:31:13;15074:5;-1:-1:-1;;;;;15066:31:13;;15062:714;;-1:-1:-1;;15127:28:13;;-1:-1:-1;;;;;15127:28:13;;14973:809::o;15062:714::-;-1:-1:-1;;;;;15217:23:13;;;15186:28;15217:23;;;:16;:23;;;;;;;;15186:54;;;;;;;;;;;;;;;;;;;;;;;;;;15276:23;;-1:-1:-1;;;15276:23:13;;;;15186:28;;15217:23;15276:21;;:23;;;;;15217;;15276;;;;;;15217;15276;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;15366:28;;15254:45;;-1:-1:-1;15313:35:13;;15351:69;;-1:-1:-1;;;;;15366:28:13;15396:8;15254:45;15351:14;:69::i;:::-;15438:19;;15313:107;;-1:-1:-1;15434:332:13;;;15491:27;15477:41;;15434:332;;;15557:17;15577:4;:17;;;-1:-1:-1;;;;;15577:25:13;;:27;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;15557:47;-1:-1:-1;15622:16:13;15641:19;15647:13;15641:2;:19;:::i;:::-;15622:38;-1:-1:-1;15692:59:13;15622:38;15712:27;15741:9;15692:19;:59::i;:::-;15678:73;;15539:227;;15434:332;15172:604;;;14973:809;;;:::o;7817:434::-;902:33:8;915:10;927:7;;-1:-1:-1;;;;;;927:7:8;902:12;:33::i;:::-;894:58;;;;-1:-1:-1;;;894:58:8;;;;;;;:::i;:::-;;;;;;;;;7946:3:13::1;7913:30;:36;;;7909:98;;;7958:49;;-1:-1:-1::0;;;7958:49:13::1;;;;;;;;;;;7909:98;8035:46:::0;;;::::1;8091:79:::0;;::::1;-1:-1:-1::0;;;8091:79:13;;::::1;-1:-1:-1::0;;;;8091:79:13;::::1;;::::0;;;8185:59:::1;::::0;;8035:46;;;::::1;::::0;;::::1;7737:34:16::0;;;7802:2;7787:18;;7780:43;;;;8035:46:13;8185:59:::1;::::0;7685:18:16;8185:59:13::1;;;;;;;;7899:352;7817:434:::0;:::o;14495:177::-;14569:24;;14541:12;;-1:-1:-1;;;14569:24:13;;;;14565:74;;;14602:37;;-1:-1:-1;;;14602:37:13;;;;;;;;;;;14565:74;-1:-1:-1;14344:28:13;;-1:-1:-1;;;;;14344:28:13;;14495:177::o;10147:2219::-;902:33:8;915:10;927:7;;-1:-1:-1;;;;;;927:7:8;902:12;:33::i;:::-;894:58;;;;-1:-1:-1;;;894:58:8;;;;;;;:::i;:::-;10292:14:13;;10263:15:::1;::::0;-1:-1:-1;;;10292:14:13;::::1;;;10288:64;;;10315:37;;-1:-1:-1::0;;;10315:37:13::1;;;;;;;;;;;10288:64;10446:18;::::0;::::1;::::0;10503:19:::1;::::0;;-1:-1:-1;;;10503:19:13;;;;10390:15:::1;::::0;-1:-1:-1;;;;;10446:18:13::1;::::0;10362::::1;::::0;-1:-1:-1;;;;;10503:5:13::1;:17;::::0;::::1;::::0;:19:::1;::::0;;::::1;::::0;::::1;::::0;;;;;;;;:17;:19:::1;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;10591:33;::::0;::::1;::::0;10474:48;;-1:-1:-1;10563:61:13::1;::::0;-1:-1:-1;;;10591:33:13;::::1;;;::::0;-1:-1:-1;;;10563:25:13;::::1;;;:61;:::i;:::-;10549:75;;:11;:75;;;:186;;;-1:-1:-1::0;10693:36:13::1;::::0;::::1;::::0;10662:73:::1;::::0;:19;;-1:-1:-1;;;10693:36:13;::::1;;;10731:3;10662:30;:73::i;:::-;10644:15;-1:-1:-1::0;;;;;10644:91:13::1;;10549:186;:297;;;-1:-1:-1::0;10804:36:13::1;::::0;::::1;::::0;10773:73:::1;::::0;:19;;-1:-1:-1;;;10804:36:13;::::1;;;10842:3;10773:30;:73::i;:::-;10755:15;-1:-1:-1::0;;;;;10755:91:13::1;;10549:297;10532:1571;;;11062:14;::::0;::::1;:21:::0;;-1:-1:-1;;;;11062:21:13::1;-1:-1:-1::0;;;11062:21:13::1;::::0;;10532:1571:::1;;;11363:27;::::0;::::1;::::0;11233:18;;-1:-1:-1;;;11363:27:13;::::1;-1:-1:-1::0;;;;;11363:27:13::1;-1:-1:-1::0;;11359:131:13::1;;;-1:-1:-1::0;11448:27:13::1;::::0;::::1;::::0;-1:-1:-1;;;11448:27:13;::::1;-1:-1:-1::0;;;;;11448:27:13::1;11359:131;11586:25;::::0;::::1;::::0;11552:17:::1;::::0;11572:39:::1;::::0;-1:-1:-1;;;11586:25:13;::::1;;;11572:11:::0;:39:::1;:::i;:::-;11552:59;;;;11625:21;11667:19;11649:15;-1:-1:-1::0;;;;;11649:37:13::1;;:189;;11783:55;:16:::0;-1:-1:-1;;;;;11783:55:13;::::1;11828:9;11783:27;:55::i;:::-;11649:189;;;11705:59;:16:::0;11733:19;11754:9:::1;11705:27;:59::i;:::-;11908:19;::::0;::::1;::::0;11625:213;;-1:-1:-1;11852:28:13::1;::::0;11883:50:::1;::::0;11625:213;;-1:-1:-1;;;11908:19:13;::::1;;;11929:3;11883:24;:50::i;:::-;11852:81:::0;-1:-1:-1;11947:25:13::1;11975:52;11852:81:::0;12007:9;12018:8:::1;11975:31;:52::i;:::-;12042:20;::::0;::::1;:50:::0;;11947:80;;-1:-1:-1;11947:80:13;;12042:20:::1;::::0;:50:::1;::::0;11947:80;;-1:-1:-1;;;;;12042:50:13::1;;:::i;:::-;;;;;;;;-1:-1:-1::0;;;;;12042:50:13::1;;;;;-1:-1:-1::0;;;;;12042:50:13::1;;;;;;11100:1003;;;;;10532:1571;12113:18;::::0;::::1;:36:::0;;;12159:27;::::1;:57:::0;;-1:-1:-1;;;;;12159:57:13;;::::1;-1:-1:-1::0;;;12159:57:13;;::::1;::::0;::::1;;::::0;;;-1:-1:-1;;;;;12113:36:13;;::::1;-1:-1:-1::0;;12226:39:13;;;;;::::1;::::0;::::1;::::0;;::::1;;::::0;;;12281:78:::1;::::0;;8668:15:16;;;8650:34;;8715:2;8700:18;;8693:43;;;;8752:18;;;8745:59;12281:78:13::1;::::0;8593:2:16;8578:18;12281:78:13::1;;;;;;;10221:2145;;;;10147:2219:::0;:::o;6231:115::-;902:33:8;915:10;927:7;;-1:-1:-1;;;;;;927:7:8;902:12;:33::i;:::-;894:58;;;;-1:-1:-1;;;894:58:8;;;;;;;:::i;:::-;6282:24:13;:32;;-1:-1:-1;;;;6282:32:13::1;::::0;;6329:10:::1;::::0;::::1;::::0;6309:5:::1;::::0;6329:10:::1;6231:115::o:0;9363:337::-;902:33:8;915:10;927:7;;-1:-1:-1;;;;;;927:7:8;902:12;:33::i;:::-;894:58;;;;-1:-1:-1;;;894:58:8;;;;;;;:::i;:::-;9518:95:13::1;::::0;;;;::::1;::::0;;;::::1;;::::0;;;-1:-1:-1;;;;;9518:95:13;;::::1;;::::0;;::::1;::::0;;;9480:23;;::::1;-1:-1:-1::0;9480:23:13;;;:16:::1;:23:::0;;;;;:133;;;;;;-1:-1:-1;;;;;;9480:133:13;;;;::::1;;-1:-1:-1::0;;;;;;9480:133:13;;::::1;::::0;;;::::1;::::0;;;::::1;::::0;;;::::1;::::0;;;9628:65;;9049:34:16;;;9099:18;;;9092:50;;;;9158:18;;;9151:43;9628:65:13::1;::::0;8999:2:16;8984:18;9628:65:13::1;;;;;;;9363:337:::0;;;:::o;8827:256::-;902:33:8;915:10;927:7;;-1:-1:-1;;;;;;927:7:8;902:12;:33::i;:::-;894:58;;;;-1:-1:-1;;;894:58:8;;;;;;;:::i;:::-;8931:15:13::1;:29:::0;;-1:-1:-1;;;;;8970:45:13;;::::1;-1:-1:-1::0;;;;;;8970:45:13;::::1;::::0;::::1;::::0;;;9030:46:::1;::::0;;8931:29;;;::::1;9417:34:16::0;;;9482:2;9467:18;;9460:43;;;;9030:46:13::1;::::0;9352:18:16;9030:46:13::1;9205:304:16::0;7220:434:13;902:33:8;915:10;927:7;;-1:-1:-1;;;;;;927:7:8;902:12;:33::i;:::-;894:58;;;;-1:-1:-1;;;894:58:8;;;;;;;:::i;:::-;7349:3:13::1;7316:30;:36;;;7312:98;;;7361:49;;-1:-1:-1::0;;;7361:49:13::1;;;;;;;;;;;7312:98;7438:46:::0;;;::::1;7494:79:::0;;::::1;-1:-1:-1::0;;;7494:79:13;;::::1;-1:-1:-1::0;;;;7494:79:13;::::1;;::::0;;;7588:59:::1;::::0;;7438:46;;;::::1;::::0;;::::1;7737:34:16::0;;;7802:2;7787:18;;7780:43;;;;7438:46:13;7588:59:::1;::::0;7685:18:16;7588:59:13::1;7542:287:16::0;1523:434:8;1794:5;;-1:-1:-1;;;;;1794:5:8;1780:10;:19;;:76;;-1:-1:-1;1803:9:8;;:53;;-1:-1:-1;;;1803:53:8;;-1:-1:-1;;;;;1803:9:8;;;;:17;;:53;;1821:10;;1841:4;;-1:-1:-1;;;;;;1803:9:8;1848:7;;;1803:53;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;1772:85;;;;;;1868:9;:24;;-1:-1:-1;;;;;;1868:24:8;-1:-1:-1;;;;;1868:24:8;;;;;;;;1908:42;;1925:10;;1908:42;;-1:-1:-1;;1908:42:8;1523:434;:::o;15987:221:13:-;16086:24;;16051:19;;-1:-1:-1;;;16086:24:13;;;;16082:74;;;16119:37;;-1:-1:-1;;;16119:37:13;;;;;;;;;;;16082:74;16180:21;16195:5;16180:14;:21::i;:::-;16166:35;15987:221;-1:-1:-1;;15987:221:13:o;5911:110::-;902:33:8;915:10;927:7;;-1:-1:-1;;;;;;927:7:8;902:12;:33::i;:::-;894:58;;;;-1:-1:-1;;;894:58:8;;;;;;;:::i;:::-;5960:24:13;:31;;-1:-1:-1;;;;5960:31:13::1;-1:-1:-1::0;;;5960:31:13::1;::::0;;6006:8:::1;::::0;::::1;::::0;5960:31;;6006:8:::1;5911:110::o:0;6632:425::-;902:33:8;915:10;927:7;;-1:-1:-1;;;;;;927:7:8;902:12;:33::i;:::-;894:58;;;;-1:-1:-1;;;894:58:8;;;;;;;:::i;:::-;6755:7:13::1;6725:27;:37;;;6721:100;;;6771:50;;-1:-1:-1::0;;;6771:50:13::1;;;;;;;;;;;6721:100;6849:43:::0;;;::::1;6902:73:::0;;::::1;-1:-1:-1::0;;;6902:73:13;;::::1;-1:-1:-1::0;;;;6902:73:13;::::1;;::::0;;;6990:60:::1;::::0;;6849:43;;;::::1;::::0;;::::1;10368:34:16::0;;;10433:2;10418:18;;10411:43;;;;6849::13;6990:60:::1;::::0;10312:18:16;6990:60:13::1;10169:291:16::0;8366:344:13;902:33:8;915:10;927:7;;-1:-1:-1;;;;;;927:7:8;902:12;:33::i;:::-;894:58;;;;-1:-1:-1;;;894:58:8;;;;;;;:::i;:::-;8469:5:13::1;8453:13;:21;;;8449:86;;;8483:52;;-1:-1:-1::0;;;8483:52:13::1;;;;;;;;;;;8449:86;8561:29:::0;;;::::1;8600:45:::0;;::::1;-1:-1:-1::0;;;8600:45:13;;::::1;-1:-1:-1::0;;;;8600:45:13;::::1;;::::0;;;8660:43:::1;::::0;;8561:29;;;::::1;::::0;;::::1;7737:34:16::0;;;7802:2;7787:18;;7780:43;;;;8561:29:13;8660:43:::1;::::0;7685:18:16;8660:43:13::1;7542:287:16::0;1963:164:8;902:33;915:10;927:7;;-1:-1:-1;;;;;;927:7:8;902:12;:33::i;:::-;894:58;;;;-1:-1:-1;;;894:58:8;;;;;;;:::i;:::-;2046:5:::1;:16:::0;;-1:-1:-1;;;;;;2046:16:8::1;-1:-1:-1::0;;;;;2046:16:8;::::1;::::0;;::::1;::::0;;2078:42:::1;::::0;2046:16;;2099:10:::1;::::0;2078:42:::1;::::0;2046:5;2078:42:::1;1963:164:::0;:::o;16423:387:13:-;16524:7;16563:10;16547:26;;:12;:26;;;16543:261;;-1:-1:-1;16596:6:13;16589:13;;16543:261;16638:10;16623:25;;:12;:25;;;16619:185;;;16687:25;16700:12;16687:10;:25;:::i;:::-;16680:33;;:2;:33;:::i;:::-;16671:42;;:6;:42;:::i;:::-;16664:49;;;;16619:185;16767:25;16782:10;16767:12;:25;:::i;:::-;16760:33;;:2;:33;:::i;:::-;16751:42;;:6;:42;:::i;16619:185::-;16423:387;;;;;:::o;1564:526:10:-;1680:9;1928:1;-1:-1:-1;;1911:19:10;1908:1;1905:26;1902:1;1898:34;1891:42;1878:11;1874:60;1864:116;;1964:1;1961;1954:12;1864:116;-1:-1:-1;2051:9:10;;2047:27;;1564:526::o;1328:1782:11:-;1466:12;1636:4;1630:11;-1:-1:-1;;;1759:17:11;1752:93;-1:-1:-1;;;;;1896:4:11;1892:53;1888:1;1869:17;1865:25;1858:88;-1:-1:-1;;;;;2038:2:11;2034:51;2029:2;2010:17;2006:26;1999:87;2172:6;2167:2;2148:17;2144:26;2137:42;3026:2;3023:1;3018:3;2999:17;2996:1;2989:5;2982;2977:52;2545:16;2538:24;2532:2;2514:16;2511:24;2507:1;2503;2497:8;2494:15;2490:46;2487:76;2287:756;2276:767;;;3071:7;3063:40;;;;-1:-1:-1;;;3063:40:11;;11218:2:16;3063:40:11;;;11200:21:16;11257:2;11237:18;;;11230:30;-1:-1:-1;;;11276:18:16;;;11269:50;11336:18;;3063:40:11;11016:344:16;3063:40:11;1456:1654;1328:1782;;;;:::o;977:540:8:-;1097:9;;1064:4;;-1:-1:-1;;;;;1097:9:8;1415:27;;;;;:77;;-1:-1:-1;1446:46:8;;-1:-1:-1;;;1446:46:8;;-1:-1:-1;;;;;1446:12:8;;;;;:46;;1459:4;;1473;;1480:11;;1446:46;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;1414:96;;;-1:-1:-1;1505:5:8;;-1:-1:-1;;;;;1497:13:8;;;1505:5;;1497:13;1414:96;1407:103;977:540;-1:-1:-1;;;;977:540:8:o;14:138:16:-;-1:-1:-1;;;;;96:31:16;;86:42;;76:70;;142:1;139;132:12;76:70;14:138;:::o;157:268::-;230:6;283:2;271:9;262:7;258:23;254:32;251:52;;;299:1;296;289:12;251:52;338:9;325:23;357:38;389:5;357:38;:::i;923:272::-;981:6;1034:2;1022:9;1013:7;1009:23;1005:32;1002:52;;;1050:1;1047;1040:12;1002:52;1089:9;1076:23;1139:6;1132:5;1128:18;1121:5;1118:29;1108:57;;1161:1;1158;1151:12;1389:292;1447:6;1500:2;1488:9;1479:7;1475:23;1471:32;1468:52;;;1516:1;1513;1506:12;1468:52;1555:9;1542:23;-1:-1:-1;;;;;1598:5:16;1594:38;1587:5;1584:49;1574:77;;1647:1;1644;1637:12;2833:118;2919:5;2912:13;2905:21;2898:5;2895:32;2885:60;;2941:1;2938;2931:12;2956:551;3044:6;3052;3060;3113:2;3101:9;3092:7;3088:23;3084:32;3081:52;;;3129:1;3126;3119:12;3081:52;3168:9;3155:23;3187:38;3219:5;3187:38;:::i;:::-;3244:5;-1:-1:-1;3301:2:16;3286:18;;3273:32;3314:30;3273:32;3314:30;:::i;:::-;3363:7;-1:-1:-1;3422:2:16;3407:18;;3394:32;3435:40;3394:32;3435:40;:::i;:::-;3494:7;3484:17;;;2956:551;;;;;:::o;4477:276::-;4535:6;4588:2;4576:9;4567:7;4563:23;4559:32;4556:52;;;4604:1;4601;4594:12;4556:52;4643:9;4630:23;4693:10;4686:5;4682:22;4675:5;4672:33;4662:61;;4719:1;4716;4709:12;5219:273;5287:6;5340:2;5328:9;5319:7;5315:23;5311:32;5308:52;;;5356:1;5353;5346:12;5308:52;5388:9;5382:16;5438:4;5431:5;5427:16;5420:5;5417:27;5407:55;;5458:1;5455;5448:12;5497:184;5567:6;5620:2;5608:9;5599:7;5595:23;5591:32;5588:52;;;5636:1;5633;5626:12;5588:52;-1:-1:-1;5659:16:16;;5497:184;-1:-1:-1;5497:184:16:o;5686:127::-;5747:10;5742:3;5738:20;5735:1;5728:31;5778:4;5775:1;5768:15;5802:4;5799:1;5792:15;5818:422;5907:1;5950:5;5907:1;5964:270;5985:7;5975:8;5972:21;5964:270;;;6044:4;6040:1;6036:6;6032:17;6026:4;6023:27;6020:53;;;6053:18;;:::i;:::-;6103:7;6093:8;6089:22;6086:55;;;6123:16;;;;6086:55;6202:22;;;;6162:15;;;;5964:270;;;5968:3;5818:422;;;;;:::o;6245:806::-;6294:5;6324:8;6314:80;;-1:-1:-1;6365:1:16;6379:5;;6314:80;6413:4;6403:76;;-1:-1:-1;6450:1:16;6464:5;;6403:76;6495:4;6513:1;6508:59;;;;6581:1;6576:130;;;;6488:218;;6508:59;6538:1;6529:10;;6552:5;;;6576:130;6613:3;6603:8;6600:17;6597:43;;;6620:18;;:::i;:::-;-1:-1:-1;;6676:1:16;6662:16;;6691:5;;6488:218;;6790:2;6780:8;6777:16;6771:3;6765:4;6762:13;6758:36;6752:2;6742:8;6739:16;6734:2;6728:4;6725:12;6721:35;6718:77;6715:159;;;-1:-1:-1;6827:19:16;;;6859:5;;6715:159;6906:34;6931:8;6925:4;6906:34;:::i;:::-;6976:6;6972:1;6968:6;6964:19;6955:7;6952:32;6949:58;;;6987:18;;:::i;:::-;7025:20;;6245:806;-1:-1:-1;;;6245:806:16:o;7056:140::-;7114:5;7143:47;7184:4;7174:8;7170:19;7164:4;7143:47;:::i;7201:336::-;7403:2;7385:21;;;7442:2;7422:18;;;7415:30;-1:-1:-1;;;7476:2:16;7461:18;;7454:42;7528:2;7513:18;;7201:336::o;7834:180::-;7901:18;7939:10;;;7951;;;7935:27;;7974:11;;;7971:37;;;7988:18;;:::i;:::-;7971:37;7834:180;;;;:::o;8019:183::-;8087:18;8138:10;;;8126;;;8122:27;;8161:12;;;8158:38;;;8176:18;;:::i;8207:197::-;-1:-1:-1;;;;;8329:10:16;;;8341;;;8325:27;;8364:11;;;8361:37;;;8378:18;;:::i;9514:400::-;-1:-1:-1;;;;;9770:15:16;;;9752:34;;9822:15;;;;9817:2;9802:18;;9795:43;-1:-1:-1;;;;;;9874:33:16;;;9869:2;9854:18;;9847:61;9702:2;9687:18;;9514:400::o;9919:245::-;9986:6;10039:2;10027:9;10018:7;10014:23;10010:32;10007:52;;;10055:1;10052;10045:12;10007:52;10087:9;10081:16;10106:28;10128:5;10106:28;:::i;10465:151::-;10555:4;10548:12;;;10534;;;10530:31;;10573:14;;10570:40;;;10590:18;;:::i;10621:168::-;10694:9;;;10725;;10742:15;;;10736:22;;10722:37;10712:71;;10763:18;;:::i;10794:217::-;10834:1;10860;10850:132;;10904:10;10899:3;10895:20;10892:1;10885:31;10939:4;10936:1;10929:15;10967:4;10964:1;10957:15;10850:132;-1:-1:-1;10996:9:16;;10794:217::o
Swarm Source
ipfs://b21874ef9576b770ee2df9ead812bb6e0a9d5af7e167ad80e1102c86e23a53e8
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
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.