Overview
ETH Balance
ETH Value
$0.00Latest 6 from a total of 6 transactions
View more zero value Internal Transactions in Advanced View mode
Cross-Chain Transactions
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-3.0
// Docgen-SOLC: 0.8.25
pragma solidity ^0.8.25;
import {Owned} from "src/utils/Owned.sol";
import {Pausable} from "src/utils/Pausable.sol";
import {FixedPointMathLib} from "solmate/utils/FixedPointMathLib.sol";
import {ERC4626} from "solmate/tokens/ERC4626.sol";
import {IPushOracle, Price} from "src/interfaces/IPushOracle.sol";
/// @notice Price update struct
struct PriceUpdate {
/// @notice The vault to update the price for
address vault;
/// @notice The asset to update the price for (the asset the vault is denominated in)
address asset;
/// @notice The share value in assets
uint256 shareValueInAssets;
/// @notice The asset value in shares
uint256 assetValueInShares;
}
/// @notice Safety limits for price updates
struct Limit {
/// @notice Maximum allowed price jump from one update to the next (1e18 = 100%)
uint256 jump; // 1e18 = 100%
/// @notice Maximum allowed drawdown from the HWM (1e18 = 100%)
uint256 drawdown; // 1e18 = 100%
}
/**
* @title OracleVaultController
* @author RedVeil
* @notice Controller for updating the price of vaults using a PushOracle
* @dev Updates are made by permissioned keepers in regular intervals.
* @dev A large jump in price or drawdown will pause the vault to safeguard against faulty updates or exploits
*/
contract OracleVaultController is Owned {
using FixedPointMathLib for uint256;
IPushOracle public oracle;
event KeeperUpdated(address previous, address current);
error NotKeeperNorOwner();
constructor(address _oracle, address _owner) Owned(_owner) {
oracle = IPushOracle(_oracle);
}
/*//////////////////////////////////////////////////////////////
ORACLE LOGIC
//////////////////////////////////////////////////////////////*/
/// @dev vault => HWM
mapping(address => uint256) public highWaterMarks;
event VaultAdded(address vault);
/**
* @notice Update the price and hwm of a vault. A large jump in price or drawdown will pause the vault if it is not already paused
* @param priceUpdate The price update to update
* @dev Vault prices shouldnt fluctuate too much since the oracle should be updated regularly. If they do this could be a error, exploit attempt or simply a price jump
* in these cases we will still update the price (future updates will revert the change if it was a faulty update) BUT pause the vault for additionals deposits
*/
function updatePrice(PriceUpdate calldata priceUpdate) external {
_updatePrice(priceUpdate);
}
/**
* @notice Update the prices of multiple vaults
* @param priceUpdates The price updates to update
*/
function updatePrices(PriceUpdate[] calldata priceUpdates) external {
for (uint256 i; i < priceUpdates.length; i++) {
_updatePrice(priceUpdates[i]);
}
}
/// @notice Internal function to update the price of a vault
function _updatePrice(
PriceUpdate calldata priceUpdate
) internal onlyKeeperOrOwner(priceUpdate.vault) {
// Caching
uint256 lastPrice = oracle.getCurrentPrice(
priceUpdate.vault,
priceUpdate.asset
);
uint256 hwm = highWaterMarks[priceUpdate.vault];
bool paused = Pausable(priceUpdate.vault).paused();
Limit memory limit = limits[priceUpdate.vault];
// Check for price jump or drawdown
if (
// Check for price jump down
priceUpdate.shareValueInAssets <
lastPrice.mulDivDown(1e18 - limit.jump, 1e18) ||
// Check for price jump up
priceUpdate.shareValueInAssets >
lastPrice.mulDivDown(1e18 + limit.jump, 1e18) ||
// Check for drawdown
priceUpdate.shareValueInAssets <
hwm.mulDivDown(1e18 - limit.drawdown, 1e18)
) {
// Pause the vault if it is not already paused
if (!paused) {
Pausable(priceUpdate.vault).pause();
}
} else if (priceUpdate.shareValueInAssets > hwm) {
// Update HWM if there wasnt a jump or drawdown
highWaterMarks[priceUpdate.vault] = priceUpdate.shareValueInAssets;
}
// Update the price
oracle.setPrice(
priceUpdate.vault,
priceUpdate.asset,
priceUpdate.shareValueInAssets,
priceUpdate.assetValueInShares
);
}
/**
* @notice Update the price and hwm of a vault over multiple blocks. A large jump in price or drawdown will pause the vault if it is not already paused
* @param priceUpdate The price update to update
* @param changePerBlock The change of price per block
* @param increase Whether the price is increasing or decreasing
* @dev Vault prices shouldnt fluctuate too much since the oracle should be updated regularly. If they do this could be a error, exploit attempt or simply a price jump
* in these cases we will still update the price (future updates will revert the change if it was a faulty update) BUT pause the vault for additionals deposits
*/
function updatePriceOverTime(
PriceUpdate calldata priceUpdate,
uint256 changePerBlock,
bool increase
) external {
_updatePriceOverTime(priceUpdate, changePerBlock, increase);
}
/**
* @notice Update the prices of multiple vaults over multiple blocks
* @param priceUpdates The price updates to update
* @param changesPerBlock The changes of price per block
* @param increases Whether the price is increasing or decreasing
*/
function updatePricesOverTime(
PriceUpdate[] calldata priceUpdates,
uint256[] calldata changesPerBlock,
bool[] calldata increases
) external {
if (priceUpdates.length != changesPerBlock.length)
revert("Invalid length");
if (priceUpdates.length != increases.length) revert("Invalid length");
for (uint256 i; i < priceUpdates.length; i++) {
_updatePriceOverTime(
priceUpdates[i],
changesPerBlock[i],
increases[i]
);
}
}
/// @notice Internal function to update the price of a vault over multiple blocks
function _updatePriceOverTime(
PriceUpdate calldata priceUpdate,
uint256 changePerBlock,
bool increase
) internal onlyKeeperOrOwner(priceUpdate.vault) {
// Caching
uint256 lastPrice = oracle.getCurrentPrice(
priceUpdate.vault,
priceUpdate.asset
);
uint256 hwm = highWaterMarks[priceUpdate.vault];
bool paused = Pausable(priceUpdate.vault).paused();
Limit memory limit = limits[priceUpdate.vault];
// Check for price jump or drawdown
if (
// Check if the changePerBlock is too large
changePerBlock > lastPrice.mulDivDown(1e18 + limit.jump, 1e18)
) {
// Pause the vault if it is not already paused
if (!paused) {
Pausable(priceUpdate.vault).pause();
}
} else if (priceUpdate.shareValueInAssets > hwm) {
// Update HWM if there wasnt a jump or drawdown
highWaterMarks[priceUpdate.vault] = priceUpdate.shareValueInAssets;
}
// Update the price
oracle.setPriceOverTime(
priceUpdate.vault,
priceUpdate.asset,
priceUpdate.shareValueInAssets,
priceUpdate.assetValueInShares,
changePerBlock,
increase
);
}
/**
* @notice Add a vault to the controller to be able to update its price
* @param vault The vault to add
* @dev Will always initialize the price to 1e18 (1:1) -- This is to prevent pausing the vault on the first update
* @dev This function should be called before the vault has received any deposits
*/
function addVault(address vault) external onlyOwner {
highWaterMarks[vault] = 1e18;
oracle.setPrice(vault, address(ERC4626(vault).asset()), 1e18, 1e18);
emit VaultAdded(vault);
}
/*//////////////////////////////////////////////////////////////
KEEPER LOGIC
//////////////////////////////////////////////////////////////*/
/// @dev vault => keeper => isKeeper
mapping(address => mapping(address => bool)) public isKeeper;
event KeeperUpdated(address vault, address keeper, bool isKeeper);
/**
* @notice Set the keeper for a vault
* @param _vault The vault to set the keeper for
* @param _keeper The keeper to set for the vault
*/
function setKeeper(
address _vault,
address _keeper,
bool _isKeeper
) external onlyOwner {
emit KeeperUpdated(_vault, _keeper, _isKeeper);
isKeeper[_vault][_keeper] = _isKeeper;
}
/**
* @notice Modifier to check if the sender is the owner or the keeper for a vault
* @param _vault The vault to check the keeper for
*/
modifier onlyKeeperOrOwner(address _vault) {
if (msg.sender != owner && !isKeeper[_vault][msg.sender])
revert NotKeeperNorOwner();
_;
}
/*//////////////////////////////////////////////////////////////
MANAGEMENT LOGIC
//////////////////////////////////////////////////////////////*/
/// @dev vault => Limit
mapping(address => Limit) public limits;
event LimitUpdated(address vault, Limit previous, Limit current);
/**
* @notice Set the limit for a vault
* @param _vault The vault to set the limit for
* @param _limit The limit to set for the vault
*/
function setLimit(address _vault, Limit memory _limit) external onlyOwner {
_setLimit(_vault, _limit);
}
/**
* @notice Set the limits for multiple vaults
* @param _vaults The vaults to set the limits for
* @param _limits The limits to set for the vaults
*/
function setLimits(
address[] memory _vaults,
Limit[] memory _limits
) external onlyOwner {
if (_vaults.length != _limits.length) revert("Invalid length");
for (uint256 i; i < _vaults.length; i++) {
_setLimit(_vaults[i], _limits[i]);
}
}
/// @notice Internal function to set the limit for a vault
function _setLimit(address _vault, Limit memory _limit) internal {
if (_limit.jump > 1e18 || _limit.drawdown > 1e18)
revert("Invalid limit");
emit LimitUpdated(_vault, limits[_vault], _limit);
limits[_vault] = _limit;
}
/*//////////////////////////////////////////////////////////////
OTHER LOGIC
//////////////////////////////////////////////////////////////*/
/**
* @notice Accept the ownership of the oracle
* @dev Used after construction since we otherwise have recursive dependencies on the construction of this contract and the oracle
*/
function acceptOracleOwnership() external onlyOwner {
Owned(address(oracle)).acceptOwnership();
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol)
/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)
/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.
abstract contract ERC20 {
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/
event Transfer(address indexed from, address indexed to, uint256 amount);
event Approval(address indexed owner, address indexed spender, uint256 amount);
/*//////////////////////////////////////////////////////////////
METADATA STORAGE
//////////////////////////////////////////////////////////////*/
string public name;
string public symbol;
uint8 public immutable decimals;
/*//////////////////////////////////////////////////////////////
ERC20 STORAGE
//////////////////////////////////////////////////////////////*/
uint256 public totalSupply;
mapping(address => uint256) public balanceOf;
mapping(address => mapping(address => uint256)) public allowance;
/*//////////////////////////////////////////////////////////////
EIP-2612 STORAGE
//////////////////////////////////////////////////////////////*/
uint256 internal immutable INITIAL_CHAIN_ID;
bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;
mapping(address => uint256) public nonces;
/*//////////////////////////////////////////////////////////////
CONSTRUCTOR
//////////////////////////////////////////////////////////////*/
constructor(
string memory _name,
string memory _symbol,
uint8 _decimals
) {
name = _name;
symbol = _symbol;
decimals = _decimals;
INITIAL_CHAIN_ID = block.chainid;
INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
}
/*//////////////////////////////////////////////////////////////
ERC20 LOGIC
//////////////////////////////////////////////////////////////*/
function approve(address spender, uint256 amount) public virtual returns (bool) {
allowance[msg.sender][spender] = amount;
emit Approval(msg.sender, spender, amount);
return true;
}
function transfer(address to, uint256 amount) public virtual returns (bool) {
balanceOf[msg.sender] -= amount;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += amount;
}
emit Transfer(msg.sender, to, amount);
return true;
}
function transferFrom(
address from,
address to,
uint256 amount
) public virtual returns (bool) {
uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.
if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;
balanceOf[from] -= amount;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += amount;
}
emit Transfer(from, to, amount);
return true;
}
/*//////////////////////////////////////////////////////////////
EIP-2612 LOGIC
//////////////////////////////////////////////////////////////*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) public virtual {
require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED");
// Unchecked because the only math done is incrementing
// the owner's nonce which cannot realistically overflow.
unchecked {
address recoveredAddress = ecrecover(
keccak256(
abi.encodePacked(
"\x19\x01",
DOMAIN_SEPARATOR(),
keccak256(
abi.encode(
keccak256(
"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
),
owner,
spender,
value,
nonces[owner]++,
deadline
)
)
)
),
v,
r,
s
);
require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER");
allowance[recoveredAddress][spender] = value;
}
emit Approval(owner, spender, value);
}
function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();
}
function computeDomainSeparator() internal view virtual returns (bytes32) {
return
keccak256(
abi.encode(
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
keccak256(bytes(name)),
keccak256("1"),
block.chainid,
address(this)
)
);
}
/*//////////////////////////////////////////////////////////////
INTERNAL MINT/BURN LOGIC
//////////////////////////////////////////////////////////////*/
function _mint(address to, uint256 amount) internal virtual {
totalSupply += amount;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += amount;
}
emit Transfer(address(0), to, amount);
}
function _burn(address from, uint256 amount) internal virtual {
balanceOf[from] -= amount;
// Cannot underflow because a user's balance
// will never be larger than the total supply.
unchecked {
totalSupply -= amount;
}
emit Transfer(from, address(0), amount);
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
import {ERC20} from "../tokens/ERC20.sol";
import {SafeTransferLib} from "../utils/SafeTransferLib.sol";
import {FixedPointMathLib} from "../utils/FixedPointMathLib.sol";
/// @notice Minimal ERC4626 tokenized Vault implementation.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC4626.sol)
abstract contract ERC4626 is ERC20 {
using SafeTransferLib for ERC20;
using FixedPointMathLib for uint256;
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/
event Deposit(address indexed caller, address indexed owner, uint256 assets, uint256 shares);
event Withdraw(
address indexed caller,
address indexed receiver,
address indexed owner,
uint256 assets,
uint256 shares
);
/*//////////////////////////////////////////////////////////////
IMMUTABLES
//////////////////////////////////////////////////////////////*/
ERC20 public immutable asset;
constructor(
ERC20 _asset,
string memory _name,
string memory _symbol
) ERC20(_name, _symbol, _asset.decimals()) {
asset = _asset;
}
/*//////////////////////////////////////////////////////////////
DEPOSIT/WITHDRAWAL LOGIC
//////////////////////////////////////////////////////////////*/
function deposit(uint256 assets, address receiver) public virtual returns (uint256 shares) {
// Check for rounding error since we round down in previewDeposit.
require((shares = previewDeposit(assets)) != 0, "ZERO_SHARES");
// Need to transfer before minting or ERC777s could reenter.
asset.safeTransferFrom(msg.sender, address(this), assets);
_mint(receiver, shares);
emit Deposit(msg.sender, receiver, assets, shares);
afterDeposit(assets, shares);
}
function mint(uint256 shares, address receiver) public virtual returns (uint256 assets) {
assets = previewMint(shares); // No need to check for rounding error, previewMint rounds up.
// Need to transfer before minting or ERC777s could reenter.
asset.safeTransferFrom(msg.sender, address(this), assets);
_mint(receiver, shares);
emit Deposit(msg.sender, receiver, assets, shares);
afterDeposit(assets, shares);
}
function withdraw(
uint256 assets,
address receiver,
address owner
) public virtual returns (uint256 shares) {
shares = previewWithdraw(assets); // No need to check for rounding error, previewWithdraw rounds up.
if (msg.sender != owner) {
uint256 allowed = allowance[owner][msg.sender]; // Saves gas for limited approvals.
if (allowed != type(uint256).max) allowance[owner][msg.sender] = allowed - shares;
}
beforeWithdraw(assets, shares);
_burn(owner, shares);
emit Withdraw(msg.sender, receiver, owner, assets, shares);
asset.safeTransfer(receiver, assets);
}
function redeem(
uint256 shares,
address receiver,
address owner
) public virtual returns (uint256 assets) {
if (msg.sender != owner) {
uint256 allowed = allowance[owner][msg.sender]; // Saves gas for limited approvals.
if (allowed != type(uint256).max) allowance[owner][msg.sender] = allowed - shares;
}
// Check for rounding error since we round down in previewRedeem.
require((assets = previewRedeem(shares)) != 0, "ZERO_ASSETS");
beforeWithdraw(assets, shares);
_burn(owner, shares);
emit Withdraw(msg.sender, receiver, owner, assets, shares);
asset.safeTransfer(receiver, assets);
}
/*//////////////////////////////////////////////////////////////
ACCOUNTING LOGIC
//////////////////////////////////////////////////////////////*/
function totalAssets() public view virtual returns (uint256);
function convertToShares(uint256 assets) public view virtual returns (uint256) {
uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero.
return supply == 0 ? assets : assets.mulDivDown(supply, totalAssets());
}
function convertToAssets(uint256 shares) public view virtual returns (uint256) {
uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero.
return supply == 0 ? shares : shares.mulDivDown(totalAssets(), supply);
}
function previewDeposit(uint256 assets) public view virtual returns (uint256) {
return convertToShares(assets);
}
function previewMint(uint256 shares) public view virtual returns (uint256) {
uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero.
return supply == 0 ? shares : shares.mulDivUp(totalAssets(), supply);
}
function previewWithdraw(uint256 assets) public view virtual returns (uint256) {
uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero.
return supply == 0 ? assets : assets.mulDivUp(supply, totalAssets());
}
function previewRedeem(uint256 shares) public view virtual returns (uint256) {
return convertToAssets(shares);
}
/*//////////////////////////////////////////////////////////////
DEPOSIT/WITHDRAWAL LIMIT LOGIC
//////////////////////////////////////////////////////////////*/
function maxDeposit(address) public view virtual returns (uint256) {
return type(uint256).max;
}
function maxMint(address) public view virtual returns (uint256) {
return type(uint256).max;
}
function maxWithdraw(address owner) public view virtual returns (uint256) {
return convertToAssets(balanceOf[owner]);
}
function maxRedeem(address owner) public view virtual returns (uint256) {
return balanceOf[owner];
}
/*//////////////////////////////////////////////////////////////
INTERNAL HOOKS LOGIC
//////////////////////////////////////////////////////////////*/
function beforeWithdraw(uint256 assets, uint256 shares) internal virtual {}
function afterDeposit(uint256 assets, uint256 shares) internal virtual {}
}// 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: 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: GPL-2.0-or-later pragma solidity >=0.8.0; /// @title IPriceOracle /// @custom:security-contact [email protected] /// @author Euler Labs (https://www.eulerlabs.com/) /// @notice Common PriceOracle interface. interface IPriceOracle { /// @notice Get the name of the oracle. /// @return The name of the oracle. function name() external view returns (string memory); /// @notice One-sided price: How much quote token you would get for inAmount of base token, assuming no price spread. /// @param inAmount The amount of `base` to convert. /// @param base The token that is being priced. /// @param quote The token that is the unit of account. /// @return outAmount The amount of `quote` that is equivalent to `inAmount` of `base`. function getQuote( uint256 inAmount, address base, address quote ) external view returns (uint256 outAmount); /// @notice Two-sided price: How much quote token you would get/spend for selling/buying inAmount of base token. /// @param inAmount The amount of `base` to convert. /// @param base The token that is being priced. /// @param quote The token that is the unit of account. /// @return bidOutAmount The amount of `quote` you would get for selling `inAmount` of `base`. /// @return askOutAmount The amount of `quote` you would spend for buying `inAmount` of `base`. function getQuotes( uint256 inAmount, address base, address quote ) external view returns (uint256 bidOutAmount, uint256 askOutAmount); }
// SPDX-License-Identifier: GPL-3.0
// Docgen-SOLC: 0.8.25
pragma solidity ^0.8.25;
import {IPriceOracle} from "./IPriceOracle.sol";
struct Price {
uint256 price;
uint256 targetPrice;
uint256 changePerBlock;
uint256 lastUpdatedBlock;
bool increase;
}
interface IPushOracle is IPriceOracle {
function setPrice(
address base,
address quote,
uint256 bqPrice,
uint256 qbPrice
) external;
function setPrices(
address[] memory bases,
address[] memory quotes,
uint256[] memory bqPrices,
uint256[] memory qbPrices
) external;
function prices(
address base,
address quote
) external view returns (Price memory);
function setPriceOverTime(
address base,
address quote,
uint256 bqTargetPrice,
uint256 qbTargetPrice,
uint256 changePerBlock,
bool increase
) external;
function setPricesOverTime(
address[] memory bases,
address[] memory quotes,
uint256[] memory bqTargetPrices,
uint256[] memory qbTargetPrices,
uint256[] memory changePerBlocks,
bool[] memory increases
) external;
function getCurrentPrice(
address base,
address quote
) external view returns (uint256);
}// SPDX-License-Identifier: GPL-3.0
// Docgen-SOLC: 0.8.25
pragma solidity ^0.8.25;
// https://docs.synthetix.io/contracts/source/contracts/owned
contract Owned {
address public owner;
address public nominatedOwner;
event OwnerNominated(address newOwner);
event OwnerChanged(address oldOwner, address newOwner);
constructor(address _owner) {
require(_owner != address(0), "Owned/owner-zero");
owner = _owner;
emit OwnerChanged(address(0), _owner);
}
function nominateNewOwner(address _owner) external virtual onlyOwner {
nominatedOwner = _owner;
emit OwnerNominated(_owner);
}
function acceptOwnership() external virtual {
require(
msg.sender == nominatedOwner,
"Owned/not-nominated"
);
emit OwnerChanged(owner, nominatedOwner);
owner = nominatedOwner;
nominatedOwner = address(0);
}
modifier onlyOwner() {
_onlyOwner();
_;
}
function _onlyOwner() private view {
require(
msg.sender == owner,
"Owned/not-owner"
);
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
/// @notice Gas optimized Pausable for smart contracts.
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Pausable.sol)
abstract contract Pausable {
bool public paused;
event Paused(address account);
event Unpaused(address account);
modifier whenNotPaused() {
_requireNotPaused();
_;
}
modifier whenPaused() {
_requirePaused();
_;
}
function _requireNotPaused() internal view virtual {
if (paused) {
revert("Pausable/paused");
}
}
/**
* @dev Throws if the contract is not paused.
*/
function _requirePaused() internal view virtual {
if (!paused) {
revert("Pausable/not-paused");
}
}
function _pause() internal virtual whenNotPaused {
paused = true;
emit Paused(msg.sender);
}
function _unpause() internal virtual whenPaused {
paused = false;
emit Unpaused(msg.sender);
}
function pause() external virtual whenNotPaused {
_pause();
}
function unpause() external virtual whenPaused {
_unpause();
}
}{
"evmVersion": "shanghai",
"libraries": {},
"metadata": {
"appendCBOR": true,
"bytecodeHash": "ipfs",
"useLiteralContent": false
},
"optimizer": {
"enabled": true,
"runs": 20000
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"remappings": [
"ds-test/=lib/forge-std/lib/ds-test/src/",
"forge-std/=lib/forge-std/src/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/contracts/",
"openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
"solmate/=lib/solmate/src/",
"safe-smart-account/=lib/safe-smart-account/contracts/",
"weiroll/=lib/weiroll/contracts/",
"solady/=lib/solady/src/",
"bitlib/=lib/solidity-bytes-utils/contracts/",
"ERC-7540/=lib/ERC-7540-Reference/src/",
"@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
"@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
"@pyth/=lib/euler-price-oracle/lib/pyth-sdk-solidity/",
"@redstone/evm-connector/=lib/euler-price-oracle/lib/redstone-oracles-monorepo/packages/evm-connector/contracts/",
"@solady/=lib/euler-price-oracle/lib/solady/src/",
"@uniswap/v3-core/=lib/euler-price-oracle/lib/v3-core/",
"@uniswap/v3-periphery/=lib/euler-price-oracle/lib/v3-periphery/",
"ERC-7540-Reference/=lib/ERC-7540-Reference/src/",
"erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
"euler-price-oracle/=lib/euler-price-oracle/src/",
"halmos-cheatcodes/=lib/openzeppelin-contracts-upgradeable/lib/halmos-cheatcodes/src/",
"openzeppelin/=lib/euler-price-oracle/lib/openzeppelin-contracts/contracts/",
"pyth-sdk-solidity/=lib/euler-price-oracle/lib/pyth-sdk-solidity/",
"redstone-oracles-monorepo/=lib/euler-price-oracle/lib/",
"solidity-bytes-utils/=lib/solidity-bytes-utils/contracts/",
"v3-core/=lib/v3-core/",
"v3-periphery/=lib/v3-periphery/contracts/"
],
"viaIR": false
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_oracle","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"NotKeeperNorOwner","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"previous","type":"address"},{"indexed":false,"internalType":"address","name":"current","type":"address"}],"name":"KeeperUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"vault","type":"address"},{"indexed":false,"internalType":"address","name":"keeper","type":"address"},{"indexed":false,"internalType":"bool","name":"isKeeper","type":"bool"}],"name":"KeeperUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"vault","type":"address"},{"components":[{"internalType":"uint256","name":"jump","type":"uint256"},{"internalType":"uint256","name":"drawdown","type":"uint256"}],"indexed":false,"internalType":"struct Limit","name":"previous","type":"tuple"},{"components":[{"internalType":"uint256","name":"jump","type":"uint256"},{"internalType":"uint256","name":"drawdown","type":"uint256"}],"indexed":false,"internalType":"struct Limit","name":"current","type":"tuple"}],"name":"LimitUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":false,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerNominated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"vault","type":"address"}],"name":"VaultAdded","type":"event"},{"inputs":[],"name":"acceptOracleOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"vault","type":"address"}],"name":"addVault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"highWaterMarks","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"isKeeper","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"limits","outputs":[{"internalType":"uint256","name":"jump","type":"uint256"},{"internalType":"uint256","name":"drawdown","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"nominateNewOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"nominatedOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"oracle","outputs":[{"internalType":"contract IPushOracle","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_vault","type":"address"},{"internalType":"address","name":"_keeper","type":"address"},{"internalType":"bool","name":"_isKeeper","type":"bool"}],"name":"setKeeper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_vault","type":"address"},{"components":[{"internalType":"uint256","name":"jump","type":"uint256"},{"internalType":"uint256","name":"drawdown","type":"uint256"}],"internalType":"struct Limit","name":"_limit","type":"tuple"}],"name":"setLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_vaults","type":"address[]"},{"components":[{"internalType":"uint256","name":"jump","type":"uint256"},{"internalType":"uint256","name":"drawdown","type":"uint256"}],"internalType":"struct Limit[]","name":"_limits","type":"tuple[]"}],"name":"setLimits","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"vault","type":"address"},{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint256","name":"shareValueInAssets","type":"uint256"},{"internalType":"uint256","name":"assetValueInShares","type":"uint256"}],"internalType":"struct PriceUpdate","name":"priceUpdate","type":"tuple"}],"name":"updatePrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"vault","type":"address"},{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint256","name":"shareValueInAssets","type":"uint256"},{"internalType":"uint256","name":"assetValueInShares","type":"uint256"}],"internalType":"struct PriceUpdate","name":"priceUpdate","type":"tuple"},{"internalType":"uint256","name":"changePerBlock","type":"uint256"},{"internalType":"bool","name":"increase","type":"bool"}],"name":"updatePriceOverTime","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"vault","type":"address"},{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint256","name":"shareValueInAssets","type":"uint256"},{"internalType":"uint256","name":"assetValueInShares","type":"uint256"}],"internalType":"struct PriceUpdate[]","name":"priceUpdates","type":"tuple[]"}],"name":"updatePrices","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"vault","type":"address"},{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint256","name":"shareValueInAssets","type":"uint256"},{"internalType":"uint256","name":"assetValueInShares","type":"uint256"}],"internalType":"struct PriceUpdate[]","name":"priceUpdates","type":"tuple[]"},{"internalType":"uint256[]","name":"changesPerBlock","type":"uint256[]"},{"internalType":"bool[]","name":"increases","type":"bool[]"}],"name":"updatePricesOverTime","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
608060405234801561000f575f5ffd5b50604051611c2a380380611c2a83398101604081905261002e91610114565b806001600160a01b03811661007c5760405162461bcd60e51b815260206004820152601060248201526f4f776e65642f6f776e65722d7a65726f60801b604482015260640160405180910390fd5b5f80546001600160a01b0319166001600160a01b03831690811782556040805192835260208301919091527fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c910160405180910390a15050600280546001600160a01b0319166001600160a01b0392909216919091179055610145565b80516001600160a01b038116811461010f575f5ffd5b919050565b5f5f60408385031215610125575f5ffd5b61012e836100f9565b915061013c602084016100f9565b90509250929050565b611ad8806101525f395ff3fe608060405234801561000f575f5ffd5b5060043610610115575f3560e01c806379ba5097116100ad578063a64d48361161007d578063fb116cd811610063578063fb116cd8146102d6578063fd5835d0146102e9578063fe47ec9a146102f1575f5ffd5b8063a64d483614610296578063aa165f32146102c3575f5ffd5b806379ba5097146102125780637dc0d1d01461021a5780638da5cb5b1461023a57806397f2b7f214610259575f5ffd5b8063256b5a02116100e8578063256b5a02146101945780634261da37146101a757806353a47bb7146101ba578063720d033f146101ff575f5ffd5b806304efb1fb146101195780631032a4131461012e5780631627540c1461014157806320d7bec114610154575b5f5ffd5b61012c610127366004611643565b610304565b005b61012c61013c36600461172b565b6103d0565b61012c61014f366004611769565b6103db565b61017a610162366004611769565b60056020525f90815260409020805460019091015482565b604080519283526020830191909152015b60405180910390f35b61012c6101a2366004611769565b61045d565b61012c6101b536600461178b565b6105f3565b6001546101da9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161018b565b61012c61020d366004611807565b610609565b61012c61063b565b6002546101da9073ffffffffffffffffffffffffffffffffffffffff1681565b5f546101da9073ffffffffffffffffffffffffffffffffffffffff1681565b610286610267366004611846565b600460209081525f928352604080842090915290825290205460ff1681565b604051901515815260200161018b565b6102b56102a4366004611769565b60036020525f908152604090205481565b60405190815260200161018b565b61012c6102d136600461187d565b61075e565b61012c6102e43660046118d8565b61076a565b61012c6108b7565b61012c6102ff366004611977565b61093d565b61030c610a01565b805182511461037c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f496e76616c6964206c656e67746800000000000000000000000000000000000060448201526064015b60405180910390fd5b5f5b82518110156103cb576103c383828151811061039c5761039c6119b4565b60200260200101518383815181106103b6576103b66119b4565b6020026020010151610a83565b60010161037e565b505050565b6103cb838383610bb8565b6103e3610a01565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce22906020015b60405180910390a150565b610465610a01565b73ffffffffffffffffffffffffffffffffffffffff8082165f81815260036020908152604091829020670de0b6b3a7640000905560025482517f38d52e0f000000000000000000000000000000000000000000000000000000008152925194169363a405d31293869390926338d52e0f926004808401938290030181865afa1580156104f3573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061051791906119e1565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff928316600482015291166024820152670de0b6b3a76400006044820181905260648201526084015f604051808303815f87803b158015610596575f5ffd5b505af11580156105a8573d5f5f3e3d5ffd5b505060405173ffffffffffffffffffffffffffffffffffffffff841681527f7b7ef7a864d96a85497a1ed846adb39940dd6ccef678ff6ac8d55505e09b8cc492506020019050610452565b6105fb610a01565b6106058282610a83565b5050565b5f5b818110156103cb57610633838383818110610628576106286119b4565b905060800201611000565b60010161060b565b60015473ffffffffffffffffffffffffffffffffffffffff1633146106bc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4f776e65642f6e6f742d6e6f6d696e61746564000000000000000000000000006044820152606401610373565b5f546001546040805173ffffffffffffffffffffffffffffffffffffffff93841681529290911660208301527fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c910160405180910390a1600180545f80547fffffffffffffffffffffffff000000000000000000000000000000000000000090811673ffffffffffffffffffffffffffffffffffffffff841617909155169055565b61076781611000565b50565b8483146107d3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f496e76616c6964206c656e6774680000000000000000000000000000000000006044820152606401610373565b84811461083c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f496e76616c6964206c656e6774680000000000000000000000000000000000006044820152606401610373565b5f5b858110156108ae576108a687878381811061085b5761085b6119b4565b905060800201868684818110610873576108736119b4565b9050602002013585858581811061088c5761088c6119b4565b90506020020160208101906108a191906119fc565b610bb8565b60010161083e565b50505050505050565b6108bf610a01565b60025f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166379ba50976040518163ffffffff1660e01b81526004015f604051808303815f87803b158015610925575f5ffd5b505af1158015610937573d5f5f3e3d5ffd5b50505050565b610945610a01565b6040805173ffffffffffffffffffffffffffffffffffffffff8581168252841660208201528215158183015290517f86665cd5d3d01ca9aad62eea6871fe4a5a65c2359ab24777315c7cf712f1e2a99181900360600190a173ffffffffffffffffffffffffffffffffffffffff9283165f9081526004602090815260408083209490951682529290925291902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055565b5f5473ffffffffffffffffffffffffffffffffffffffff163314610a81576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f4f776e65642f6e6f742d6f776e657200000000000000000000000000000000006044820152606401610373565b565b8051670de0b6b3a76400001080610aa55750670de0b6b3a76400008160200151115b15610b0c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c6964206c696d6974000000000000000000000000000000000000006044820152606401610373565b73ffffffffffffffffffffffffffffffffffffffff82165f8181526005602090815260409182902082519384528054848301526001015483830152835160608401528301516080830152517fc4b9b0c18c54d55c96918e7cb235095f193a9fae0a7c81a0c19c0397ec9779329181900360a00190a173ffffffffffffffffffffffffffffffffffffffff9091165f90815260056020908152604090912082518155910151600190910155565b610bc56020840184611769565b5f5473ffffffffffffffffffffffffffffffffffffffff163314801590610c1c575073ffffffffffffffffffffffffffffffffffffffff81165f90815260046020908152604080832033845290915290205460ff16155b15610c53576040517fc6764d6d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002545f9073ffffffffffffffffffffffffffffffffffffffff1663db16a555610c806020880188611769565b610c906040890160208a01611769565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff928316600482015291166024820152604401602060405180830381865afa158015610cfe573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d229190611a17565b90505f600381610d356020890189611769565b73ffffffffffffffffffffffffffffffffffffffff1681526020808201929092526040015f90812054925090610d6d90880188611769565b73ffffffffffffffffffffffffffffffffffffffff16635c975abb6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610db5573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610dd99190611a2e565b90505f600581610dec60208b018b611769565b73ffffffffffffffffffffffffffffffffffffffff16815260208082019290925260409081015f2081518083019092528054808352600190910154928201929092529150610e5690610e4690670de0b6b3a7640000611a76565b8590670de0b6b3a7640000611488565b871115610ecf5781610eca57610e6f6020890189611769565b73ffffffffffffffffffffffffffffffffffffffff16638456cb596040518163ffffffff1660e01b81526004015f604051808303815f87803b158015610eb3575f5ffd5b505af1158015610ec5573d5f5f3e3d5ffd5b505050505b610f17565b8288604001351115610f1757604088013560035f610ef060208c018c611769565b73ffffffffffffffffffffffffffffffffffffffff16815260208101919091526040015f20555b60025473ffffffffffffffffffffffffffffffffffffffff1663d073aec1610f4260208b018b611769565b610f5260408c0160208d01611769565b604080517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b16815273ffffffffffffffffffffffffffffffffffffffff93841660048201529290911660248301528b0135604482015260608b01356064820152608481018a905288151560a482015260c4015f604051808303815f87803b158015610fe0575f5ffd5b505af1158015610ff2573d5f5f3e3d5ffd5b505050505050505050505050565b61100d6020820182611769565b5f5473ffffffffffffffffffffffffffffffffffffffff163314801590611064575073ffffffffffffffffffffffffffffffffffffffff81165f90815260046020908152604080832033845290915290205460ff16155b1561109b576040517fc6764d6d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002545f9073ffffffffffffffffffffffffffffffffffffffff1663db16a5556110c86020860186611769565b6110d86040870160208801611769565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff928316600482015291166024820152604401602060405180830381865afa158015611146573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061116a9190611a17565b90505f60038161117d6020870187611769565b73ffffffffffffffffffffffffffffffffffffffff1681526020808201929092526040015f908120549250906111b590860186611769565b73ffffffffffffffffffffffffffffffffffffffff16635c975abb6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156111fd573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112219190611a2e565b90505f6005816112346020890189611769565b73ffffffffffffffffffffffffffffffffffffffff16815260208082019290925260409081015f208151808301909252805480835260019091015492820192909252915061128e90610e4690670de0b6b3a7640000611a8f565b866040013510806112b9575080516112b290610e4690670de0b6b3a7640000611a76565b8660400135115b806112f157506112ea8160200151670de0b6b3a76400006112da9190611a8f565b8490670de0b6b3a7640000611488565b8660400135105b156113685781611363576113086020870187611769565b73ffffffffffffffffffffffffffffffffffffffff16638456cb596040518163ffffffff1660e01b81526004015f604051808303815f87803b15801561134c575f5ffd5b505af115801561135e573d5f5f3e3d5ffd5b505050505b6113b0565b82866040013511156113b057604086013560035f61138960208a018a611769565b73ffffffffffffffffffffffffffffffffffffffff16815260208101919091526040015f20555b60025473ffffffffffffffffffffffffffffffffffffffff1663a405d3126113db6020890189611769565b6113eb60408a0160208b01611769565b604080517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b16815273ffffffffffffffffffffffffffffffffffffffff93841660048201529290911660248301528901356044820152606089013560648201526084015f604051808303815f87803b15801561146a575f5ffd5b505af115801561147c573d5f5f3e3d5ffd5b50505050505050505050565b5f827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04841183021582026114bb575f5ffd5b5091020490565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715611536576115366114c2565b604052919050565b5f67ffffffffffffffff821115611557576115576114c2565b5060051b60200190565b73ffffffffffffffffffffffffffffffffffffffff81168114610767575f5ffd5b5f60408284031215611592575f5ffd5b6040805190810167ffffffffffffffff811182821017156115b5576115b56114c2565b604052823581526020928301359281019290925250919050565b5f82601f8301126115de575f5ffd5b81356115f16115ec8261153e565b6114ef565b8082825260208201915060208360061b860101925085831115611612575f5ffd5b602085015b83811015611639576116298782611582565b8352602090920191604001611617565b5095945050505050565b5f5f60408385031215611654575f5ffd5b823567ffffffffffffffff81111561166a575f5ffd5b8301601f8101851361167a575f5ffd5b80356116886115ec8261153e565b8082825260208201915060208360051b8501019250878311156116a9575f5ffd5b6020840193505b828410156116d45783356116c381611561565b8252602093840193909101906116b0565b9450505050602083013567ffffffffffffffff8111156116f2575f5ffd5b6116fe858286016115cf565b9150509250929050565b5f60808284031215611718575f5ffd5b50919050565b8015158114610767575f5ffd5b5f5f5f60c0848603121561173d575f5ffd5b6117478585611708565b92506080840135915060a084013561175e8161171e565b809150509250925092565b5f60208284031215611779575f5ffd5b813561178481611561565b9392505050565b5f5f6060838503121561179c575f5ffd5b82356117a781611561565b91506117b68460208501611582565b90509250929050565b5f5f83601f8401126117cf575f5ffd5b50813567ffffffffffffffff8111156117e6575f5ffd5b6020830191508360208260071b8501011115611800575f5ffd5b9250929050565b5f5f60208385031215611818575f5ffd5b823567ffffffffffffffff81111561182e575f5ffd5b61183a858286016117bf565b90969095509350505050565b5f5f60408385031215611857575f5ffd5b823561186281611561565b9150602083013561187281611561565b809150509250929050565b5f6080828403121561188d575f5ffd5b6117848383611708565b5f5f83601f8401126118a7575f5ffd5b50813567ffffffffffffffff8111156118be575f5ffd5b6020830191508360208260051b8501011115611800575f5ffd5b5f5f5f5f5f5f606087890312156118ed575f5ffd5b863567ffffffffffffffff811115611903575f5ffd5b61190f89828a016117bf565b909750955050602087013567ffffffffffffffff81111561192e575f5ffd5b61193a89828a01611897565b909550935050604087013567ffffffffffffffff811115611959575f5ffd5b61196589828a01611897565b979a9699509497509295939492505050565b5f5f5f60608486031215611989575f5ffd5b833561199481611561565b925060208401356119a481611561565b9150604084013561175e8161171e565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f602082840312156119f1575f5ffd5b815161178481611561565b5f60208284031215611a0c575f5ffd5b81356117848161171e565b5f60208284031215611a27575f5ffd5b5051919050565b5f60208284031215611a3e575f5ffd5b81516117848161171e565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b80820180821115611a8957611a89611a49565b92915050565b81810381811115611a8957611a89611a4956fea2646970667358221220db68e1a93f8437761fe63c5e07908089b074b42e793e75b333259423d92221ee64736f6c634300081c0033000000000000000000000000b2a4e3b4843adea2abdcc02aa9db8261fd9323ad000000000000000000000000919d5a6f2cbc0731380c26b4ac4f6183dd3a40c8
Deployed Bytecode
0x608060405234801561000f575f5ffd5b5060043610610115575f3560e01c806379ba5097116100ad578063a64d48361161007d578063fb116cd811610063578063fb116cd8146102d6578063fd5835d0146102e9578063fe47ec9a146102f1575f5ffd5b8063a64d483614610296578063aa165f32146102c3575f5ffd5b806379ba5097146102125780637dc0d1d01461021a5780638da5cb5b1461023a57806397f2b7f214610259575f5ffd5b8063256b5a02116100e8578063256b5a02146101945780634261da37146101a757806353a47bb7146101ba578063720d033f146101ff575f5ffd5b806304efb1fb146101195780631032a4131461012e5780631627540c1461014157806320d7bec114610154575b5f5ffd5b61012c610127366004611643565b610304565b005b61012c61013c36600461172b565b6103d0565b61012c61014f366004611769565b6103db565b61017a610162366004611769565b60056020525f90815260409020805460019091015482565b604080519283526020830191909152015b60405180910390f35b61012c6101a2366004611769565b61045d565b61012c6101b536600461178b565b6105f3565b6001546101da9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161018b565b61012c61020d366004611807565b610609565b61012c61063b565b6002546101da9073ffffffffffffffffffffffffffffffffffffffff1681565b5f546101da9073ffffffffffffffffffffffffffffffffffffffff1681565b610286610267366004611846565b600460209081525f928352604080842090915290825290205460ff1681565b604051901515815260200161018b565b6102b56102a4366004611769565b60036020525f908152604090205481565b60405190815260200161018b565b61012c6102d136600461187d565b61075e565b61012c6102e43660046118d8565b61076a565b61012c6108b7565b61012c6102ff366004611977565b61093d565b61030c610a01565b805182511461037c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f496e76616c6964206c656e67746800000000000000000000000000000000000060448201526064015b60405180910390fd5b5f5b82518110156103cb576103c383828151811061039c5761039c6119b4565b60200260200101518383815181106103b6576103b66119b4565b6020026020010151610a83565b60010161037e565b505050565b6103cb838383610bb8565b6103e3610a01565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce22906020015b60405180910390a150565b610465610a01565b73ffffffffffffffffffffffffffffffffffffffff8082165f81815260036020908152604091829020670de0b6b3a7640000905560025482517f38d52e0f000000000000000000000000000000000000000000000000000000008152925194169363a405d31293869390926338d52e0f926004808401938290030181865afa1580156104f3573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061051791906119e1565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff928316600482015291166024820152670de0b6b3a76400006044820181905260648201526084015f604051808303815f87803b158015610596575f5ffd5b505af11580156105a8573d5f5f3e3d5ffd5b505060405173ffffffffffffffffffffffffffffffffffffffff841681527f7b7ef7a864d96a85497a1ed846adb39940dd6ccef678ff6ac8d55505e09b8cc492506020019050610452565b6105fb610a01565b6106058282610a83565b5050565b5f5b818110156103cb57610633838383818110610628576106286119b4565b905060800201611000565b60010161060b565b60015473ffffffffffffffffffffffffffffffffffffffff1633146106bc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4f776e65642f6e6f742d6e6f6d696e61746564000000000000000000000000006044820152606401610373565b5f546001546040805173ffffffffffffffffffffffffffffffffffffffff93841681529290911660208301527fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c910160405180910390a1600180545f80547fffffffffffffffffffffffff000000000000000000000000000000000000000090811673ffffffffffffffffffffffffffffffffffffffff841617909155169055565b61076781611000565b50565b8483146107d3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f496e76616c6964206c656e6774680000000000000000000000000000000000006044820152606401610373565b84811461083c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f496e76616c6964206c656e6774680000000000000000000000000000000000006044820152606401610373565b5f5b858110156108ae576108a687878381811061085b5761085b6119b4565b905060800201868684818110610873576108736119b4565b9050602002013585858581811061088c5761088c6119b4565b90506020020160208101906108a191906119fc565b610bb8565b60010161083e565b50505050505050565b6108bf610a01565b60025f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166379ba50976040518163ffffffff1660e01b81526004015f604051808303815f87803b158015610925575f5ffd5b505af1158015610937573d5f5f3e3d5ffd5b50505050565b610945610a01565b6040805173ffffffffffffffffffffffffffffffffffffffff8581168252841660208201528215158183015290517f86665cd5d3d01ca9aad62eea6871fe4a5a65c2359ab24777315c7cf712f1e2a99181900360600190a173ffffffffffffffffffffffffffffffffffffffff9283165f9081526004602090815260408083209490951682529290925291902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055565b5f5473ffffffffffffffffffffffffffffffffffffffff163314610a81576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f4f776e65642f6e6f742d6f776e657200000000000000000000000000000000006044820152606401610373565b565b8051670de0b6b3a76400001080610aa55750670de0b6b3a76400008160200151115b15610b0c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f496e76616c6964206c696d6974000000000000000000000000000000000000006044820152606401610373565b73ffffffffffffffffffffffffffffffffffffffff82165f8181526005602090815260409182902082519384528054848301526001015483830152835160608401528301516080830152517fc4b9b0c18c54d55c96918e7cb235095f193a9fae0a7c81a0c19c0397ec9779329181900360a00190a173ffffffffffffffffffffffffffffffffffffffff9091165f90815260056020908152604090912082518155910151600190910155565b610bc56020840184611769565b5f5473ffffffffffffffffffffffffffffffffffffffff163314801590610c1c575073ffffffffffffffffffffffffffffffffffffffff81165f90815260046020908152604080832033845290915290205460ff16155b15610c53576040517fc6764d6d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002545f9073ffffffffffffffffffffffffffffffffffffffff1663db16a555610c806020880188611769565b610c906040890160208a01611769565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff928316600482015291166024820152604401602060405180830381865afa158015610cfe573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d229190611a17565b90505f600381610d356020890189611769565b73ffffffffffffffffffffffffffffffffffffffff1681526020808201929092526040015f90812054925090610d6d90880188611769565b73ffffffffffffffffffffffffffffffffffffffff16635c975abb6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610db5573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610dd99190611a2e565b90505f600581610dec60208b018b611769565b73ffffffffffffffffffffffffffffffffffffffff16815260208082019290925260409081015f2081518083019092528054808352600190910154928201929092529150610e5690610e4690670de0b6b3a7640000611a76565b8590670de0b6b3a7640000611488565b871115610ecf5781610eca57610e6f6020890189611769565b73ffffffffffffffffffffffffffffffffffffffff16638456cb596040518163ffffffff1660e01b81526004015f604051808303815f87803b158015610eb3575f5ffd5b505af1158015610ec5573d5f5f3e3d5ffd5b505050505b610f17565b8288604001351115610f1757604088013560035f610ef060208c018c611769565b73ffffffffffffffffffffffffffffffffffffffff16815260208101919091526040015f20555b60025473ffffffffffffffffffffffffffffffffffffffff1663d073aec1610f4260208b018b611769565b610f5260408c0160208d01611769565b604080517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b16815273ffffffffffffffffffffffffffffffffffffffff93841660048201529290911660248301528b0135604482015260608b01356064820152608481018a905288151560a482015260c4015f604051808303815f87803b158015610fe0575f5ffd5b505af1158015610ff2573d5f5f3e3d5ffd5b505050505050505050505050565b61100d6020820182611769565b5f5473ffffffffffffffffffffffffffffffffffffffff163314801590611064575073ffffffffffffffffffffffffffffffffffffffff81165f90815260046020908152604080832033845290915290205460ff16155b1561109b576040517fc6764d6d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002545f9073ffffffffffffffffffffffffffffffffffffffff1663db16a5556110c86020860186611769565b6110d86040870160208801611769565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff928316600482015291166024820152604401602060405180830381865afa158015611146573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061116a9190611a17565b90505f60038161117d6020870187611769565b73ffffffffffffffffffffffffffffffffffffffff1681526020808201929092526040015f908120549250906111b590860186611769565b73ffffffffffffffffffffffffffffffffffffffff16635c975abb6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156111fd573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112219190611a2e565b90505f6005816112346020890189611769565b73ffffffffffffffffffffffffffffffffffffffff16815260208082019290925260409081015f208151808301909252805480835260019091015492820192909252915061128e90610e4690670de0b6b3a7640000611a8f565b866040013510806112b9575080516112b290610e4690670de0b6b3a7640000611a76565b8660400135115b806112f157506112ea8160200151670de0b6b3a76400006112da9190611a8f565b8490670de0b6b3a7640000611488565b8660400135105b156113685781611363576113086020870187611769565b73ffffffffffffffffffffffffffffffffffffffff16638456cb596040518163ffffffff1660e01b81526004015f604051808303815f87803b15801561134c575f5ffd5b505af115801561135e573d5f5f3e3d5ffd5b505050505b6113b0565b82866040013511156113b057604086013560035f61138960208a018a611769565b73ffffffffffffffffffffffffffffffffffffffff16815260208101919091526040015f20555b60025473ffffffffffffffffffffffffffffffffffffffff1663a405d3126113db6020890189611769565b6113eb60408a0160208b01611769565b604080517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b16815273ffffffffffffffffffffffffffffffffffffffff93841660048201529290911660248301528901356044820152606089013560648201526084015f604051808303815f87803b15801561146a575f5ffd5b505af115801561147c573d5f5f3e3d5ffd5b50505050505050505050565b5f827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04841183021582026114bb575f5ffd5b5091020490565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715611536576115366114c2565b604052919050565b5f67ffffffffffffffff821115611557576115576114c2565b5060051b60200190565b73ffffffffffffffffffffffffffffffffffffffff81168114610767575f5ffd5b5f60408284031215611592575f5ffd5b6040805190810167ffffffffffffffff811182821017156115b5576115b56114c2565b604052823581526020928301359281019290925250919050565b5f82601f8301126115de575f5ffd5b81356115f16115ec8261153e565b6114ef565b8082825260208201915060208360061b860101925085831115611612575f5ffd5b602085015b83811015611639576116298782611582565b8352602090920191604001611617565b5095945050505050565b5f5f60408385031215611654575f5ffd5b823567ffffffffffffffff81111561166a575f5ffd5b8301601f8101851361167a575f5ffd5b80356116886115ec8261153e565b8082825260208201915060208360051b8501019250878311156116a9575f5ffd5b6020840193505b828410156116d45783356116c381611561565b8252602093840193909101906116b0565b9450505050602083013567ffffffffffffffff8111156116f2575f5ffd5b6116fe858286016115cf565b9150509250929050565b5f60808284031215611718575f5ffd5b50919050565b8015158114610767575f5ffd5b5f5f5f60c0848603121561173d575f5ffd5b6117478585611708565b92506080840135915060a084013561175e8161171e565b809150509250925092565b5f60208284031215611779575f5ffd5b813561178481611561565b9392505050565b5f5f6060838503121561179c575f5ffd5b82356117a781611561565b91506117b68460208501611582565b90509250929050565b5f5f83601f8401126117cf575f5ffd5b50813567ffffffffffffffff8111156117e6575f5ffd5b6020830191508360208260071b8501011115611800575f5ffd5b9250929050565b5f5f60208385031215611818575f5ffd5b823567ffffffffffffffff81111561182e575f5ffd5b61183a858286016117bf565b90969095509350505050565b5f5f60408385031215611857575f5ffd5b823561186281611561565b9150602083013561187281611561565b809150509250929050565b5f6080828403121561188d575f5ffd5b6117848383611708565b5f5f83601f8401126118a7575f5ffd5b50813567ffffffffffffffff8111156118be575f5ffd5b6020830191508360208260051b8501011115611800575f5ffd5b5f5f5f5f5f5f606087890312156118ed575f5ffd5b863567ffffffffffffffff811115611903575f5ffd5b61190f89828a016117bf565b909750955050602087013567ffffffffffffffff81111561192e575f5ffd5b61193a89828a01611897565b909550935050604087013567ffffffffffffffff811115611959575f5ffd5b61196589828a01611897565b979a9699509497509295939492505050565b5f5f5f60608486031215611989575f5ffd5b833561199481611561565b925060208401356119a481611561565b9150604084013561175e8161171e565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f602082840312156119f1575f5ffd5b815161178481611561565b5f60208284031215611a0c575f5ffd5b81356117848161171e565b5f60208284031215611a27575f5ffd5b5051919050565b5f60208284031215611a3e575f5ffd5b81516117848161171e565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b80820180821115611a8957611a89611a49565b92915050565b81810381811115611a8957611a89611a4956fea2646970667358221220db68e1a93f8437761fe63c5e07908089b074b42e793e75b333259423d92221ee64736f6c634300081c0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000b2a4e3b4843adea2abdcc02aa9db8261fd9323ad000000000000000000000000919d5a6f2cbc0731380c26b4ac4f6183dd3a40c8
-----Decoded View---------------
Arg [0] : _oracle (address): 0xb2a4E3B4843ADea2abdCc02aa9db8261Fd9323AD
Arg [1] : _owner (address): 0x919D5a6F2CBc0731380C26B4AC4f6183dD3A40C8
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000b2a4e3b4843adea2abdcc02aa9db8261fd9323ad
Arg [1] : 000000000000000000000000919d5a6f2cbc0731380c26b4ac4f6183dd3a40c8
Net Worth in USD
Net Worth in ETH
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.