Overview
ETH Balance
ETH Value
$0.00Multichain Info
Latest 6 from a total of 6 transactions
Latest 22 internal transactions
Parent Transaction Hash | Block | From | To | ||||
---|---|---|---|---|---|---|---|
12670739 | 4 days ago | 0 ETH | |||||
12670739 | 4 days ago | 0 ETH | |||||
12670739 | 4 days ago | 0 ETH | |||||
12670739 | 4 days ago | 0 ETH | |||||
11900595 | 13 days ago | 0 ETH | |||||
11900595 | 13 days ago | 0 ETH | |||||
11900595 | 13 days ago | 0 ETH | |||||
11900595 | 13 days ago | 0 ETH | |||||
11289758 | 20 days ago | 0 ETH | |||||
11289758 | 20 days ago | 0 ETH | |||||
11289758 | 20 days ago | 0 ETH | |||||
11289758 | 20 days ago | 0 ETH | |||||
11289758 | 20 days ago | 0 ETH | |||||
10582446 | 28 days ago | 0 ETH | |||||
10582446 | 28 days ago | 0 ETH | |||||
10582446 | 28 days ago | 0 ETH | |||||
3337265 | 112 days ago | 0 ETH | |||||
3334073 | 112 days ago | 0 ETH | |||||
3334073 | 112 days ago | 0 ETH | |||||
1851417 | 129 days ago | 0 ETH | |||||
1851417 | 129 days ago | 0 ETH | |||||
1850959 | 129 days ago | 0 ETH |
Contract Source Code Verified (Exact Match)
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

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.