Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00Latest 7 from a total of 7 transactions
| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
| Set Outer Manage... | 23680577 | 87 days ago | IN | 0 ETH | 0.00001843 | ||||
| Set Outer Decode... | 23680577 | 87 days ago | IN | 0 ETH | 0.00000754 | ||||
| Set Repay Inner ... | 23680577 | 87 days ago | IN | 0 ETH | 0.00001179 | ||||
| Set Repay Inner ... | 23680577 | 87 days ago | IN | 0 ETH | 0.00004448 | ||||
| Set Borrow Inner... | 23680577 | 87 days ago | IN | 0 ETH | 0.00001179 | ||||
| Set Borrow Inner... | 23680577 | 87 days ago | IN | 0 ETH | 0.00004448 | ||||
| Set Authority | 23680577 | 87 days ago | IN | 0 ETH | 0.00000433 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Similar Match Source Code This contract matches the deployed Bytecode of the Source Code for Contract 0x7baC3d95...8cBea8811 The constructor portion of the code might be different and could alter the actual behaviour of the contract
Contract Name:
PrvlFlashloanAaveBorrowV4
Compiler Version
v0.8.21+commit.d9974bed
Optimization Enabled:
Yes with 200 runs
Other Settings:
shanghai EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.21;
import {UManager, FixedPointMathLib, ManagerWithMerkleVerification, ERC20} from "src/micro-managers/UManager.sol";
import {IUniswapV3Router} from "src/interfaces/IUniswapV3Router.sol";
import {DecoderCustomTypes} from "src/interfaces/DecoderCustomTypes.sol";
import {BalancerVault} from "src/interfaces/BalancerVault.sol";
import {BoringVault} from "src/base/BoringVault.sol";
import {Auth, Authority} from "@solmate/auth/Auth.sol";
interface IQuoter {
function quoteExactInputSingle(
address tokenIn,
address tokenOut,
uint24 fee,
uint256 amountIn,
uint160 sqrtPriceLimitX96
) external returns (uint256 amountOut);
function quoteExactOutputSingle(
address tokenIn,
address tokenOut,
uint24 fee,
uint256 amountOut,
uint160 sqrtPriceLimitX96
) external returns (uint256 amountIn);
}
interface IAavePool {
function getUserAccountData(address user) external view returns (
uint256 totalCollateralBase,
uint256 totalDebtBase,
uint256 availableBorrowsBase,
uint256 currentLiquidationThreshold,
uint256 ltv,
uint256 healthFactor
);
}
struct TokenConfig {
address baseToken; // eg WETH
address depositToken; // eg wstETH
address aToken; // eg awstETH
address debtToken; // eg variableDebtEthWETH
}
contract PrvlFlashloanAaveBorrowV4 is UManager {
using FixedPointMathLib for uint256;
/*
* @dev V4 uses struct to avoid stack too deep
*/
IUniswapV3Router public immutable uniswapV3Router;
IQuoter public immutable quoter;
BalancerVault public immutable balancerVault;
address public immutable AAVE;
address public immutable baseToken; // eg depositToken
address public immutable depositToken; // eg wstdepositToken
address public immutable aToken; // eg awstETH
address public immutable debtToken; // eg variableDebtEthWETH;
uint24 public immutable uniFeeTier;
uint256 public immutable aaveVariableRate;
bytes4 constant EXACT_INPUT_SINGLE_SELECTOR = 0x04e45aaf;
bytes4 constant SUPPLY_SELECTOR = 0x617ba037;
bytes4 constant BORROW_SELECTOR = 0xa415bcad;
bytes4 constant FLASHLOAN_SELECTOR = 0x5c38449e;
bytes4 constant REPAY_SELECTOR = 0x573ade81;
bytes4 constant WITHDRAW_SELECTOR = 0x69328dec;
bytes32[][] private borrowInnerManageProofs;
address[] private borrowInnerDecodersAndSanitizers;
bytes32[][] private repayInnerManageProofs;
address[] private repayInnerDecodersAndSanitizers;
address[] private outerDecodersAndSanitizers;
bytes32[][] private outerManageProofs;
constructor(
address _owner,
address _manager,
address _boringVault,
address _balancerVault,
address _uniswapV3Router,
address _quoter,
address _aave,
TokenConfig memory _tokens,
uint24 _uniFeeTier,
uint256 _aaveVariableRate
) UManager(_owner, _manager, _boringVault) {
uniswapV3Router = IUniswapV3Router(_uniswapV3Router);
quoter = IQuoter(_quoter);
balancerVault = BalancerVault(_balancerVault);
AAVE = _aave;
baseToken = _tokens.baseToken;
depositToken = _tokens.depositToken;
aToken = _tokens.aToken;
debtToken = _tokens.debtToken;
uniFeeTier = _uniFeeTier;
aaveVariableRate = _aaveVariableRate;
}
error InsufficientVaultBalance();
function setBorrowInnerManageProofs(bytes32[][] calldata _borrowInnerManageProofs) external requiresAuth {
// Manual deep copy to avoid calldata-to-storage issue
delete borrowInnerManageProofs; // Clear existing
borrowInnerManageProofs = new bytes32[][](_borrowInnerManageProofs.length);
for (uint256 i = 0; i < _borrowInnerManageProofs.length; i++) {
borrowInnerManageProofs[i] = new bytes32[](_borrowInnerManageProofs[i].length);
for (uint256 j = 0; j < _borrowInnerManageProofs[i].length; j++) {
borrowInnerManageProofs[i][j] = _borrowInnerManageProofs[i][j];
}
}
}
function setBorrowInnerDecodersAndSanitizers(address[] calldata _borrowInnerDecodersAndSanitizers)
external
requiresAuth
{
// Simple array: manual copy
delete borrowInnerDecodersAndSanitizers;
borrowInnerDecodersAndSanitizers = new address[](_borrowInnerDecodersAndSanitizers.length);
for (uint256 i = 0; i < _borrowInnerDecodersAndSanitizers.length; i++) {
borrowInnerDecodersAndSanitizers[i] = _borrowInnerDecodersAndSanitizers[i];
}
}
function setRepayInnerManageProofs(bytes32[][] calldata _repayInnerManageProofs) external requiresAuth {
// Manual deep copy to avoid calldata-to-storage issue
delete repayInnerManageProofs; // Clear existing
repayInnerManageProofs = new bytes32[][](_repayInnerManageProofs.length);
for (uint256 i = 0; i < _repayInnerManageProofs.length; i++) {
repayInnerManageProofs[i] = new bytes32[](_repayInnerManageProofs[i].length);
for (uint256 j = 0; j < _repayInnerManageProofs[i].length; j++) {
repayInnerManageProofs[i][j] = _repayInnerManageProofs[i][j];
}
}
}
function setRepayInnerDecodersAndSanitizers(address[] calldata _repayInnerDecodersAndSanitizers)
external
requiresAuth
{
// Simple array: manual copy
delete repayInnerDecodersAndSanitizers;
repayInnerDecodersAndSanitizers = new address[](_repayInnerDecodersAndSanitizers.length);
for (uint256 i = 0; i < _repayInnerDecodersAndSanitizers.length; i++) {
repayInnerDecodersAndSanitizers[i] = _repayInnerDecodersAndSanitizers[i];
}
}
function setOuterDecodersAndSanitizers(address[] calldata _outerDecodersAndSanitizers) external requiresAuth {
// Simple array: manual copy
delete outerDecodersAndSanitizers;
outerDecodersAndSanitizers = new address[](_outerDecodersAndSanitizers.length);
for (uint256 i = 0; i < _outerDecodersAndSanitizers.length; i++) {
outerDecodersAndSanitizers[i] = _outerDecodersAndSanitizers[i];
}
}
function setOuterManageProofs(bytes32[][] calldata _outerManageProofs) external requiresAuth {
// Manual deep copy to avoid calldata-to-storage issue
delete outerManageProofs; // Clear existing
outerManageProofs = new bytes32[][](_outerManageProofs.length);
for (uint256 i = 0; i < _outerManageProofs.length; i++) {
outerManageProofs[i] = new bytes32[](_outerManageProofs[i].length);
for (uint256 j = 0; j < _outerManageProofs[i].length; j++) {
outerManageProofs[i][j] = _outerManageProofs[i][j];
}
}
}
function borrow(uint256 collateralAmount, uint256 borrowAmount) external requiresAuth {
uint256 vaultBalance = ERC20(baseToken).balanceOf(boringVault);
if (vaultBalance < collateralAmount) {
revert InsufficientVaultBalance();
}
bytes memory innerUserData = getBorrowUserData(collateralAmount, borrowAmount);
_executeFlashloan(innerUserData, borrowAmount);
}
function repay(uint256 borrowAmount, uint256 supplyAmount) external requiresAuth {
bytes memory innerUserData = getRepayUserData(borrowAmount, supplyAmount);
_executeFlashloan(innerUserData, borrowAmount);
}
function settle() external requiresAuth {
// Get total debt in USD (base currency)
uint256 debtAmount = ERC20(debtToken).balanceOf(boringVault);
bytes memory innerUserData = getRepayUserData(type(uint256).max, type(uint256).max);
// Use actual debt amount for flashloan
_executeFlashloan(innerUserData, debtAmount);
}
function _executeFlashloan(bytes memory innerUserData, uint256 flashloanAmount) internal {
bytes32[][] memory outerProofs = outerManageProofs;
address[] memory outerTargets = new address[](1);
outerTargets[0] = address(manager);
uint256[] memory outerValues = new uint256[](1);
bytes[] memory outerTargetData = new bytes[](1);
address[] memory flashloanTokens = new address[](1);
flashloanTokens[0] = baseToken;
uint256[] memory flashloanAmounts = new uint256[](1);
flashloanAmounts[0] = flashloanAmount;
outerTargetData[0] = abi.encodeWithSelector(
ManagerWithMerkleVerification.flashLoan.selector,
address(manager),
flashloanTokens,
flashloanAmounts,
innerUserData
);
manager.manageVaultWithMerkleVerification(
outerProofs, outerDecodersAndSanitizers, outerTargets, outerTargetData, outerValues
);
}
function getBorrowUserData(uint256 collateralAmount, uint256 borrowAmount)
internal
returns (bytes memory userData)
{
uint256 swapAmount = collateralAmount + borrowAmount;
uint256 supplyAmount = quoter.quoteExactInputSingle(baseToken, depositToken, uniFeeTier, swapAmount, uint160(0));
bytes memory swapData = abi.encodeWithSelector(
EXACT_INPUT_SINGLE_SELECTOR, baseToken, depositToken, uniFeeTier, boringVault, swapAmount, 0, uint160(0)
);
bytes memory supplyData = abi.encodeWithSelector(SUPPLY_SELECTOR, depositToken, supplyAmount, boringVault, 0);
bytes memory borrowData =
abi.encodeWithSelector(BORROW_SELECTOR, baseToken, borrowAmount, aaveVariableRate, 0, boringVault);
address[] memory innerTargets = new address[](3);
innerTargets[0] = address(uniswapV3Router);
innerTargets[1] = AAVE;
innerTargets[2] = AAVE;
bytes[] memory innerTargetData = new bytes[](3);
innerTargetData[0] = swapData;
innerTargetData[1] = supplyData;
innerTargetData[2] = borrowData;
uint256[] memory innerValues = new uint256[](3);
userData = abi.encode(
borrowInnerManageProofs, borrowInnerDecodersAndSanitizers, innerTargets, innerTargetData, innerValues
);
}
function getRepayUserData(uint256 borrowAmount, uint256 supplyAmount) internal returns (bytes memory userData) {
bytes memory repayData =
abi.encodeWithSelector(REPAY_SELECTOR, baseToken, borrowAmount, aaveVariableRate, boringVault);
bytes memory withdrawData = abi.encodeWithSelector(WITHDRAW_SELECTOR, depositToken, supplyAmount, boringVault);
// For swap, use actual adepositToken balance if supplyAmount is max
uint256 swapAmount = supplyAmount;
if (supplyAmount == type(uint256).max) {
swapAmount = ERC20(aToken).balanceOf(boringVault);
}
bytes memory swapData = abi.encodeWithSelector(
EXACT_INPUT_SINGLE_SELECTOR, depositToken, baseToken, uniFeeTier, boringVault, swapAmount, 0, uint160(0)
);
address[] memory innerTargets = new address[](3);
innerTargets[0] = AAVE;
innerTargets[1] = AAVE;
innerTargets[2] = address(uniswapV3Router);
bytes[] memory innerTargetData = new bytes[](3);
innerTargetData[0] = repayData;
innerTargetData[1] = withdrawData;
innerTargetData[2] = swapData;
uint256[] memory innerValues = new uint256[](3);
userData = abi.encode(
repayInnerManageProofs, repayInnerDecodersAndSanitizers, innerTargets, innerTargetData, innerValues
);
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.21;
import {FixedPointMathLib} from "@solmate/utils/FixedPointMathLib.sol";
import {ManagerWithMerkleVerification} from "src/base/Roles/ManagerWithMerkleVerification.sol";
import {ERC20} from "@solmate/tokens/ERC20.sol";
import {Auth, Authority} from "@solmate/auth/Auth.sol";
abstract contract UManager is Auth {
using FixedPointMathLib for uint256;
// ========================================= STATE =========================================
/**
* @notice The period in seconds for the rate limit.
*/
uint16 public period;
/**
* @notice The number of calls allowed per period.
*/
uint16 public allowedCallsPerPeriod;
/**
* @notice The number of calls made in the current period.
*/
mapping(uint256 => uint256) public callCountPerPeriod;
//============================== ERRORS ===============================
error UManager__CallCountExceeded();
//============================== EVENTS ===============================
event PeriodUpdated(uint16 oldPeriod, uint16 newPeriod);
event AllowedCallsPeriodUpdated(uint16 oldAllowance, uint16 newAllowance);
//============================== MODIFIERS ===============================
modifier enforceRateLimit() {
// Use parenthesis to avoid stack too deep error.
{
// We include this call in the current call count for period.
uint256 currentCallCountForPeriod = callCountPerPeriod[block.timestamp % period] + 1;
if (currentCallCountForPeriod > allowedCallsPerPeriod) {
revert UManager__CallCountExceeded();
}
callCountPerPeriod[block.timestamp % period] = currentCallCountForPeriod;
}
_;
}
//============================== IMMUTABLES ===============================
/**
* @notice The ManagerWithMerkleVerification this uManager works with.
*/
ManagerWithMerkleVerification internal immutable manager;
/**
* @notice The BoringVault this uManager works with.
*/
address internal immutable boringVault;
constructor(address _owner, address _manager, address _boringVault) Auth(_owner, Authority(address(0))) {
manager = ManagerWithMerkleVerification(_manager);
boringVault = _boringVault;
}
// ========================================= ADMIN FUNCTIONS =========================================
/**
* @notice Sets the duration of the period.
* @dev Callable by MULTISIG_ROLE.
*/
function setPeriod(uint16 _period) external requiresAuth {
emit PeriodUpdated(period, _period);
period = _period;
}
/**
* @notice Sets the number of calls allowed per period.
* @dev Callable by MULTISIG_ROLE.
*/
function setAllowedCallsPerPeriod(uint16 _allowedCallsPerPeriod) external requiresAuth {
emit AllowedCallsPeriodUpdated(allowedCallsPerPeriod, _allowedCallsPerPeriod);
allowedCallsPerPeriod = _allowedCallsPerPeriod;
}
/**
* @notice Allows auth to set token approvals to zero.
* @dev Callable by STRATEGIST_ROLE.
*/
function revokeTokenApproval(
bytes32[][] calldata manageProofs,
address[] calldata decodersAndSanitizers,
ERC20[] calldata tokens,
address[] calldata spenders
) external requiresAuth {
uint256 tokensLength = tokens.length;
address[] memory targets = new address[](tokensLength);
bytes[] memory targetData = new bytes[](tokensLength);
uint256[] memory values = new uint256[](tokensLength);
for (uint256 i; i < tokensLength; ++i) {
targets[i] = address(tokens[i]);
targetData[i] = abi.encodeWithSelector(ERC20.approve.selector, spenders[i], 0);
// values[i] = 0;
}
// Make the manage call.
manager.manageVaultWithMerkleVerification(manageProofs, decodersAndSanitizers, targets, targetData, values);
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.0;
/// @title Callback for IUniswapV3PoolActions#swap
/// @notice Any contract that calls IUniswapV3PoolActions#swap must implement this interface
interface IUniswapV3SwapCallback {
/// @notice Called to `msg.sender` after executing a swap via IUniswapV3Pool#swap.
/// @dev In the implementation you must pay the pool tokens owed for the swap.
/// The caller of this method must be checked to be a UniswapV3Pool deployed by the canonical UniswapV3Factory.
/// amount0Delta and amount1Delta can both be 0 if no tokens were swapped.
/// @param amount0Delta The amount of token0 that was sent (negative) or must be received (positive) by the pool by
/// the end of the swap. If positive, the callback must send that amount of token0 to the pool.
/// @param amount1Delta The amount of token1 that was sent (negative) or must be received (positive) by the pool by
/// the end of the swap. If positive, the callback must send that amount of token1 to the pool.
/// @param data Any data passed through by the caller via the IUniswapV3PoolActions#swap call
function uniswapV3SwapCallback(int256 amount0Delta, int256 amount1Delta, bytes calldata data) external;
}
/// @title Router token swapping functionality
/// @notice Functions for swapping tokens via Uniswap V3
interface IUniswapV3Router is IUniswapV3SwapCallback {
struct ExactInputSingleParams {
address tokenIn;
address tokenOut;
uint24 fee;
address recipient;
uint256 deadline;
uint256 amountIn;
uint256 amountOutMinimum;
uint160 sqrtPriceLimitX96;
}
/// @notice Swaps `amountIn` of one token for as much as possible of another token
/// @param params The parameters necessary for the swap, encoded as `ExactInputSingleParams` in calldata
/// @return amountOut The amount of the received token
function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut);
struct ExactInputParams {
bytes path;
address recipient;
uint256 deadline;
uint256 amountIn;
uint256 amountOutMinimum;
}
/// @notice Swaps `amountIn` of one token for as much as possible of another along the specified path
/// @param params The parameters necessary for the multi-hop swap, encoded as `ExactInputParams` in calldata
/// @return amountOut The amount of the received token
function exactInput(ExactInputParams calldata params) external payable returns (uint256 amountOut);
struct ExactOutputSingleParams {
address tokenIn;
address tokenOut;
uint24 fee;
address recipient;
uint256 deadline;
uint256 amountOut;
uint256 amountInMaximum;
uint160 sqrtPriceLimitX96;
}
/// @notice Swaps as little as possible of one token for `amountOut` of another token
/// @param params The parameters necessary for the swap, encoded as `ExactOutputSingleParams` in calldata
/// @return amountIn The amount of the input token
function exactOutputSingle(ExactOutputSingleParams calldata params) external payable returns (uint256 amountIn);
struct ExactOutputParams {
bytes path;
address recipient;
uint256 deadline;
uint256 amountOut;
uint256 amountInMaximum;
}
/// @notice Swaps as little as possible of one token for `amountOut` of another along the specified path (reversed)
/// @param params The parameters necessary for the multi-hop swap, encoded as `ExactOutputParams` in calldata
/// @return amountIn The amount of the input token
function exactOutput(ExactOutputParams calldata params) external payable returns (uint256 amountIn);
}// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.21;
contract DecoderCustomTypes {
// ========================================= BALANCER =========================================
struct JoinPoolRequest {
address[] assets;
uint256[] maxAmountsIn;
bytes userData;
bool fromInternalBalance;
}
struct ExitPoolRequest {
address[] assets;
uint256[] minAmountsOut;
bytes userData;
bool toInternalBalance;
}
enum SwapKind {
GIVEN_IN,
GIVEN_OUT
}
struct SingleSwap {
bytes32 poolId;
SwapKind kind;
address assetIn;
address assetOut;
uint256 amount;
bytes userData;
}
struct FundManagement {
address sender;
bool fromInternalBalance;
address recipient;
bool toInternalBalance;
}
// ========================================= UNISWAP V3 =========================================
struct MintParams {
address token0;
address token1;
uint24 fee;
int24 tickLower;
int24 tickUpper;
uint256 amount0Desired;
uint256 amount1Desired;
uint256 amount0Min;
uint256 amount1Min;
address recipient;
uint256 deadline;
}
struct IncreaseLiquidityParams {
uint256 tokenId;
uint256 amount0Desired;
uint256 amount1Desired;
uint256 amount0Min;
uint256 amount1Min;
uint256 deadline;
}
struct DecreaseLiquidityParams {
uint256 tokenId;
uint128 liquidity;
uint256 amount0Min;
uint256 amount1Min;
uint256 deadline;
}
struct CollectParams {
uint256 tokenId;
address recipient;
uint128 amount0Max;
uint128 amount1Max;
}
struct ExactInputParams {
bytes path;
address recipient;
uint256 deadline;
uint256 amountIn;
uint256 amountOutMinimum;
}
struct ExactInputParamsRouter02 {
bytes path;
address recipient;
uint256 amountIn;
uint256 amountOutMinimum;
}
struct PancakeSwapExactInputParams {
bytes path;
address recipient;
uint256 amountIn;
uint256 amountOutMinimum;
}
// ========================================= UNISWAP V4 =========================================
struct SwapParams {
/// Whether to swap token0 for token1 or vice versa
bool zeroForOne;
/// The desired input amount if negative (exactIn), or the desired output amount if positive (exactOut)
int256 amountSpecified;
/// The sqrt price at which, if reached, the swap will stop executing
uint160 sqrtPriceLimitX96;
}
struct PoolKey {
/// @notice The lower currency of the pool, sorted numerically
address currency0;
/// @notice The higher currency of the pool, sorted numerically
address currency1;
/// @notice The pool LP fee, capped at 1_000_000. If the highest bit is 1, the pool has a dynamic fee and must be exactly equal to 0x800000
uint24 fee;
/// @notice Ticks that involve positions must be a multiple of tick spacing
int24 tickSpacing;
/// @notice The hooks of the pool
address hooks;
}
/// @dev comes from IV4 Router
struct ExactInputSingleParams {
PoolKey poolKey;
bool zeroForOne;
uint128 amountIn;
uint128 amountOutMinimum;
bytes hookData;
}
/// @notice Parameters for a single-hop exact-output swap
struct ExactOutputSingleParams {
PoolKey poolKey;
bool zeroForOne;
uint128 amountOut;
uint128 amountInMaximum;
bytes hookData;
}
// ========================================= MORPHO BLUE =========================================
struct MarketParams {
address loanToken;
address collateralToken;
address oracle;
address irm;
uint256 lltv;
}
// ========================================= 1INCH =========================================
struct SwapDescription {
address srcToken;
address dstToken;
address payable srcReceiver;
address payable dstReceiver;
uint256 amount;
uint256 minReturnAmount;
uint256 flags;
}
// ========================================= PENDLE =========================================
struct TokenInput {
// TOKEN DATA
address tokenIn;
uint256 netTokenIn;
address tokenMintSy;
// AGGREGATOR DATA
address pendleSwap;
SwapData swapData;
}
struct TokenOutput {
// TOKEN DATA
address tokenOut;
uint256 minTokenOut;
address tokenRedeemSy;
// AGGREGATOR DATA
address pendleSwap;
SwapData swapData;
}
struct ApproxParams {
uint256 guessMin;
uint256 guessMax;
uint256 guessOffchain; // pass 0 in to skip this variable
uint256 maxIteration; // every iteration, the diff between guessMin and guessMax will be divided by 2
uint256 eps; // the max eps between the returned result & the correct result, base 1e18. Normally this number will be set
// to 1e15 (1e18/1000 = 0.1%)
}
struct SwapData {
SwapType swapType;
address extRouter;
bytes extCalldata;
bool needScale;
}
enum SwapType {
NONE,
KYBERSWAP,
ONE_INCH,
// ETH_WETH not used in Aggregator
ETH_WETH
}
struct LimitOrderData {
address limitRouter;
uint256 epsSkipMarket; // only used for swap operations, will be ignored otherwise
FillOrderParams[] normalFills;
FillOrderParams[] flashFills;
bytes optData;
}
struct FillOrderParams {
Order order;
bytes signature;
uint256 makingAmount;
}
struct Order {
uint256 salt;
uint256 expiry;
uint256 nonce;
OrderType orderType;
address token;
address YT;
address maker;
address receiver;
uint256 makingAmount;
uint256 lnImpliedRate;
uint256 failSafeRate;
bytes permit;
}
enum OrderType {
SY_FOR_PT,
PT_FOR_SY,
SY_FOR_YT,
YT_FOR_SY
}
// ========================================= EIGEN LAYER =========================================
struct QueuedWithdrawalParams {
// Array of strategies that the QueuedWithdrawal contains
address[] strategies;
// Array containing the amount of shares in each Strategy in the `strategies` array
uint256[] shares;
// The address of the withdrawer
address withdrawer;
}
struct Withdrawal {
// The address that originated the Withdrawal
address staker;
// The address that the staker was delegated to at the time that the Withdrawal was created
address delegatedTo;
// The address that can complete the Withdrawal + will receive funds when completing the withdrawal
address withdrawer;
// Nonce used to guarantee that otherwise identical withdrawals have unique hashes
uint256 nonce;
// Block number when the Withdrawal was created
uint32 startBlock;
// Array of strategies that the Withdrawal contains
address[] strategies;
// Array containing the amount of shares in each Strategy in the `strategies` array
uint256[] shares;
}
struct SignatureWithExpiry {
// the signature itself, formatted as a single bytes object
bytes signature;
// the expiration timestamp (UTC) of the signature
uint256 expiry;
}
struct EarnerTreeMerkleLeaf {
address earner;
bytes32 earnerTokenRoot;
}
struct TokenTreeMerkleLeaf {
address token;
uint256 cumulativeEarnings;
}
struct RewardsMerkleClaim {
uint32 rootIndex;
uint32 earnerIndex;
bytes earnerTreeProof;
EarnerTreeMerkleLeaf earnerLeaf;
uint32[] tokenIndices;
bytes[] tokenTreeProofs;
TokenTreeMerkleLeaf[] tokenLeaves;
}
// ========================================= CCIP =========================================
// If extraArgs is empty bytes, the default is 200k gas limit.
struct EVM2AnyMessage {
bytes receiver; // abi.encode(receiver address) for dest EVM chains
bytes data; // Data payload
EVMTokenAmount[] tokenAmounts; // Token transfers
address feeToken; // Address of feeToken. address(0) means you will send msg.value.
bytes extraArgs; // Populate this with _argsToBytes(EVMExtraArgsV2)
}
/// @dev RMN depends on this struct, if changing, please notify the RMN maintainers.
struct EVMTokenAmount {
address token; // token address on the local chain.
uint256 amount; // Amount of tokens.
}
struct EVMExtraArgsV1 {
uint256 gasLimit;
}
// ========================================= OFT =========================================
struct SendParam {
uint32 dstEid; // Destination endpoint ID.
bytes32 to; // Recipient address.
uint256 amountLD; // Amount to send in local decimals.
uint256 minAmountLD; // Minimum amount to send in local decimals.
bytes extraOptions; // Additional options supplied by the caller to be used in the LayerZero message.
bytes composeMsg; // The composed message for the send() operation.
bytes oftCmd; // The OFT command to be executed, unused in default OFT implementations.
}
struct MessagingFee {
uint256 nativeFee;
uint256 lzTokenFee;
}
// ========================================= L1StandardBridge =========================================
struct WithdrawalTransaction {
uint256 nonce;
address sender;
address target;
uint256 value;
uint256 gasLimit;
bytes data;
}
struct OutputRootProof {
bytes32 version;
bytes32 stateRoot;
bytes32 messagePasserStorageRoot;
bytes32 latestBlockhash;
}
// ========================================= Mantle L1StandardBridge =========================================
struct MantleWithdrawalTransaction {
uint256 nonce;
address sender;
address target;
uint256 mntValue;
uint256 value;
uint256 gasLimit;
bytes data;
}
// ========================================= Linea Bridge =========================================
struct ClaimMessageWithProofParams {
bytes32[] proof;
uint256 messageNumber;
uint32 leafIndex;
address from;
address to;
uint256 fee;
uint256 value;
address payable feeRecipient;
bytes32 merkleRoot;
bytes data;
}
// ========================================= Scroll Bridge =========================================
struct L2MessageProof {
uint256 batchIndex;
bytes merkleProof;
}
// ========================================= Camelot V3 / Algebra V3 =========================================
struct CamelotMintParams {
address token0;
address token1;
int24 tickLower;
int24 tickUpper;
uint256 amount0Desired;
uint256 amount1Desired;
uint256 amount0Min;
uint256 amount1Min;
address recipient;
uint256 deadline;
}
// ========================================= Algebra V4 =========================================
struct AlgebraMintParams {
address token0;
address token1;
address deployer;
int24 tickLower;
int24 tickUpper;
uint256 amount0Desired;
uint256 amount1Desired;
uint256 amount0Min;
uint256 amount1Min;
address recipient;
uint256 deadline;
}
// ========================================= Velodrome V3 =========================================
struct VelodromeMintParams {
address token0;
address token1;
int24 tickSpacing;
int24 tickLower;
int24 tickUpper;
uint256 amount0Desired;
uint256 amount1Desired;
uint256 amount0Min;
uint256 amount1Min;
address recipient;
uint256 deadline;
uint160 sqrtPriceX96;
}
// ========================================= Karak =========================================
struct QueuedWithdrawal {
address staker;
address delegatedTo;
uint256 nonce;
uint256 start;
WithdrawRequest request;
}
struct WithdrawRequest {
address[] vaults;
uint256[] shares;
address withdrawer;
}
// ========================================= Term Finance ==================================
/// @dev TermAuctionOfferSubmission represents an offer submission to offeror an amount of money for a specific interest rate
struct TermAuctionOfferSubmission {
/// @dev For an existing offer this is the unique onchain identifier for this offer. For a new offer this is a randomized input that will be used to generate the unique onchain identifier.
bytes32 id;
/// @dev The address of the offeror
address offeror;
/// @dev Hash of the offered price as a percentage of the initial loaned amount vs amount returned at maturity. This stores 9 decimal places
bytes32 offerPriceHash;
/// @dev The maximum amount of purchase tokens that can be lent
uint256 amount;
/// @dev The address of the ERC20 purchase token
address purchaseToken;
}
// ========================================= Dolomite Finance ==================================
enum BalanceCheckFlag {
Both,
From,
To,
None
}
// ========================================= Silo Finance ==================================
/// @dev There are 2 types of accounting in the system: for non-borrowable collateral deposit called "protected" and
/// for borrowable collateral deposit called "collateral". System does
/// identical calculations for each type of accounting but it uses different data. To avoid code duplication
/// this enum is used to decide which data should be read.
enum CollateralType {
Protected, // default
Collateral
}
enum ActionType {
Deposit,
Mint,
Repay,
RepayShares
}
struct Action {
// what do you want to do?
uint8 actionType;
// which Silo are you interacting with?
address silo;
// what asset do you want to use?
address asset;
// options specific for actions
bytes options;
}
struct AnyAction {
// how much assets or shares do you want to use?
uint256 amount;
// are you using Protected, Collateral
uint8 assetType;
}
// ========================================= LBTC Bridge ==================================
struct DepositBridgeAction {
uint256 fromChain;
bytes32 fromContract;
uint256 toChain;
address toContract;
address recipient;
uint64 amount;
uint256 nonce;
}
// ========================================= Odos ==================================
struct swapTokenInfo {
address inputToken;
uint256 inputAmount;
address inputReceiver;
address outputToken;
uint256 outputQuote;
uint256 outputMin;
address outputReceiver;
}
struct swapTokenInfoOogaBooga {
address inputToken;
uint256 inputAmount;
address outputToken;
uint256 outputQuote;
uint256 outputMin;
address outputReceiver;
}
// ========================================= Level ==================================
/// @dev for reference
//enum OrderType {
// MINT,
// REDEEM
//}
struct LevelOrder {
uint8 order_type;
address benefactor;
address beneficiary;
address collateral_asset;
uint256 collateral_amount;
uint256 lvlusd_amount;
}
struct LevelOrderV2 {
address beneficiary;
address collateral_asset;
uint256 collateral_amount;
uint256 min_lvlusd_amount;
}
struct Route {
address[] addresses;
uint256[] ratios;
}
// ========================================= Royco ==================================
struct APOffer { // RecipeMarketHub
uint256 offerID;
bytes32 targetMarketHash;
address ap;
address fundingVault;
uint256 quantity;
uint256 expiry;
address[] incentivesRequested;
uint256[] incentiveAmountsRequested;
}
struct APOfferVault { // VaultMarketHub (renamed to avoid collision)
uint256 offerID;
address targetVault;
address ap;
address fundingVault;
uint256 expiry;
address[] incentivesRequested;
uint256[] incentivesRatesRequested;
}
struct Reward {
uint48 startEpoch;
uint48 endEpoch;
address token;
uint256 rewardRate;
}
// ========================================= Permit2 ==================================
struct TokenSpenderPair {
address token;
address spender;
}
// ========================================= OnChainQueue ==================================
struct OnChainWithdraw {
uint96 nonce; // read from state, used to make it impossible for request Ids to be repeated.
address user; // msg.sender
address assetOut; // input sanitized
uint128 amountOfShares; // input transfered in
uint128 amountOfAssets; // derived from amountOfShares and price
uint40 creationTime; // time withdraw was made
uint24 secondsToMaturity; // in contract, from withdrawAsset?
uint24 secondsToDeadline; // in contract, from withdrawAsset? To get the deadline you take the creationTime add seconds to maturity, add the secondsToDeadline
}
// ========================================= Beraborrow ==================================
struct OpenDenVaultParams {
address denManager;
address collVault;
uint256 _maxFeePercentage;
uint256 _debtAmount;
uint256 _collAssetToDeposit;
address _upperHint;
address _lowerHint;
uint256 _minSharesMinted;
uint256 _collIndex;
bytes _preDeposit;
}
struct AdjustDenVaultParams {
address denManager;
address collVault;
uint256 _maxFeePercentage;
uint256 _collAssetToDeposit;
uint256 _collWithdrawal;
uint256 _debtChange;
bool _isDebtIncrease;
address _upperHint;
address _lowerHint;
bool unwrap;
uint256 _minSharesMinted;
uint256 _minAssetsWithdrawn;
uint256 _collIndex;
bytes _preDeposit;
}
struct RedeemCollateralVaultParams {
address denManager;
address collVault;
uint256 _debtAmount;
address _firstRedemptionHint;
address _upperPartialRedemptionHint;
address _lowerPartialRedemptionHint;
uint256 _partialRedemptionHintNICR;
uint256 _maxIterations;
uint256 _maxFeePercentage;
uint256 _minSharesWithdrawn;
uint256 minAssetsWithdrawn;
uint256 collIndex;
bool unwrap;
}
struct AddCollParams {
address upperHint;
address lowerHint;
uint256 minSharesOut;
uint256 minCollVaultShares;
}
struct ExternalRebalanceParams {
address swapper;
bytes payload;
uint256 minRebalanceOut;
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.21;
import {DecoderCustomTypes} from "src/interfaces/DecoderCustomTypes.sol";
interface BalancerVault {
function flashLoan(address, address[] memory tokens, uint256[] memory amounts, bytes calldata userData) external;
function swap(
DecoderCustomTypes.SingleSwap memory singleSwap,
DecoderCustomTypes.FundManagement memory funds,
uint256 limit,
uint256 deadline
) external returns (uint256 amountCalculated);
}// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.21;
import {Address} from "@openzeppelin/contracts/utils/Address.sol";
import {ERC721Holder} from "@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol";
import {ERC1155Holder} from "@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol";
import {FixedPointMathLib} from "@solmate/utils/FixedPointMathLib.sol";
import {SafeTransferLib} from "@solmate/utils/SafeTransferLib.sol";
import {ERC20} from "@solmate/tokens/ERC20.sol";
import {BeforeTransferHook} from "src/interfaces/BeforeTransferHook.sol";
import {Auth, Authority} from "@solmate/auth/Auth.sol";
contract BoringVault is ERC20, Auth, ERC721Holder, ERC1155Holder {
using Address for address;
using SafeTransferLib for ERC20;
using FixedPointMathLib for uint256;
// ========================================= STATE =========================================
/**
* @notice Contract responsbile for implementing `beforeTransfer`.
*/
BeforeTransferHook public hook;
//============================== EVENTS ===============================
event Enter(address indexed from, address indexed asset, uint256 amount, address indexed to, uint256 shares);
event Exit(address indexed to, address indexed asset, uint256 amount, address indexed from, uint256 shares);
//============================== CONSTRUCTOR ===============================
constructor(address _owner, string memory _name, string memory _symbol, uint8 _decimals)
ERC20(_name, _symbol, _decimals)
Auth(_owner, Authority(address(0)))
{}
//============================== MANAGE ===============================
/**
* @notice Allows manager to make an arbitrary function call from this contract.
* @dev Callable by MANAGER_ROLE.
*/
function manage(address target, bytes calldata data, uint256 value)
external
requiresAuth
returns (bytes memory result)
{
result = target.functionCallWithValue(data, value);
}
/**
* @notice Allows manager to make arbitrary function calls from this contract.
* @dev Callable by MANAGER_ROLE.
*/
function manage(address[] calldata targets, bytes[] calldata data, uint256[] calldata values)
external
requiresAuth
returns (bytes[] memory results)
{
uint256 targetsLength = targets.length;
results = new bytes[](targetsLength);
for (uint256 i; i < targetsLength; ++i) {
results[i] = targets[i].functionCallWithValue(data[i], values[i]);
}
}
//============================== ENTER ===============================
/**
* @notice Allows minter to mint shares, in exchange for assets.
* @dev If assetAmount is zero, no assets are transferred in.
* @dev Callable by MINTER_ROLE.
*/
function enter(address from, ERC20 asset, uint256 assetAmount, address to, uint256 shareAmount)
external
requiresAuth
{
// Transfer assets in
if (assetAmount > 0) asset.safeTransferFrom(from, address(this), assetAmount);
// Mint shares.
_mint(to, shareAmount);
emit Enter(from, address(asset), assetAmount, to, shareAmount);
}
//============================== EXIT ===============================
/**
* @notice Allows burner to burn shares, in exchange for assets.
* @dev If assetAmount is zero, no assets are transferred out.
* @dev Callable by BURNER_ROLE.
*/
function exit(address to, ERC20 asset, uint256 assetAmount, address from, uint256 shareAmount)
external
requiresAuth
{
// Burn shares.
_burn(from, shareAmount);
// Transfer assets out.
if (assetAmount > 0) asset.safeTransfer(to, assetAmount);
emit Exit(to, address(asset), assetAmount, from, shareAmount);
}
//============================== BEFORE TRANSFER HOOK ===============================
/**
* @notice Sets the share locker.
* @notice If set to zero address, the share locker logic is disabled.
* @dev Callable by OWNER_ROLE.
*/
function setBeforeTransferHook(address _hook) external requiresAuth {
hook = BeforeTransferHook(_hook);
}
/**
* @notice Call `beforeTransferHook` passing in `from` `to`, and `msg.sender`.
*/
function _callBeforeTransfer(address from, address to) internal view {
if (address(hook) != address(0)) hook.beforeTransfer(from, to, msg.sender);
}
function transfer(address to, uint256 amount) public override returns (bool) {
_callBeforeTransfer(msg.sender, to);
return super.transfer(to, amount);
}
function transferFrom(address from, address to, uint256 amount) public override returns (bool) {
_callBeforeTransfer(from, to);
return super.transferFrom(from, to, amount);
}
//============================== RECEIVE ===============================
receive() external payable {}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
/// @notice Provides a flexible and updatable auth pattern which is completely separate from application logic.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/auth/Auth.sol)
/// @author Modified from Dappsys (https://github.com/dapphub/ds-auth/blob/master/src/auth.sol)
abstract contract Auth {
event OwnershipTransferred(address indexed user, address indexed newOwner);
event AuthorityUpdated(address indexed user, Authority indexed newAuthority);
address public owner;
Authority public authority;
constructor(address _owner, Authority _authority) {
owner = _owner;
authority = _authority;
emit OwnershipTransferred(msg.sender, _owner);
emit AuthorityUpdated(msg.sender, _authority);
}
modifier requiresAuth() virtual {
require(isAuthorized(msg.sender, msg.sig), "UNAUTHORIZED");
_;
}
function isAuthorized(address user, bytes4 functionSig) internal view virtual returns (bool) {
Authority auth = authority; // Memoizing authority saves us a warm SLOAD, around 100 gas.
// Checking if the caller is the owner only after calling the authority saves gas in most cases, but be
// aware that this makes protected functions uncallable even to the owner if the authority is out of order.
return (address(auth) != address(0) && auth.canCall(user, address(this), functionSig)) || user == owner;
}
function setAuthority(Authority newAuthority) public virtual {
// We check if the caller is the owner first because we want to ensure they can
// always swap out the authority even if it's reverting or using up a lot of gas.
require(msg.sender == owner || authority.canCall(msg.sender, address(this), msg.sig));
authority = newAuthority;
emit AuthorityUpdated(msg.sender, newAuthority);
}
function transferOwnership(address newOwner) public virtual requiresAuth {
owner = newOwner;
emit OwnershipTransferred(msg.sender, newOwner);
}
}
/// @notice A generic interface for a contract which provides authorization data to an Auth instance.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/auth/Auth.sol)
/// @author Modified from Dappsys (https://github.com/dapphub/ds-auth/blob/master/src/auth.sol)
interface Authority {
function canCall(
address user,
address target,
bytes4 functionSig
) external view returns (bool);
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
/// @notice Arithmetic library with operations for fixed-point numbers.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol)
/// @author Inspired by USM (https://github.com/usmfum/USM/blob/master/contracts/WadMath.sol)
library FixedPointMathLib {
/*//////////////////////////////////////////////////////////////
SIMPLIFIED FIXED POINT OPERATIONS
//////////////////////////////////////////////////////////////*/
uint256 internal constant MAX_UINT256 = 2**256 - 1;
uint256 internal constant WAD = 1e18; // The scalar of ETH and most ERC20s.
function mulWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivDown(x, y, WAD); // Equivalent to (x * y) / WAD rounded down.
}
function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivUp(x, y, WAD); // Equivalent to (x * y) / WAD rounded up.
}
function divWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivDown(x, WAD, y); // Equivalent to (x * WAD) / y rounded down.
}
function divWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivUp(x, WAD, y); // Equivalent to (x * WAD) / y rounded up.
}
/*//////////////////////////////////////////////////////////////
LOW LEVEL FIXED POINT OPERATIONS
//////////////////////////////////////////////////////////////*/
function mulDivDown(
uint256 x,
uint256 y,
uint256 denominator
) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y))
if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) {
revert(0, 0)
}
// Divide x * y by the denominator.
z := div(mul(x, y), denominator)
}
}
function mulDivUp(
uint256 x,
uint256 y,
uint256 denominator
) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y))
if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) {
revert(0, 0)
}
// If x * y modulo the denominator is strictly greater than 0,
// 1 is added to round up the division of x * y by the denominator.
z := add(gt(mod(mul(x, y), denominator), 0), div(mul(x, y), denominator))
}
}
function rpow(
uint256 x,
uint256 n,
uint256 scalar
) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
switch x
case 0 {
switch n
case 0 {
// 0 ** 0 = 1
z := scalar
}
default {
// 0 ** n = 0
z := 0
}
}
default {
switch mod(n, 2)
case 0 {
// If n is even, store scalar in z for now.
z := scalar
}
default {
// If n is odd, store x in z for now.
z := x
}
// Shifting right by 1 is like dividing by 2.
let half := shr(1, scalar)
for {
// Shift n right by 1 before looping to halve it.
n := shr(1, n)
} n {
// Shift n right by 1 each iteration to halve it.
n := shr(1, n)
} {
// Revert immediately if x ** 2 would overflow.
// Equivalent to iszero(eq(div(xx, x), x)) here.
if shr(128, x) {
revert(0, 0)
}
// Store x squared.
let xx := mul(x, x)
// Round to the nearest number.
let xxRound := add(xx, half)
// Revert if xx + half overflowed.
if lt(xxRound, xx) {
revert(0, 0)
}
// Set x to scaled xxRound.
x := div(xxRound, scalar)
// If n is even:
if mod(n, 2) {
// Compute z * x.
let zx := mul(z, x)
// If z * x overflowed:
if iszero(eq(div(zx, x), z)) {
// Revert if x is non-zero.
if iszero(iszero(x)) {
revert(0, 0)
}
}
// Round to the nearest number.
let zxRound := add(zx, half)
// Revert if zx + half overflowed.
if lt(zxRound, zx) {
revert(0, 0)
}
// Return properly scaled zxRound.
z := div(zxRound, scalar)
}
}
}
}
}
/*//////////////////////////////////////////////////////////////
GENERAL NUMBER UTILITIES
//////////////////////////////////////////////////////////////*/
function sqrt(uint256 x) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
let y := x // We start y at x, which will help us make our initial estimate.
z := 181 // The "correct" value is 1, but this saves a multiplication later.
// This segment is to get a reasonable initial estimate for the Babylonian method. With a bad
// start, the correct # of bits increases ~linearly each iteration instead of ~quadratically.
// We check y >= 2^(k + 8) but shift right by k bits
// each branch to ensure that if x >= 256, then y >= 256.
if iszero(lt(y, 0x10000000000000000000000000000000000)) {
y := shr(128, y)
z := shl(64, z)
}
if iszero(lt(y, 0x1000000000000000000)) {
y := shr(64, y)
z := shl(32, z)
}
if iszero(lt(y, 0x10000000000)) {
y := shr(32, y)
z := shl(16, z)
}
if iszero(lt(y, 0x1000000)) {
y := shr(16, y)
z := shl(8, z)
}
// Goal was to get z*z*y within a small factor of x. More iterations could
// get y in a tighter range. Currently, we will have y in [256, 256*2^16).
// We ensured y >= 256 so that the relative difference between y and y+1 is small.
// That's not possible if x < 256 but we can just verify those cases exhaustively.
// Now, z*z*y <= x < z*z*(y+1), and y <= 2^(16+8), and either y >= 256, or x < 256.
// Correctness can be checked exhaustively for x < 256, so we assume y >= 256.
// Then z*sqrt(y) is within sqrt(257)/sqrt(256) of sqrt(x), or about 20bps.
// For s in the range [1/256, 256], the estimate f(s) = (181/1024) * (s+1) is in the range
// (1/2.84 * sqrt(s), 2.84 * sqrt(s)), with largest error when s = 1 and when s = 256 or 1/256.
// Since y is in [256, 256*2^16), let a = y/65536, so that a is in [1/256, 256). Then we can estimate
// sqrt(y) using sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2^18.
// There is no overflow risk here since y < 2^136 after the first branch above.
z := shr(18, mul(z, add(y, 65536))) // A mul() is saved from starting z at 181.
// Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough.
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
// If x+1 is a perfect square, the Babylonian method cycles between
// floor(sqrt(x)) and ceil(sqrt(x)). This statement ensures we return floor.
// See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division
// Since the ceil is rare, we save gas on the assignment and repeat division in the rare case.
// If you don't care whether the floor or ceil square root is returned, you can remove this statement.
z := sub(z, lt(div(x, z), z))
}
}
function unsafeMod(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Mod x by y. Note this will return
// 0 instead of reverting if y is zero.
z := mod(x, y)
}
}
function unsafeDiv(uint256 x, uint256 y) internal pure returns (uint256 r) {
/// @solidity memory-safe-assembly
assembly {
// Divide x by y. Note this will return
// 0 instead of reverting if y is zero.
r := div(x, y)
}
}
function unsafeDivUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Add 1 to x * y if x % y > 0. Note this will
// return 0 instead of reverting if y is zero.
z := add(gt(mod(x, y), 0), div(x, y))
}
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.21;
import {FixedPointMathLib} from "@solmate/utils/FixedPointMathLib.sol";
import {BoringVault} from "src/base/BoringVault.sol";
import {MerkleProofLib} from "@solmate/utils/MerkleProofLib.sol";
import {ERC20} from "@solmate/tokens/ERC20.sol";
import {SafeTransferLib} from "@solmate/utils/SafeTransferLib.sol";
import {Address} from "@openzeppelin/contracts/utils/Address.sol";
import {BalancerVault} from "src/interfaces/BalancerVault.sol";
import {Auth, Authority} from "@solmate/auth/Auth.sol";
import {IPausable} from "src/interfaces/IPausable.sol";
import {DroneLib} from "src/base/Drones/DroneLib.sol";
contract ManagerWithMerkleVerification is Auth, IPausable {
using FixedPointMathLib for uint256;
using SafeTransferLib for ERC20;
using Address for address;
// ========================================= STATE =========================================
/**
* @notice A merkle tree root that restricts what data can be passed to the BoringVault.
* @dev Maps a strategist address to their specific merkle root.
* @dev Each leaf is composed of the keccak256 hash of abi.encodePacked {decodersAndSanitizer, target, valueIsNonZero, selector, argumentAddress_0, ...., argumentAddress_N}
* Where:
* - decodersAndSanitizer is the addres to call to extract packed address arguments from the calldata
* - target is the address to make the call to
* - valueIsNonZero is a bool indicating whether or not the value is non-zero
* - selector is the function selector on target
* - argumentAddress is each allowed address argument in that call
*/
mapping(address => bytes32) public manageRoot;
/**
* @notice Bool indicating whether or not this contract is actively performing a flash loan.
* @dev Used to block flash loans that are initiated outside a manage call.
*/
bool internal performingFlashLoan;
/**
* @notice keccak256 hash of flash loan data.
*/
bytes32 internal flashLoanIntentHash = bytes32(0);
/**
* @notice Used to pause calls to `manageVaultWithMerkleVerification`.
*/
bool public isPaused;
//============================== ERRORS ===============================
error ManagerWithMerkleVerification__InvalidManageProofLength();
error ManagerWithMerkleVerification__InvalidTargetDataLength();
error ManagerWithMerkleVerification__InvalidValuesLength();
error ManagerWithMerkleVerification__InvalidDecodersAndSanitizersLength();
error ManagerWithMerkleVerification__FlashLoanNotExecuted();
error ManagerWithMerkleVerification__FlashLoanNotInProgress();
error ManagerWithMerkleVerification__BadFlashLoanIntentHash();
error ManagerWithMerkleVerification__FailedToVerifyManageProof(address target, bytes targetData, uint256 value);
error ManagerWithMerkleVerification__Paused();
error ManagerWithMerkleVerification__OnlyCallableByBoringVault();
error ManagerWithMerkleVerification__OnlyCallableByBalancerVault();
error ManagerWithMerkleVerification__TotalSupplyMustRemainConstantDuringPlatform();
//============================== EVENTS ===============================
event ManageRootUpdated(address indexed strategist, bytes32 oldRoot, bytes32 newRoot);
event BoringVaultManaged(uint256 callsMade);
event Paused();
event Unpaused();
//============================== IMMUTABLES ===============================
/**
* @notice The BoringVault this contract can manage.
*/
BoringVault public immutable vault;
/**
* @notice The balancer vault this contract can use for flash loans.
*/
BalancerVault public immutable balancerVault;
constructor(address _owner, address _vault, address _balancerVault) Auth(_owner, Authority(address(0))) {
vault = BoringVault(payable(_vault));
balancerVault = BalancerVault(_balancerVault);
}
// ========================================= ADMIN FUNCTIONS =========================================
/**
* @notice Sets the manageRoot.
* @dev Callable by OWNER_ROLE.
*/
function setManageRoot(address strategist, bytes32 _manageRoot) external requiresAuth {
bytes32 oldRoot = manageRoot[strategist];
manageRoot[strategist] = _manageRoot;
emit ManageRootUpdated(strategist, oldRoot, _manageRoot);
}
/**
* @notice Pause this contract, which prevents future calls to `manageVaultWithMerkleVerification`.
* @dev Callable by MULTISIG_ROLE.
*/
function pause() external requiresAuth {
isPaused = true;
emit Paused();
}
/**
* @notice Unpause this contract, which allows future calls to `manageVaultWithMerkleVerification`.
* @dev Callable by MULTISIG_ROLE.
*/
function unpause() external requiresAuth {
isPaused = false;
emit Unpaused();
}
// ========================================= STRATEGIST FUNCTIONS =========================================
/**
* @notice Allows strategist to manage the BoringVault.
* @dev The strategist must provide a merkle proof for every call that verifiees they are allowed to make that call.
* @dev Callable by MANAGER_INTERNAL_ROLE.
* @dev Callable by STRATEGIST_ROLE.
* @dev Callable by MICRO_MANAGER_ROLE.
*/
function manageVaultWithMerkleVerification(
bytes32[][] calldata manageProofs,
address[] calldata decodersAndSanitizers,
address[] calldata targets,
bytes[] calldata targetData,
uint256[] calldata values
) external requiresAuth {
if (isPaused) revert ManagerWithMerkleVerification__Paused();
uint256 targetsLength = targets.length;
if (targetsLength != manageProofs.length) revert ManagerWithMerkleVerification__InvalidManageProofLength();
if (targetsLength != targetData.length) revert ManagerWithMerkleVerification__InvalidTargetDataLength();
if (targetsLength != values.length) revert ManagerWithMerkleVerification__InvalidValuesLength();
if (targetsLength != decodersAndSanitizers.length) {
revert ManagerWithMerkleVerification__InvalidDecodersAndSanitizersLength();
}
bytes32 strategistManageRoot = manageRoot[msg.sender];
uint256 totalSupply = vault.totalSupply();
for (uint256 i; i < targetsLength; ++i) {
_verifyCallData(
strategistManageRoot, manageProofs[i], decodersAndSanitizers[i], targets[i], values[i], targetData[i]
);
vault.manage(targets[i], targetData[i], values[i]);
}
if (totalSupply != vault.totalSupply()) {
revert ManagerWithMerkleVerification__TotalSupplyMustRemainConstantDuringPlatform();
}
emit BoringVaultManaged(targetsLength);
}
// ========================================= FLASH LOAN FUNCTIONS =========================================
/**
* @notice In order to perform a flash loan,
* 1) Merkle root must contain the leaf(address(this), this.flashLoan.selector, ARGUMENT_ADDRESSES ...)
* 2) Strategist must initiate the flash loan using `manageVaultWithMerkleVerification`
* 3) balancerVault MUST callback to this contract with the same userData
*/
function flashLoan(
address recipient,
address[] calldata tokens,
uint256[] calldata amounts,
bytes calldata userData
) external {
if (msg.sender != address(vault)) revert ManagerWithMerkleVerification__OnlyCallableByBoringVault();
flashLoanIntentHash = keccak256(userData);
performingFlashLoan = true;
balancerVault.flashLoan(recipient, tokens, amounts, userData);
performingFlashLoan = false;
if (flashLoanIntentHash != bytes32(0)) revert ManagerWithMerkleVerification__FlashLoanNotExecuted();
}
/**
* @notice Add support for balancer flash loans.
* @dev userData can optionally have salt encoded at the end of it, in order to change the intentHash,
* if a flash loan is exact userData is being repeated, and their is fear of 3rd parties
* front-running the rebalance.
*/
function receiveFlashLoan(
address[] calldata tokens,
uint256[] calldata amounts,
uint256[] calldata feeAmounts,
bytes calldata userData
) external {
if (msg.sender != address(balancerVault)) revert ManagerWithMerkleVerification__OnlyCallableByBalancerVault();
if (!performingFlashLoan) revert ManagerWithMerkleVerification__FlashLoanNotInProgress();
// Validate userData using intentHash.
bytes32 intentHash = keccak256(userData);
if (intentHash != flashLoanIntentHash) revert ManagerWithMerkleVerification__BadFlashLoanIntentHash();
// reset intent hash to prevent replays.
flashLoanIntentHash = bytes32(0);
// Transfer tokens to vault.
for (uint256 i = 0; i < amounts.length; ++i) {
ERC20(tokens[i]).safeTransfer(address(vault), amounts[i]);
}
{
(
bytes32[][] memory manageProofs,
address[] memory decodersAndSanitizers,
address[] memory targets,
bytes[] memory data,
uint256[] memory values
) = abi.decode(userData, (bytes32[][], address[], address[], bytes[], uint256[]));
ManagerWithMerkleVerification(address(this)).manageVaultWithMerkleVerification(
manageProofs, decodersAndSanitizers, targets, data, values
);
}
// Transfer tokens back to balancer.
// Have vault transfer amount + fees back to balancer
bytes[] memory transferData = new bytes[](amounts.length);
for (uint256 i; i < amounts.length; ++i) {
transferData[i] =
abi.encodeWithSelector(ERC20.transfer.selector, address(balancerVault), (amounts[i] + feeAmounts[i]));
}
// Values is always zero, just pass in an array of zeroes.
vault.manage(tokens, transferData, new uint256[](amounts.length));
}
// ========================================= INTERNAL HELPER FUNCTIONS =========================================
/**
* @notice Helper function to decode, sanitize, and verify call data.
*/
function _verifyCallData(
bytes32 currentManageRoot,
bytes32[] calldata manageProof,
address decoderAndSanitizer,
address target,
uint256 value,
bytes calldata targetData
) internal view {
// Use address decoder to get addresses in call data.
bytes memory packedArgumentAddresses = abi.decode(decoderAndSanitizer.functionStaticCall(targetData), (bytes));
address droneTarget = DroneLib.extractTargetFromInput(targetData);
if (droneTarget != address(0)) {
packedArgumentAddresses = abi.encodePacked(packedArgumentAddresses, droneTarget);
}
if (
!_verifyManageProof(
currentManageRoot,
manageProof,
target,
decoderAndSanitizer,
value,
bytes4(targetData),
packedArgumentAddresses
)
) {
revert ManagerWithMerkleVerification__FailedToVerifyManageProof(target, targetData, value);
}
}
/**
* @notice Helper function to verify a manageProof is valid.
*/
function _verifyManageProof(
bytes32 root,
bytes32[] calldata proof,
address target,
address decoderAndSanitizer,
uint256 value,
bytes4 selector,
bytes memory packedArgumentAddresses
) internal pure returns (bool) {
bool valueNonZero = value > 0;
bytes32 leaf =
keccak256(abi.encodePacked(decoderAndSanitizer, target, valueNonZero, selector, packedArgumentAddresses));
return MerkleProofLib.verify(proof, root, leaf);
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol)
/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)
/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.
abstract contract ERC20 {
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/
event Transfer(address indexed from, address indexed to, uint256 amount);
event Approval(address indexed owner, address indexed spender, uint256 amount);
/*//////////////////////////////////////////////////////////////
METADATA STORAGE
//////////////////////////////////////////////////////////////*/
string public name;
string public symbol;
uint8 public immutable decimals;
/*//////////////////////////////////////////////////////////////
ERC20 STORAGE
//////////////////////////////////////////////////////////////*/
uint256 public totalSupply;
mapping(address => uint256) public balanceOf;
mapping(address => mapping(address => uint256)) public allowance;
/*//////////////////////////////////////////////////////////////
EIP-2612 STORAGE
//////////////////////////////////////////////////////////////*/
uint256 internal immutable INITIAL_CHAIN_ID;
bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;
mapping(address => uint256) public nonces;
/*//////////////////////////////////////////////////////////////
CONSTRUCTOR
//////////////////////////////////////////////////////////////*/
constructor(
string memory _name,
string memory _symbol,
uint8 _decimals
) {
name = _name;
symbol = _symbol;
decimals = _decimals;
INITIAL_CHAIN_ID = block.chainid;
INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
}
/*//////////////////////////////////////////////////////////////
ERC20 LOGIC
//////////////////////////////////////////////////////////////*/
function approve(address spender, uint256 amount) public virtual returns (bool) {
allowance[msg.sender][spender] = amount;
emit Approval(msg.sender, spender, amount);
return true;
}
function transfer(address to, uint256 amount) public virtual returns (bool) {
balanceOf[msg.sender] -= amount;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += amount;
}
emit Transfer(msg.sender, to, amount);
return true;
}
function transferFrom(
address from,
address to,
uint256 amount
) public virtual returns (bool) {
uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.
if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;
balanceOf[from] -= amount;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += amount;
}
emit Transfer(from, to, amount);
return true;
}
/*//////////////////////////////////////////////////////////////
EIP-2612 LOGIC
//////////////////////////////////////////////////////////////*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) public virtual {
require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED");
// Unchecked because the only math done is incrementing
// the owner's nonce which cannot realistically overflow.
unchecked {
address recoveredAddress = ecrecover(
keccak256(
abi.encodePacked(
"\x19\x01",
DOMAIN_SEPARATOR(),
keccak256(
abi.encode(
keccak256(
"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
),
owner,
spender,
value,
nonces[owner]++,
deadline
)
)
)
),
v,
r,
s
);
require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER");
allowance[recoveredAddress][spender] = value;
}
emit Approval(owner, spender, value);
}
function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();
}
function computeDomainSeparator() internal view virtual returns (bytes32) {
return
keccak256(
abi.encode(
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
keccak256(bytes(name)),
keccak256("1"),
block.chainid,
address(this)
)
);
}
/*//////////////////////////////////////////////////////////////
INTERNAL MINT/BURN LOGIC
//////////////////////////////////////////////////////////////*/
function _mint(address to, uint256 amount) internal virtual {
totalSupply += amount;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += amount;
}
emit Transfer(address(0), to, amount);
}
function _burn(address from, uint256 amount) internal virtual {
balanceOf[from] -= amount;
// Cannot underflow because a user's balance
// will never be larger than the total supply.
unchecked {
totalSupply -= amount;
}
emit Transfer(from, address(0), amount);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)
pragma solidity ^0.8.20;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/
error AddressInsufficientBalance(address account);
/**
* @dev There's no code at `target` (it is not a contract).
*/
error AddressEmptyCode(address target);
/**
* @dev A call to an address target failed. The target may have reverted.
*/
error FailedInnerCall();
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert AddressInsufficientBalance(address(this));
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert FailedInnerCall();
}
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason or custom error, it is bubbled
* up by this function (like regular Solidity function calls). However, if
* the call reverted with no returned reason, this function reverts with a
* {FailedInnerCall} error.
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert AddressInsufficientBalance(address(this));
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
* was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
* unsuccessful call.
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
// only check if target is a contract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
/**
* @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
* revert reason or with a default {FailedInnerCall} error.
*/
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
/**
* @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
*/
function _revert(bytes memory returndata) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert FailedInnerCall();
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/utils/ERC721Holder.sol)
pragma solidity ^0.8.20;
import {IERC721Receiver} from "../IERC721Receiver.sol";
/**
* @dev Implementation of the {IERC721Receiver} interface.
*
* Accepts all token transfers.
* Make sure the contract is able to use its token with {IERC721-safeTransferFrom}, {IERC721-approve} or
* {IERC721-setApprovalForAll}.
*/
abstract contract ERC721Holder is IERC721Receiver {
/**
* @dev See {IERC721Receiver-onERC721Received}.
*
* Always returns `IERC721Receiver.onERC721Received.selector`.
*/
function onERC721Received(address, address, uint256, bytes memory) public virtual returns (bytes4) {
return this.onERC721Received.selector;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/utils/ERC1155Holder.sol)
pragma solidity ^0.8.20;
import {IERC165, ERC165} from "../../../utils/introspection/ERC165.sol";
import {IERC1155Receiver} from "../IERC1155Receiver.sol";
/**
* @dev Simple implementation of `IERC1155Receiver` that will allow a contract to hold ERC1155 tokens.
*
* IMPORTANT: When inheriting this contract, you must include a way to use the received tokens, otherwise they will be
* stuck.
*/
abstract contract ERC1155Holder is ERC165, IERC1155Receiver {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
return interfaceId == type(IERC1155Receiver).interfaceId || super.supportsInterface(interfaceId);
}
function onERC1155Received(
address,
address,
uint256,
uint256,
bytes memory
) public virtual override returns (bytes4) {
return this.onERC1155Received.selector;
}
function onERC1155BatchReceived(
address,
address,
uint256[] memory,
uint256[] memory,
bytes memory
) public virtual override returns (bytes4) {
return this.onERC1155BatchReceived.selector;
}
}// SPDX-License-Identifier: 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: UNLICENSED
pragma solidity 0.8.21;
interface BeforeTransferHook {
function beforeTransfer(address from, address to, address operator) external view;
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
/// @notice Gas optimized merkle proof verification library.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/MerkleProofLib.sol)
/// @author Modified from Solady (https://github.com/Vectorized/solady/blob/main/src/utils/MerkleProofLib.sol)
library MerkleProofLib {
function verify(
bytes32[] calldata proof,
bytes32 root,
bytes32 leaf
) internal pure returns (bool isValid) {
/// @solidity memory-safe-assembly
assembly {
if proof.length {
// Left shifting by 5 is like multiplying by 32.
let end := add(proof.offset, shl(5, proof.length))
// Initialize offset to the offset of the proof in calldata.
let offset := proof.offset
// Iterate over proof elements to compute root hash.
// prettier-ignore
for {} 1 {} {
// Slot where the leaf should be put in scratch space. If
// leaf > calldataload(offset): slot 32, otherwise: slot 0.
let leafSlot := shl(5, gt(leaf, calldataload(offset)))
// Store elements to hash contiguously in scratch space.
// The xor puts calldataload(offset) in whichever slot leaf
// is not occupying, so 0 if leafSlot is 32, and 32 otherwise.
mstore(leafSlot, leaf)
mstore(xor(leafSlot, 32), calldataload(offset))
// Reuse leaf to store the hash to reduce stack operations.
leaf := keccak256(0, 64) // Hash both slots of scratch space.
offset := add(offset, 32) // Shift 1 word per cycle.
// prettier-ignore
if iszero(lt(offset, end)) { break }
}
}
isValid := eq(leaf, root) // The proof is valid if the roots match.
}
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.21;
interface IPausable {
function pause() external;
function unpause() external;
}// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.0;
library DroneLib {
bytes32 internal constant TARGET_FLAG = keccak256(bytes("DroneLib.target"));
function extractTargetFromCalldata() internal pure returns (address target) {
target = extractTargetFromInput(msg.data);
}
function extractTargetFromInput(bytes calldata data) internal pure returns (address target) {
// Look at the last 32 bytes of calldata and see if the TARGET_FLAG is there.
uint256 length = data.length;
if (length >= 68) {
bytes32 flag = bytes32(data[length - 32:]);
if (flag == TARGET_FLAG) {
// If the flag is there, extract the target from the calldata.
target = address(bytes20(data[length - 52:length - 32]));
}
}
// else no target present, so target is address(0).
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721Receiver.sol)
pragma solidity ^0.8.20;
/**
* @title ERC721 token receiver interface
* @dev Interface for any contract that wants to support safeTransfers
* from ERC721 asset contracts.
*/
interface IERC721Receiver {
/**
* @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
* by `operator` from `from`, this function is called.
*
* It must return its Solidity selector to confirm the token transfer.
* If any other value is returned or the interface is not implemented by the recipient, the transfer will be
* reverted.
*
* The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
*/
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/IERC1155Receiver.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../../utils/introspection/IERC165.sol";
/**
* @dev Interface that must be implemented by smart contracts in order to receive
* ERC-1155 token transfers.
*/
interface IERC1155Receiver is IERC165 {
/**
* @dev Handles the receipt of a single ERC1155 token type. This function is
* called at the end of a `safeTransferFrom` after the balance has been updated.
*
* NOTE: To accept the transfer, this must return
* `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
* (i.e. 0xf23a6e61, or its own function selector).
*
* @param operator The address which initiated the transfer (i.e. msg.sender)
* @param from The address which previously owned the token
* @param id The ID of the token being transferred
* @param value The amount of tokens being transferred
* @param data Additional data with no specified format
* @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed
*/
function onERC1155Received(
address operator,
address from,
uint256 id,
uint256 value,
bytes calldata data
) external returns (bytes4);
/**
* @dev Handles the receipt of a multiple ERC1155 token types. This function
* is called at the end of a `safeBatchTransferFrom` after the balances have
* been updated.
*
* NOTE: To accept the transfer(s), this must return
* `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
* (i.e. 0xbc197c81, or its own function selector).
*
* @param operator The address which initiated the batch transfer (i.e. msg.sender)
* @param from The address which previously owned the token
* @param ids An array containing ids of each token being transferred (order and length must match values array)
* @param values An array containing amounts of each token being transferred (order and length must match ids array)
* @param data Additional data with no specified format
* @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed
*/
function onERC1155BatchReceived(
address operator,
address from,
uint256[] calldata ids,
uint256[] calldata values,
bytes calldata data
) external returns (bytes4);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}{
"remappings": [
"@solmate/=lib/solmate/src/",
"@forge-std/=lib/forge-std/src/",
"@ds-test/=lib/forge-std/lib/ds-test/src/",
"ds-test/=lib/forge-std/lib/ds-test/src/",
"@openzeppelin/=lib/openzeppelin-contracts/",
"@ccip/=lib/ccip/",
"@oapp-auth/=lib/OAppAuth/src/",
"@ccip/=lib/ccip/",
"@oapp-auth/=lib/OAppAuth/src/",
"@devtools-oapp-evm/=lib/OAppAuth/lib/devtools/packages/oapp-evm/contracts/oapp/",
"@layerzerolabs/lz-evm-messagelib-v2/=lib/OAppAuth/node_modules/@layerzerolabs/lz-evm-messagelib-v2/",
"@layerzerolabs/lz-evm-protocol-v2/=lib/OAppAuth/lib/LayerZero-V2/packages/layerzero-v2/evm/protocol/",
"@layerzerolabs/oapp-evm/=lib/OAppAuth/lib/devtools/packages/oapp-evm/",
"@lz-oapp-evm/=lib/OAppAuth/lib/LayerZero-V2/packages/layerzero-v2/evm/oapp/contracts/oapp/",
"LayerZero-V2/=lib/OAppAuth/lib/",
"OAppAuth/=lib/OAppAuth/",
"ccip/=lib/ccip/contracts/",
"erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
"forge-std/=lib/forge-std/src/",
"halmos-cheatcodes/=lib/OAppAuth/lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/",
"solidity-bytes-utils/=lib/OAppAuth/node_modules/solidity-bytes-utils/",
"solmate/=lib/solmate/src/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "shanghai",
"viaIR": false
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_manager","type":"address"},{"internalType":"address","name":"_boringVault","type":"address"},{"internalType":"address","name":"_balancerVault","type":"address"},{"internalType":"address","name":"_uniswapV3Router","type":"address"},{"internalType":"address","name":"_quoter","type":"address"},{"internalType":"address","name":"_aave","type":"address"},{"components":[{"internalType":"address","name":"baseToken","type":"address"},{"internalType":"address","name":"depositToken","type":"address"},{"internalType":"address","name":"aToken","type":"address"},{"internalType":"address","name":"debtToken","type":"address"}],"internalType":"struct TokenConfig","name":"_tokens","type":"tuple"},{"internalType":"uint24","name":"_uniFeeTier","type":"uint24"},{"internalType":"uint256","name":"_aaveVariableRate","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"InsufficientVaultBalance","type":"error"},{"inputs":[],"name":"UManager__CallCountExceeded","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"oldAllowance","type":"uint16"},{"indexed":false,"internalType":"uint16","name":"newAllowance","type":"uint16"}],"name":"AllowedCallsPeriodUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"contract Authority","name":"newAuthority","type":"address"}],"name":"AuthorityUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"oldPeriod","type":"uint16"},{"indexed":false,"internalType":"uint16","name":"newPeriod","type":"uint16"}],"name":"PeriodUpdated","type":"event"},{"inputs":[],"name":"AAVE","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"aToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"aaveVariableRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"allowedCallsPerPeriod","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"authority","outputs":[{"internalType":"contract Authority","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"balancerVault","outputs":[{"internalType":"contract BalancerVault","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"collateralAmount","type":"uint256"},{"internalType":"uint256","name":"borrowAmount","type":"uint256"}],"name":"borrow","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"callCountPerPeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"debtToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"depositToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"period","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"quoter","outputs":[{"internalType":"contract IQuoter","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"borrowAmount","type":"uint256"},{"internalType":"uint256","name":"supplyAmount","type":"uint256"}],"name":"repay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32[][]","name":"manageProofs","type":"bytes32[][]"},{"internalType":"address[]","name":"decodersAndSanitizers","type":"address[]"},{"internalType":"contract ERC20[]","name":"tokens","type":"address[]"},{"internalType":"address[]","name":"spenders","type":"address[]"}],"name":"revokeTokenApproval","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_allowedCallsPerPeriod","type":"uint16"}],"name":"setAllowedCallsPerPeriod","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract Authority","name":"newAuthority","type":"address"}],"name":"setAuthority","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_borrowInnerDecodersAndSanitizers","type":"address[]"}],"name":"setBorrowInnerDecodersAndSanitizers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32[][]","name":"_borrowInnerManageProofs","type":"bytes32[][]"}],"name":"setBorrowInnerManageProofs","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_outerDecodersAndSanitizers","type":"address[]"}],"name":"setOuterDecodersAndSanitizers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32[][]","name":"_outerManageProofs","type":"bytes32[][]"}],"name":"setOuterManageProofs","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_period","type":"uint16"}],"name":"setPeriod","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_repayInnerDecodersAndSanitizers","type":"address[]"}],"name":"setRepayInnerDecodersAndSanitizers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32[][]","name":"_repayInnerManageProofs","type":"bytes32[][]"}],"name":"setRepayInnerManageProofs","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"settle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"uniFeeTier","outputs":[{"internalType":"uint24","name":"","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"uniswapV3Router","outputs":[{"internalType":"contract IUniswapV3Router","name":"","type":"address"}],"stateMutability":"view","type":"function"}]Contract Creation Code
0x61020060405234801562000011575f80fd5b506040516200316938038062003169833981016040819052620000349162000165565b5f80546001600160a01b038c166001600160a01b031991821681178355600180549092169091556040518c928c928c928592919033907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908490a36040516001600160a01b0382169033907fa3396fd7f6e0a21b50e5089d2da70d5ac0a3bbbd1f617a93f134b76389980198905f90a350506001600160a01b03918216608052811660a05296871660c0525093851660e0529484166101005290831661012052805183166101405260208101518316610160526040810151831661018052606001519091166101a05262ffffff9091166101c0526101e05250620002a9915050565b80516001600160a01b03811681146200014d575f80fd5b919050565b805162ffffff811681146200014d575f80fd5b5f805f805f805f805f808a8c036101a081121562000181575f80fd5b6200018c8c62000136565b9a506200019c60208d0162000136565b9950620001ac60408d0162000136565b9850620001bc60608d0162000136565b9750620001cc60808d0162000136565b9650620001dc60a08d0162000136565b9550620001ec60c08d0162000136565b9450608060df198201121562000200575f80fd5b50604051608081016001600160401b03811182821017156200023057634e487b7160e01b5f52604160045260245ffd5b6040526200024160e08d0162000136565b8152620002526101008d0162000136565b6020820152620002666101208d0162000136565b60408201526200027a6101408d0162000136565b60608201529250620002906101608c0162000152565b91506101808b015190509295989b9194979a5092959850565b60805160a05160c05160e05161010051610120516101405161016051610180516101a0516101c0516101e051612d40620004295f395f81816101fc0152818161197d0152611f9901525f818161034d015281816117140152818161180a015261217d01525f81816104dc01526106a901525f818161039a01526120c401525f818161047a015281816116ec015281816117e90152818161189a0152818161201e015261213b01525f81816104190152818161058c015281816116c4015281816117c80152818161194501528181611daf01528181611f5c015261215c01525f818161030001528181611a9001528181611ae40152818161222d015261228001525f61024e01525f8181610440015261175101525f81816102b301528181611a3d01526122d401525f81816105620152818161067f0152818161182b015281816118d2015281816119ab01528181611fc30152818161209c015261219e01525f8181610f1401528181611cf001528181611e4c0152611ee10152612d405ff3fe608060405234801561000f575f80fd5b50600436106101c6575f3560e01c80638da5cb5b116100fe578063c6bbd5a71161009e578063ef78d4fd1161006e578063ef78d4fd146104af578063f2fde38b146104c4578063f8d89898146104d7578063fba2a2d2146104fe575f80fd5b8063c6bbd5a71461043b578063c888872014610462578063c89039c514610475578063d8aed1451461049c575f80fd5b8063b429c220116100d9578063b429c220146103db578063beb651f3146103ee578063bf7e214f14610401578063c55dae6314610414575f80fd5b80638da5cb5b14610383578063a0c1f15e14610395578063a0edf34e146103bc575f80fd5b80632c76d7a61161016957806348ccda3c1161014457806348ccda3c146102fb578063568eb346146103225780637a9e5e4b146103355780638b39d4d814610348575f80fd5b80632c76d7a6146102ae5780632ce4bd33146102d55780632d26dae7146102e8575f80fd5b806311da60b4116101a457806311da60b414610241578063158274a51461024957806323dcaa13146102885780632912a96a1461029b575f80fd5b80630401176f146101ca57806305114978146101f75780630ecbcdab1461022c575b5f80fd5b6001546101df90600160b01b900461ffff1681565b60405161ffff90911681526020015b60405180910390f35b61021e7f000000000000000000000000000000000000000000000000000000000000000081565b6040519081526020016101ee565b61023f61023a366004612562565b610511565b005b61023f610637565b6102707f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016101ee565b61023f6102963660046125c9565b610732565b61023f6102a93660046125c9565b61093a565b6102707f000000000000000000000000000000000000000000000000000000000000000081565b61023f6102e33660046125c9565b610b3d565b61023f6102f6366004612607565b610c4e565b6102707f000000000000000000000000000000000000000000000000000000000000000081565b61023f61033036600461262f565b610cea565b61023f6103433660046126fd565b610f90565b61036f7f000000000000000000000000000000000000000000000000000000000000000081565b60405162ffffff90911681526020016101ee565b5f54610270906001600160a01b031681565b6102707f000000000000000000000000000000000000000000000000000000000000000081565b61021e6103ca366004612718565b60026020525f908152604090205481565b61023f6103e93660046125c9565b611074565b61023f6103fc3660046125c9565b611185565b600154610270906001600160a01b031681565b6102707f000000000000000000000000000000000000000000000000000000000000000081565b6102707f000000000000000000000000000000000000000000000000000000000000000081565b61023f6104703660046125c9565b611296565b6102707f000000000000000000000000000000000000000000000000000000000000000081565b61023f6104aa366004612562565b611499565b6001546101df90600160a01b900461ffff1681565b61023f6104d23660046126fd565b6114e1565b6102707f000000000000000000000000000000000000000000000000000000000000000081565b61023f61050c366004612607565b61155c565b610526335f356001600160e01b0319166115f8565b61054b5760405162461bcd60e51b81526004016105429061272f565b60405180910390fd5b6040516370a0823160e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301525f917f0000000000000000000000000000000000000000000000000000000000000000909116906370a0823190602401602060405180830381865afa1580156105d3573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105f79190612755565b90508281101561061a576040516314ecd6c760e01b815260040160405180910390fd5b5f61062584846116a0565b90506106318184611c17565b50505050565b61064c335f356001600160e01b0319166115f8565b6106685760405162461bcd60e51b81526004016105429061272f565b6040516370a0823160e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301525f917f0000000000000000000000000000000000000000000000000000000000000000909116906370a0823190602401602060405180830381865afa1580156106f0573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107149190612755565b90505f6107225f1980611f56565b905061072e8183611c17565b5050565b610747335f356001600160e01b0319166115f8565b6107635760405162461bcd60e51b81526004016105429061272f565b61076e60055f612406565b806001600160401b038111156107865761078661276c565b6040519080825280602002602001820160405280156107b957816020015b60608152602001906001900390816107a45790505b5080516107ce91600591602090910190612424565b505f5b81811015610935578282828181106107eb576107eb612780565b90506020028101906107fd9190612794565b90506001600160401b038111156108165761081661276c565b60405190808252806020026020018201604052801561083f578160200160208202803683370190505b506005828154811061085357610853612780565b905f5260205f2001908051906020019061086e92919061247f565b505f5b83838381811061088357610883612780565b90506020028101906108959190612794565b9050811015610922578383838181106108b0576108b0612780565b90506020028101906108c29190612794565b828181106108d2576108d2612780565b90506020020135600583815481106108ec576108ec612780565b905f5260205f2001828154811061090557610905612780565b5f918252602090912001558061091a816127ed565b915050610871565b508061092d816127ed565b9150506107d1565b505050565b61094f335f356001600160e01b0319166115f8565b61096b5760405162461bcd60e51b81526004016105429061272f565b61097660035f612406565b806001600160401b0381111561098e5761098e61276c565b6040519080825280602002602001820160405280156109c157816020015b60608152602001906001900390816109ac5790505b5080516109d691600391602090910190612424565b505f5b81811015610935578282828181106109f3576109f3612780565b9050602002810190610a059190612794565b90506001600160401b03811115610a1e57610a1e61276c565b604051908082528060200260200182016040528015610a47578160200160208202803683370190505b5060038281548110610a5b57610a5b612780565b905f5260205f20019080519060200190610a7692919061247f565b505f5b838383818110610a8b57610a8b612780565b9050602002810190610a9d9190612794565b9050811015610b2a57838383818110610ab857610ab8612780565b9050602002810190610aca9190612794565b82818110610ada57610ada612780565b9050602002013560038381548110610af457610af4612780565b905f5260205f20018281548110610b0d57610b0d612780565b5f9182526020909120015580610b22816127ed565b915050610a79565b5080610b35816127ed565b9150506109d9565b610b52335f356001600160e01b0319166115f8565b610b6e5760405162461bcd60e51b81526004016105429061272f565b610b7960045f6124c4565b806001600160401b03811115610b9157610b9161276c565b604051908082528060200260200182016040528015610bba578160200160208202803683370190505b508051610bcf916004916020909101906124df565b505f5b8181101561093557828282818110610bec57610bec612780565b9050602002016020810190610c0191906126fd565b60048281548110610c1457610c14612780565b5f91825260209091200180546001600160a01b0319166001600160a01b039290921691909117905580610c46816127ed565b915050610bd2565b610c63335f356001600160e01b0319166115f8565b610c7f5760405162461bcd60e51b81526004016105429061272f565b6001546040805161ffff600160b01b9093048316815291831660208301527f0c9650a4effa4263b9af38b4d55bf55b5636f5c9cf0ad04f4a255da47f33635c910160405180910390a16001805461ffff909216600160b01b0261ffff60b01b19909216919091179055565b610cff335f356001600160e01b0319166115f8565b610d1b5760405162461bcd60e51b81526004016105429061272f565b825f816001600160401b03811115610d3557610d3561276c565b604051908082528060200260200182016040528015610d5e578160200160208202803683370190505b5090505f826001600160401b03811115610d7a57610d7a61276c565b604051908082528060200260200182016040528015610dad57816020015b6060815260200190600190039081610d985790505b5090505f836001600160401b03811115610dc957610dc961276c565b604051908082528060200260200182016040528015610df2578160200160208202803683370190505b5090505f5b84811015610efc57888882818110610e1157610e11612780565b9050602002016020810190610e2691906126fd565b848281518110610e3857610e38612780565b6001600160a01b039092166020928302919091019091015263095ea7b360e01b878783818110610e6a57610e6a612780565b9050602002016020810190610e7f91906126fd565b6040516001600160a01b0390911660248201525f6044820152606401604051602081830303815290604052906001600160e01b0319166020820180516001600160e01b038381831617835250505050838281518110610ee057610ee0612780565b602002602001018190525080610ef5906127ed565b9050610df7565b5060405163122587b560e11b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063244b0f6a90610f55908f908f908f908f908a908a908a90600401612977565b5f604051808303815f87803b158015610f6c575f80fd5b505af1158015610f7e573d5f803e3d5ffd5b50505050505050505050505050505050565b5f546001600160a01b0316331480611021575060015460405163b700961360e01b81526001600160a01b039091169063b700961390610fe290339030906001600160e01b03195f351690600401612a66565b602060405180830381865afa158015610ffd573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110219190612a93565b611029575f80fd5b600180546001600160a01b0319166001600160a01b03831690811790915560405133907fa3396fd7f6e0a21b50e5089d2da70d5ac0a3bbbd1f617a93f134b76389980198905f90a350565b611089335f356001600160e01b0319166115f8565b6110a55760405162461bcd60e51b81526004016105429061272f565b6110b060065f6124c4565b806001600160401b038111156110c8576110c861276c565b6040519080825280602002602001820160405280156110f1578160200160208202803683370190505b508051611106916006916020909101906124df565b505f5b818110156109355782828281811061112357611123612780565b905060200201602081019061113891906126fd565b6006828154811061114b5761114b612780565b5f91825260209091200180546001600160a01b0319166001600160a01b03929092169190911790558061117d816127ed565b915050611109565b61119a335f356001600160e01b0319166115f8565b6111b65760405162461bcd60e51b81526004016105429061272f565b6111c160075f6124c4565b806001600160401b038111156111d9576111d961276c565b604051908082528060200260200182016040528015611202578160200160208202803683370190505b508051611217916007916020909101906124df565b505f5b818110156109355782828281811061123457611234612780565b905060200201602081019061124991906126fd565b6007828154811061125c5761125c612780565b5f91825260209091200180546001600160a01b0319166001600160a01b03929092169190911790558061128e816127ed565b91505061121a565b6112ab335f356001600160e01b0319166115f8565b6112c75760405162461bcd60e51b81526004016105429061272f565b6112d260085f612406565b806001600160401b038111156112ea576112ea61276c565b60405190808252806020026020018201604052801561131d57816020015b60608152602001906001900390816113085790505b50805161133291600891602090910190612424565b505f5b818110156109355782828281811061134f5761134f612780565b90506020028101906113619190612794565b90506001600160401b0381111561137a5761137a61276c565b6040519080825280602002602001820160405280156113a3578160200160208202803683370190505b50600882815481106113b7576113b7612780565b905f5260205f200190805190602001906113d292919061247f565b505f5b8383838181106113e7576113e7612780565b90506020028101906113f99190612794565b90508110156114865783838381811061141457611414612780565b90506020028101906114269190612794565b8281811061143657611436612780565b905060200201356008838154811061145057611450612780565b905f5260205f2001828154811061146957611469612780565b5f918252602090912001558061147e816127ed565b9150506113d5565b5080611491816127ed565b915050611335565b6114ae335f356001600160e01b0319166115f8565b6114ca5760405162461bcd60e51b81526004016105429061272f565b5f6114d58383611f56565b90506109358184611c17565b6114f6335f356001600160e01b0319166115f8565b6115125760405162461bcd60e51b81526004016105429061272f565b5f80546001600160a01b0319166001600160a01b0383169081178255604051909133917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a350565b611571335f356001600160e01b0319166115f8565b61158d5760405162461bcd60e51b81526004016105429061272f565b6001546040805161ffff600160a01b9093048316815291831660208301527fdefd7021b18355bad5c7ef351652f8516c7ec83fff11b4ac3913e38fdd628c13910160405180910390a16001805461ffff909216600160a01b0261ffff60a01b19909216919091179055565b6001545f906001600160a01b0316801580159061167f575060405163b700961360e01b81526001600160a01b0382169063b70096139061164090879030908890600401612a66565b602060405180830381865afa15801561165b573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061167f9190612a93565b8061169657505f546001600160a01b038581169116145b9150505b92915050565b60605f6116ad8385612ab2565b60405163f7729d4360e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301527f0000000000000000000000000000000000000000000000000000000000000000811660248301527f000000000000000000000000000000000000000000000000000000000000000062ffffff166044830152606482018390525f608483018190529293507f0000000000000000000000000000000000000000000000000000000000000000169063f7729d439060a4016020604051808303815f875af1158015611797573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117bb9190612755565b90505f6304e45aaf60e01b7f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000875f806040516024016118639796959493929190612ac5565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319949094169390931790925290517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b039081166024830152604482018590527f00000000000000000000000000000000000000000000000000000000000000001660648201525f6084820181905291925063617ba03760e01b9060a40160408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319949094169390931790925290517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b039081166024830152604482018990527f000000000000000000000000000000000000000000000000000000000000000060648301525f608483018190527f000000000000000000000000000000000000000000000000000000000000000090911660a483015291925063a415bcad60e01b9060c40160408051808303601f190181529181526020820180516001600160e01b0319949094166001600160e01b039094169390931790925281516003808252608082019093529092505f918160200160208202803683370190505090507f0000000000000000000000000000000000000000000000000000000000000000815f81518110611a6e57611a6e612780565b60200260200101906001600160a01b031690816001600160a01b0316815250507f000000000000000000000000000000000000000000000000000000000000000081600181518110611ac257611ac2612780565b60200260200101906001600160a01b031690816001600160a01b0316815250507f000000000000000000000000000000000000000000000000000000000000000081600281518110611b1657611b16612780565b6001600160a01b039290921660209283029190910190910152604080516003808252608082019092525f91816020015b6060815260200190600190039081611b4657905050905084815f81518110611b7057611b70612780565b60200260200101819052508381600181518110611b8f57611b8f612780565b60200260200101819052508281600281518110611bae57611bae612780565b6020908102919091010152604080516003808252608082019092525f9181602001602082028036833701905050905060036004848484604051602001611bf8959493929190612b44565b6040516020818303038152906040529850505050505050505092915050565b5f6008805480602002602001604051908101604052809291908181526020015f905b82821015611ca2575f84815260209081902083018054604080518285028101850190915281815292830182828015611c8e57602002820191905f5260205f20905b815481526020019060010190808311611c7a575b505050505081526020019060010190611c39565b5050505090505f60016001600160401b03811115611cc257611cc261276c565b604051908082528060200260200182016040528015611ceb578160200160208202803683370190505b5090507f0000000000000000000000000000000000000000000000000000000000000000815f81518110611d2157611d21612780565b6001600160a01b0392909216602092830291909101909101526040805160018082528183019092525f9181602001602082028036833750506040805160018082528183019092529293505f929150602082015b6060815260200190600190039081611d745750506040805160018082528183019092529192505f9190602080830190803683370190505090507f0000000000000000000000000000000000000000000000000000000000000000815f81518110611de057611de0612780565b6001600160a01b0392909216602092830291909101909101526040805160018082528183019092525f9181602001602082028036833701905050905086815f81518110611e2f57611e2f612780565b6020908102919091010152604051632e1c224f60e11b90611e7a907f000000000000000000000000000000000000000000000000000000000000000090859085908d90602401612c23565b604051602081830303815290604052906001600160e01b0319166020820180516001600160e01b038381831617835250505050835f81518110611ebf57611ebf612780565b602090810291909101015260405163122587b560e11b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063244b0f6a90611f1f9089906007908a9089908b90600401612c77565b5f604051808303815f87803b158015611f36575f80fd5b505af1158015611f48573d5f803e3d5ffd5b505050505050505050505050565b604080517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811660248084019190915260448084018790527f00000000000000000000000000000000000000000000000000000000000000006064808601919091527f00000000000000000000000000000000000000000000000000000000000000008416608480870182905287518088038201815260a49097018852602080880180516001600160e01b0390811663573ade8160e01b1790915289517f0000000000000000000000000000000000000000000000000000000000000000909816968801969096529386018990528583019190915286518086039092018252939093019094529281018051909316631a4ca37b60e21b179092526060918360018101612130576040516370a0823160e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301527f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa158015612109573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061212d9190612755565b90505b5f6304e45aaf60e01b7f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000865f806040516024016121d69796959493929190612ac5565b60408051601f19818403018152918152602080830180516001600160e01b03166001600160e01b0319959095169490941790935280516003808252608082019092529193505f9282016060803683370190505090507f0000000000000000000000000000000000000000000000000000000000000000815f8151811061225e5761225e612780565b60200260200101906001600160a01b031690816001600160a01b0316815250507f0000000000000000000000000000000000000000000000000000000000000000816001815181106122b2576122b2612780565b60200260200101906001600160a01b031690816001600160a01b0316815250507f00000000000000000000000000000000000000000000000000000000000000008160028151811061230657612306612780565b6001600160a01b039290921660209283029190910190910152604080516003808252608082019092525f91816020015b606081526020019060019003908161233657905050905085815f8151811061236057612360612780565b6020026020010181905250848160018151811061237f5761237f612780565b6020026020010181905250828160028151811061239e5761239e612780565b6020908102919091010152604080516003808252608082019092525f91816020016020820280368337019050509050600560068484846040516020016123e8959493929190612b44565b60405160208183030381529060405297505050505050505092915050565b5080545f8255905f5260205f20908101906124219190612532565b50565b828054828255905f5260205f2090810192821561246f579160200282015b8281111561246f578251805161245f91849160209091019061247f565b5091602001919060010190612442565b5061247b929150612532565b5090565b828054828255905f5260205f209081019282156124b8579160200282015b828111156124b857825182559160200191906001019061249d565b5061247b92915061254e565b5080545f8255905f5260205f2090810190612421919061254e565b828054828255905f5260205f209081019282156124b8579160200282015b828111156124b857825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906124fd565b8082111561247b575f61254582826124c4565b50600101612532565b5b8082111561247b575f815560010161254f565b5f8060408385031215612573575f80fd5b50508035926020909101359150565b5f8083601f840112612592575f80fd5b5081356001600160401b038111156125a8575f80fd5b6020830191508360208260051b85010111156125c2575f80fd5b9250929050565b5f80602083850312156125da575f80fd5b82356001600160401b038111156125ef575f80fd5b6125fb85828601612582565b90969095509350505050565b5f60208284031215612617575f80fd5b813561ffff81168114612628575f80fd5b9392505050565b5f805f805f805f806080898b031215612646575f80fd5b88356001600160401b038082111561265c575f80fd5b6126688c838d01612582565b909a50985060208b0135915080821115612680575f80fd5b61268c8c838d01612582565b909850965060408b01359150808211156126a4575f80fd5b6126b08c838d01612582565b909650945060608b01359150808211156126c8575f80fd5b506126d58b828c01612582565b999c989b5096995094979396929594505050565b6001600160a01b0381168114612421575f80fd5b5f6020828403121561270d575f80fd5b8135612628816126e9565b5f60208284031215612728575f80fd5b5035919050565b6020808252600c908201526b15539055551213d49256915160a21b604082015260600190565b5f60208284031215612765575f80fd5b5051919050565b634e487b7160e01b5f52604160045260245ffd5b634e487b7160e01b5f52603260045260245ffd5b5f808335601e198436030181126127a9575f80fd5b8301803591506001600160401b038211156127c2575f80fd5b6020019150600581901b36038213156125c2575f80fd5b634e487b7160e01b5f52601160045260245ffd5b5f600182016127fe576127fe6127d9565b5060010190565b8183525f6001600160fb1b0383111561281c575f80fd5b8260051b80836020870137939093016020019392505050565b8183525f60208085019450825f5b85811015612871578135612856816126e9565b6001600160a01b031687529582019590820190600101612843565b509495945050505050565b5f8151808452602080850194508084015f5b838110156128715781516001600160a01b03168752958201959082019060010161288e565b5f81518084525f5b818110156128d7576020818501810151868301820152016128bb565b505f602082860101526020601f19601f83011685010191505092915050565b5f81518084526020808501808196508360051b810191508286015f5b8581101561293c57828403895261292a8483516128b3565b98850198935090840190600101612912565b5091979650505050505050565b5f8151808452602080850194508084015f5b838110156128715781518752958201959082019060010161295b565b60a080825281018790525f600560c0808401908a831b8501018b845b8c811015612a055786830360bf190184528135368f9003601e190181126129b8575f80fd5b8e0160208181019135906001600160401b038211156129d5575f80fd5b81881b36038313156129e5575f80fd5b6129f0868385612805565b96810196955093909301925050600101612993565b50508481036020860152612a1a818a8c612835565b925050508281036040840152612a30818761287c565b90508281036060840152612a4481866128f6565b90508281036080840152612a588185612949565b9a9950505050505050505050565b6001600160a01b0393841681529190921660208201526001600160e01b0319909116604082015260600190565b5f60208284031215612aa3575f80fd5b81518015158114612628575f80fd5b8082018082111561169a5761169a6127d9565b6001600160a01b039788168152958716602087015262ffffff9490941660408601529185166060850152608084015260ff1660a083015290911660c082015260e00190565b5f815480845260208085019450835f52805f205f5b838110156128715781546001600160a01b031687529582019560019182019101612b1f565b5f60a0820160a0835280885480835260c08501915060c08160051b86010192505f8a81526020808220825b84811015612bc45788870360bf1901865281548088528285528385208489019190865b82811015612bae57815484529286019260019182019101612b92565b5091985050509482019460019182019101612b6f565b50508685038188015250505050612bdb8188612b0a565b90508281036040840152612bef818761287c565b90508281036060840152612c0381866128f6565b90508281036080840152612c178185612949565b98975050505050505050565b6001600160a01b03851681526080602082018190525f90612c469083018661287c565b8281036040840152612c588186612949565b90508281036060840152612c6c81856128b3565b979650505050505050565b5f60a0820160a0835280885180835260c08501915060c08160051b86010192506020808b015f805b84811015612cf35788870360bf19018652825180518089529085019085890190845b81811015612cdd57835183529287019291870191600101612cc1565b5090985050509483019491830191600101612c9f565b50505085840381870152505050612bdb8188612b0a56fea2646970667358221220c0f92e3e9b75e33e1b01ddea99afccc91bfe5c99c94111ef0a807da2bc9317ee64736f6c63430008150033000000000000000000000000a45a9b2bc0230fa78af0c92031a2e4016afa9b4000000000000000000000000028d0d9c4553c24abf55cbd0680b03524eec966aa0000000000000000000000007e68c279ea86fa49a49eef2cbb79b9cbfbc48025000000000000000000000000ba12222222228d8ba445958a75a0704d566bf2c800000000000000000000000068b3465833fb72a70ecdf485e0e4c7bd8665fc45000000000000000000000000b27308f9f90d607463bb33ea1bebb41c27ce5ab600000000000000000000000087870bca3f3fd6335c3f4ce8392d69350b4fa4e2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000009d39a5de30e57443bff2a8307a4256c8797a34970000000000000000000000004579a27af00a62c0eb156349f31b345c0838641900000000000000000000000072e95b8931767c79ba4eee721354d6e99a61d00400000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000002
Deployed Bytecode
0x608060405234801561000f575f80fd5b50600436106101c6575f3560e01c80638da5cb5b116100fe578063c6bbd5a71161009e578063ef78d4fd1161006e578063ef78d4fd146104af578063f2fde38b146104c4578063f8d89898146104d7578063fba2a2d2146104fe575f80fd5b8063c6bbd5a71461043b578063c888872014610462578063c89039c514610475578063d8aed1451461049c575f80fd5b8063b429c220116100d9578063b429c220146103db578063beb651f3146103ee578063bf7e214f14610401578063c55dae6314610414575f80fd5b80638da5cb5b14610383578063a0c1f15e14610395578063a0edf34e146103bc575f80fd5b80632c76d7a61161016957806348ccda3c1161014457806348ccda3c146102fb578063568eb346146103225780637a9e5e4b146103355780638b39d4d814610348575f80fd5b80632c76d7a6146102ae5780632ce4bd33146102d55780632d26dae7146102e8575f80fd5b806311da60b4116101a457806311da60b414610241578063158274a51461024957806323dcaa13146102885780632912a96a1461029b575f80fd5b80630401176f146101ca57806305114978146101f75780630ecbcdab1461022c575b5f80fd5b6001546101df90600160b01b900461ffff1681565b60405161ffff90911681526020015b60405180910390f35b61021e7f000000000000000000000000000000000000000000000000000000000000000281565b6040519081526020016101ee565b61023f61023a366004612562565b610511565b005b61023f610637565b6102707f000000000000000000000000ba12222222228d8ba445958a75a0704d566bf2c881565b6040516001600160a01b0390911681526020016101ee565b61023f6102963660046125c9565b610732565b61023f6102a93660046125c9565b61093a565b6102707f00000000000000000000000068b3465833fb72a70ecdf485e0e4c7bd8665fc4581565b61023f6102e33660046125c9565b610b3d565b61023f6102f6366004612607565b610c4e565b6102707f00000000000000000000000087870bca3f3fd6335c3f4ce8392d69350b4fa4e281565b61023f61033036600461262f565b610cea565b61023f6103433660046126fd565b610f90565b61036f7f000000000000000000000000000000000000000000000000000000000000006481565b60405162ffffff90911681526020016101ee565b5f54610270906001600160a01b031681565b6102707f0000000000000000000000004579a27af00a62c0eb156349f31b345c0838641981565b61021e6103ca366004612718565b60026020525f908152604090205481565b61023f6103e93660046125c9565b611074565b61023f6103fc3660046125c9565b611185565b600154610270906001600160a01b031681565b6102707f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4881565b6102707f000000000000000000000000b27308f9f90d607463bb33ea1bebb41c27ce5ab681565b61023f6104703660046125c9565b611296565b6102707f0000000000000000000000009d39a5de30e57443bff2a8307a4256c8797a349781565b61023f6104aa366004612562565b611499565b6001546101df90600160a01b900461ffff1681565b61023f6104d23660046126fd565b6114e1565b6102707f00000000000000000000000072e95b8931767c79ba4eee721354d6e99a61d00481565b61023f61050c366004612607565b61155c565b610526335f356001600160e01b0319166115f8565b61054b5760405162461bcd60e51b81526004016105429061272f565b60405180910390fd5b6040516370a0823160e01b81526001600160a01b037f0000000000000000000000007e68c279ea86fa49a49eef2cbb79b9cbfbc48025811660048301525f917f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48909116906370a0823190602401602060405180830381865afa1580156105d3573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105f79190612755565b90508281101561061a576040516314ecd6c760e01b815260040160405180910390fd5b5f61062584846116a0565b90506106318184611c17565b50505050565b61064c335f356001600160e01b0319166115f8565b6106685760405162461bcd60e51b81526004016105429061272f565b6040516370a0823160e01b81526001600160a01b037f0000000000000000000000007e68c279ea86fa49a49eef2cbb79b9cbfbc48025811660048301525f917f00000000000000000000000072e95b8931767c79ba4eee721354d6e99a61d004909116906370a0823190602401602060405180830381865afa1580156106f0573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107149190612755565b90505f6107225f1980611f56565b905061072e8183611c17565b5050565b610747335f356001600160e01b0319166115f8565b6107635760405162461bcd60e51b81526004016105429061272f565b61076e60055f612406565b806001600160401b038111156107865761078661276c565b6040519080825280602002602001820160405280156107b957816020015b60608152602001906001900390816107a45790505b5080516107ce91600591602090910190612424565b505f5b81811015610935578282828181106107eb576107eb612780565b90506020028101906107fd9190612794565b90506001600160401b038111156108165761081661276c565b60405190808252806020026020018201604052801561083f578160200160208202803683370190505b506005828154811061085357610853612780565b905f5260205f2001908051906020019061086e92919061247f565b505f5b83838381811061088357610883612780565b90506020028101906108959190612794565b9050811015610922578383838181106108b0576108b0612780565b90506020028101906108c29190612794565b828181106108d2576108d2612780565b90506020020135600583815481106108ec576108ec612780565b905f5260205f2001828154811061090557610905612780565b5f918252602090912001558061091a816127ed565b915050610871565b508061092d816127ed565b9150506107d1565b505050565b61094f335f356001600160e01b0319166115f8565b61096b5760405162461bcd60e51b81526004016105429061272f565b61097660035f612406565b806001600160401b0381111561098e5761098e61276c565b6040519080825280602002602001820160405280156109c157816020015b60608152602001906001900390816109ac5790505b5080516109d691600391602090910190612424565b505f5b81811015610935578282828181106109f3576109f3612780565b9050602002810190610a059190612794565b90506001600160401b03811115610a1e57610a1e61276c565b604051908082528060200260200182016040528015610a47578160200160208202803683370190505b5060038281548110610a5b57610a5b612780565b905f5260205f20019080519060200190610a7692919061247f565b505f5b838383818110610a8b57610a8b612780565b9050602002810190610a9d9190612794565b9050811015610b2a57838383818110610ab857610ab8612780565b9050602002810190610aca9190612794565b82818110610ada57610ada612780565b9050602002013560038381548110610af457610af4612780565b905f5260205f20018281548110610b0d57610b0d612780565b5f9182526020909120015580610b22816127ed565b915050610a79565b5080610b35816127ed565b9150506109d9565b610b52335f356001600160e01b0319166115f8565b610b6e5760405162461bcd60e51b81526004016105429061272f565b610b7960045f6124c4565b806001600160401b03811115610b9157610b9161276c565b604051908082528060200260200182016040528015610bba578160200160208202803683370190505b508051610bcf916004916020909101906124df565b505f5b8181101561093557828282818110610bec57610bec612780565b9050602002016020810190610c0191906126fd565b60048281548110610c1457610c14612780565b5f91825260209091200180546001600160a01b0319166001600160a01b039290921691909117905580610c46816127ed565b915050610bd2565b610c63335f356001600160e01b0319166115f8565b610c7f5760405162461bcd60e51b81526004016105429061272f565b6001546040805161ffff600160b01b9093048316815291831660208301527f0c9650a4effa4263b9af38b4d55bf55b5636f5c9cf0ad04f4a255da47f33635c910160405180910390a16001805461ffff909216600160b01b0261ffff60b01b19909216919091179055565b610cff335f356001600160e01b0319166115f8565b610d1b5760405162461bcd60e51b81526004016105429061272f565b825f816001600160401b03811115610d3557610d3561276c565b604051908082528060200260200182016040528015610d5e578160200160208202803683370190505b5090505f826001600160401b03811115610d7a57610d7a61276c565b604051908082528060200260200182016040528015610dad57816020015b6060815260200190600190039081610d985790505b5090505f836001600160401b03811115610dc957610dc961276c565b604051908082528060200260200182016040528015610df2578160200160208202803683370190505b5090505f5b84811015610efc57888882818110610e1157610e11612780565b9050602002016020810190610e2691906126fd565b848281518110610e3857610e38612780565b6001600160a01b039092166020928302919091019091015263095ea7b360e01b878783818110610e6a57610e6a612780565b9050602002016020810190610e7f91906126fd565b6040516001600160a01b0390911660248201525f6044820152606401604051602081830303815290604052906001600160e01b0319166020820180516001600160e01b038381831617835250505050838281518110610ee057610ee0612780565b602002602001018190525080610ef5906127ed565b9050610df7565b5060405163122587b560e11b81526001600160a01b037f00000000000000000000000028d0d9c4553c24abf55cbd0680b03524eec966aa169063244b0f6a90610f55908f908f908f908f908a908a908a90600401612977565b5f604051808303815f87803b158015610f6c575f80fd5b505af1158015610f7e573d5f803e3d5ffd5b50505050505050505050505050505050565b5f546001600160a01b0316331480611021575060015460405163b700961360e01b81526001600160a01b039091169063b700961390610fe290339030906001600160e01b03195f351690600401612a66565b602060405180830381865afa158015610ffd573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110219190612a93565b611029575f80fd5b600180546001600160a01b0319166001600160a01b03831690811790915560405133907fa3396fd7f6e0a21b50e5089d2da70d5ac0a3bbbd1f617a93f134b76389980198905f90a350565b611089335f356001600160e01b0319166115f8565b6110a55760405162461bcd60e51b81526004016105429061272f565b6110b060065f6124c4565b806001600160401b038111156110c8576110c861276c565b6040519080825280602002602001820160405280156110f1578160200160208202803683370190505b508051611106916006916020909101906124df565b505f5b818110156109355782828281811061112357611123612780565b905060200201602081019061113891906126fd565b6006828154811061114b5761114b612780565b5f91825260209091200180546001600160a01b0319166001600160a01b03929092169190911790558061117d816127ed565b915050611109565b61119a335f356001600160e01b0319166115f8565b6111b65760405162461bcd60e51b81526004016105429061272f565b6111c160075f6124c4565b806001600160401b038111156111d9576111d961276c565b604051908082528060200260200182016040528015611202578160200160208202803683370190505b508051611217916007916020909101906124df565b505f5b818110156109355782828281811061123457611234612780565b905060200201602081019061124991906126fd565b6007828154811061125c5761125c612780565b5f91825260209091200180546001600160a01b0319166001600160a01b03929092169190911790558061128e816127ed565b91505061121a565b6112ab335f356001600160e01b0319166115f8565b6112c75760405162461bcd60e51b81526004016105429061272f565b6112d260085f612406565b806001600160401b038111156112ea576112ea61276c565b60405190808252806020026020018201604052801561131d57816020015b60608152602001906001900390816113085790505b50805161133291600891602090910190612424565b505f5b818110156109355782828281811061134f5761134f612780565b90506020028101906113619190612794565b90506001600160401b0381111561137a5761137a61276c565b6040519080825280602002602001820160405280156113a3578160200160208202803683370190505b50600882815481106113b7576113b7612780565b905f5260205f200190805190602001906113d292919061247f565b505f5b8383838181106113e7576113e7612780565b90506020028101906113f99190612794565b90508110156114865783838381811061141457611414612780565b90506020028101906114269190612794565b8281811061143657611436612780565b905060200201356008838154811061145057611450612780565b905f5260205f2001828154811061146957611469612780565b5f918252602090912001558061147e816127ed565b9150506113d5565b5080611491816127ed565b915050611335565b6114ae335f356001600160e01b0319166115f8565b6114ca5760405162461bcd60e51b81526004016105429061272f565b5f6114d58383611f56565b90506109358184611c17565b6114f6335f356001600160e01b0319166115f8565b6115125760405162461bcd60e51b81526004016105429061272f565b5f80546001600160a01b0319166001600160a01b0383169081178255604051909133917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a350565b611571335f356001600160e01b0319166115f8565b61158d5760405162461bcd60e51b81526004016105429061272f565b6001546040805161ffff600160a01b9093048316815291831660208301527fdefd7021b18355bad5c7ef351652f8516c7ec83fff11b4ac3913e38fdd628c13910160405180910390a16001805461ffff909216600160a01b0261ffff60a01b19909216919091179055565b6001545f906001600160a01b0316801580159061167f575060405163b700961360e01b81526001600160a01b0382169063b70096139061164090879030908890600401612a66565b602060405180830381865afa15801561165b573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061167f9190612a93565b8061169657505f546001600160a01b038581169116145b9150505b92915050565b60605f6116ad8385612ab2565b60405163f7729d4360e01b81526001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48811660048301527f0000000000000000000000009d39a5de30e57443bff2a8307a4256c8797a3497811660248301527f000000000000000000000000000000000000000000000000000000000000006462ffffff166044830152606482018390525f608483018190529293507f000000000000000000000000b27308f9f90d607463bb33ea1bebb41c27ce5ab6169063f7729d439060a4016020604051808303815f875af1158015611797573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117bb9190612755565b90505f6304e45aaf60e01b7f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb487f0000000000000000000000009d39a5de30e57443bff2a8307a4256c8797a34977f00000000000000000000000000000000000000000000000000000000000000647f0000000000000000000000007e68c279ea86fa49a49eef2cbb79b9cbfbc48025875f806040516024016118639796959493929190612ac5565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319949094169390931790925290517f0000000000000000000000009d39a5de30e57443bff2a8307a4256c8797a34976001600160a01b039081166024830152604482018590527f0000000000000000000000007e68c279ea86fa49a49eef2cbb79b9cbfbc480251660648201525f6084820181905291925063617ba03760e01b9060a40160408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319949094169390931790925290517f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486001600160a01b039081166024830152604482018990527f000000000000000000000000000000000000000000000000000000000000000260648301525f608483018190527f0000000000000000000000007e68c279ea86fa49a49eef2cbb79b9cbfbc4802590911660a483015291925063a415bcad60e01b9060c40160408051808303601f190181529181526020820180516001600160e01b0319949094166001600160e01b039094169390931790925281516003808252608082019093529092505f918160200160208202803683370190505090507f00000000000000000000000068b3465833fb72a70ecdf485e0e4c7bd8665fc45815f81518110611a6e57611a6e612780565b60200260200101906001600160a01b031690816001600160a01b0316815250507f00000000000000000000000087870bca3f3fd6335c3f4ce8392d69350b4fa4e281600181518110611ac257611ac2612780565b60200260200101906001600160a01b031690816001600160a01b0316815250507f00000000000000000000000087870bca3f3fd6335c3f4ce8392d69350b4fa4e281600281518110611b1657611b16612780565b6001600160a01b039290921660209283029190910190910152604080516003808252608082019092525f91816020015b6060815260200190600190039081611b4657905050905084815f81518110611b7057611b70612780565b60200260200101819052508381600181518110611b8f57611b8f612780565b60200260200101819052508281600281518110611bae57611bae612780565b6020908102919091010152604080516003808252608082019092525f9181602001602082028036833701905050905060036004848484604051602001611bf8959493929190612b44565b6040516020818303038152906040529850505050505050505092915050565b5f6008805480602002602001604051908101604052809291908181526020015f905b82821015611ca2575f84815260209081902083018054604080518285028101850190915281815292830182828015611c8e57602002820191905f5260205f20905b815481526020019060010190808311611c7a575b505050505081526020019060010190611c39565b5050505090505f60016001600160401b03811115611cc257611cc261276c565b604051908082528060200260200182016040528015611ceb578160200160208202803683370190505b5090507f00000000000000000000000028d0d9c4553c24abf55cbd0680b03524eec966aa815f81518110611d2157611d21612780565b6001600160a01b0392909216602092830291909101909101526040805160018082528183019092525f9181602001602082028036833750506040805160018082528183019092529293505f929150602082015b6060815260200190600190039081611d745750506040805160018082528183019092529192505f9190602080830190803683370190505090507f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48815f81518110611de057611de0612780565b6001600160a01b0392909216602092830291909101909101526040805160018082528183019092525f9181602001602082028036833701905050905086815f81518110611e2f57611e2f612780565b6020908102919091010152604051632e1c224f60e11b90611e7a907f00000000000000000000000028d0d9c4553c24abf55cbd0680b03524eec966aa90859085908d90602401612c23565b604051602081830303815290604052906001600160e01b0319166020820180516001600160e01b038381831617835250505050835f81518110611ebf57611ebf612780565b602090810291909101015260405163122587b560e11b81526001600160a01b037f00000000000000000000000028d0d9c4553c24abf55cbd0680b03524eec966aa169063244b0f6a90611f1f9089906007908a9089908b90600401612c77565b5f604051808303815f87803b158015611f36575f80fd5b505af1158015611f48573d5f803e3d5ffd5b505050505050505050505050565b604080517f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486001600160a01b0390811660248084019190915260448084018790527f00000000000000000000000000000000000000000000000000000000000000026064808601919091527f0000000000000000000000007e68c279ea86fa49a49eef2cbb79b9cbfbc480258416608480870182905287518088038201815260a49097018852602080880180516001600160e01b0390811663573ade8160e01b1790915289517f0000000000000000000000009d39a5de30e57443bff2a8307a4256c8797a3497909816968801969096529386018990528583019190915286518086039092018252939093019094529281018051909316631a4ca37b60e21b179092526060918360018101612130576040516370a0823160e01b81526001600160a01b037f0000000000000000000000007e68c279ea86fa49a49eef2cbb79b9cbfbc48025811660048301527f0000000000000000000000004579a27af00a62c0eb156349f31b345c0838641916906370a0823190602401602060405180830381865afa158015612109573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061212d9190612755565b90505b5f6304e45aaf60e01b7f0000000000000000000000009d39a5de30e57443bff2a8307a4256c8797a34977f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb487f00000000000000000000000000000000000000000000000000000000000000647f0000000000000000000000007e68c279ea86fa49a49eef2cbb79b9cbfbc48025865f806040516024016121d69796959493929190612ac5565b60408051601f19818403018152918152602080830180516001600160e01b03166001600160e01b0319959095169490941790935280516003808252608082019092529193505f9282016060803683370190505090507f00000000000000000000000087870bca3f3fd6335c3f4ce8392d69350b4fa4e2815f8151811061225e5761225e612780565b60200260200101906001600160a01b031690816001600160a01b0316815250507f00000000000000000000000087870bca3f3fd6335c3f4ce8392d69350b4fa4e2816001815181106122b2576122b2612780565b60200260200101906001600160a01b031690816001600160a01b0316815250507f00000000000000000000000068b3465833fb72a70ecdf485e0e4c7bd8665fc458160028151811061230657612306612780565b6001600160a01b039290921660209283029190910190910152604080516003808252608082019092525f91816020015b606081526020019060019003908161233657905050905085815f8151811061236057612360612780565b6020026020010181905250848160018151811061237f5761237f612780565b6020026020010181905250828160028151811061239e5761239e612780565b6020908102919091010152604080516003808252608082019092525f91816020016020820280368337019050509050600560068484846040516020016123e8959493929190612b44565b60405160208183030381529060405297505050505050505092915050565b5080545f8255905f5260205f20908101906124219190612532565b50565b828054828255905f5260205f2090810192821561246f579160200282015b8281111561246f578251805161245f91849160209091019061247f565b5091602001919060010190612442565b5061247b929150612532565b5090565b828054828255905f5260205f209081019282156124b8579160200282015b828111156124b857825182559160200191906001019061249d565b5061247b92915061254e565b5080545f8255905f5260205f2090810190612421919061254e565b828054828255905f5260205f209081019282156124b8579160200282015b828111156124b857825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906124fd565b8082111561247b575f61254582826124c4565b50600101612532565b5b8082111561247b575f815560010161254f565b5f8060408385031215612573575f80fd5b50508035926020909101359150565b5f8083601f840112612592575f80fd5b5081356001600160401b038111156125a8575f80fd5b6020830191508360208260051b85010111156125c2575f80fd5b9250929050565b5f80602083850312156125da575f80fd5b82356001600160401b038111156125ef575f80fd5b6125fb85828601612582565b90969095509350505050565b5f60208284031215612617575f80fd5b813561ffff81168114612628575f80fd5b9392505050565b5f805f805f805f806080898b031215612646575f80fd5b88356001600160401b038082111561265c575f80fd5b6126688c838d01612582565b909a50985060208b0135915080821115612680575f80fd5b61268c8c838d01612582565b909850965060408b01359150808211156126a4575f80fd5b6126b08c838d01612582565b909650945060608b01359150808211156126c8575f80fd5b506126d58b828c01612582565b999c989b5096995094979396929594505050565b6001600160a01b0381168114612421575f80fd5b5f6020828403121561270d575f80fd5b8135612628816126e9565b5f60208284031215612728575f80fd5b5035919050565b6020808252600c908201526b15539055551213d49256915160a21b604082015260600190565b5f60208284031215612765575f80fd5b5051919050565b634e487b7160e01b5f52604160045260245ffd5b634e487b7160e01b5f52603260045260245ffd5b5f808335601e198436030181126127a9575f80fd5b8301803591506001600160401b038211156127c2575f80fd5b6020019150600581901b36038213156125c2575f80fd5b634e487b7160e01b5f52601160045260245ffd5b5f600182016127fe576127fe6127d9565b5060010190565b8183525f6001600160fb1b0383111561281c575f80fd5b8260051b80836020870137939093016020019392505050565b8183525f60208085019450825f5b85811015612871578135612856816126e9565b6001600160a01b031687529582019590820190600101612843565b509495945050505050565b5f8151808452602080850194508084015f5b838110156128715781516001600160a01b03168752958201959082019060010161288e565b5f81518084525f5b818110156128d7576020818501810151868301820152016128bb565b505f602082860101526020601f19601f83011685010191505092915050565b5f81518084526020808501808196508360051b810191508286015f5b8581101561293c57828403895261292a8483516128b3565b98850198935090840190600101612912565b5091979650505050505050565b5f8151808452602080850194508084015f5b838110156128715781518752958201959082019060010161295b565b60a080825281018790525f600560c0808401908a831b8501018b845b8c811015612a055786830360bf190184528135368f9003601e190181126129b8575f80fd5b8e0160208181019135906001600160401b038211156129d5575f80fd5b81881b36038313156129e5575f80fd5b6129f0868385612805565b96810196955093909301925050600101612993565b50508481036020860152612a1a818a8c612835565b925050508281036040840152612a30818761287c565b90508281036060840152612a4481866128f6565b90508281036080840152612a588185612949565b9a9950505050505050505050565b6001600160a01b0393841681529190921660208201526001600160e01b0319909116604082015260600190565b5f60208284031215612aa3575f80fd5b81518015158114612628575f80fd5b8082018082111561169a5761169a6127d9565b6001600160a01b039788168152958716602087015262ffffff9490941660408601529185166060850152608084015260ff1660a083015290911660c082015260e00190565b5f815480845260208085019450835f52805f205f5b838110156128715781546001600160a01b031687529582019560019182019101612b1f565b5f60a0820160a0835280885480835260c08501915060c08160051b86010192505f8a81526020808220825b84811015612bc45788870360bf1901865281548088528285528385208489019190865b82811015612bae57815484529286019260019182019101612b92565b5091985050509482019460019182019101612b6f565b50508685038188015250505050612bdb8188612b0a565b90508281036040840152612bef818761287c565b90508281036060840152612c0381866128f6565b90508281036080840152612c178185612949565b98975050505050505050565b6001600160a01b03851681526080602082018190525f90612c469083018661287c565b8281036040840152612c588186612949565b90508281036060840152612c6c81856128b3565b979650505050505050565b5f60a0820160a0835280885180835260c08501915060c08160051b86010192506020808b015f805b84811015612cf35788870360bf19018652825180518089529085019085890190845b81811015612cdd57835183529287019291870191600101612cc1565b5090985050509483019491830191600101612c9f565b50505085840381870152505050612bdb8188612b0a56fea2646970667358221220c0f92e3e9b75e33e1b01ddea99afccc91bfe5c99c94111ef0a807da2bc9317ee64736f6c63430008150033
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.