Feature Tip: Add private address tag to any address under My Name Tag !
Overview
ETH Balance
0 ETH
Eth Value
$0.00Token Holdings
Latest 1 from a total of 1 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
0x61020060 | 14452310 | 974 days ago | IN | 0 ETH | 0.05328239 |
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
15048182 | 877 days ago | 1 ETH | ||||
15048182 | 877 days ago | 1 ETH | ||||
15044461 | 878 days ago | 0.1 ETH | ||||
15044461 | 878 days ago | 0.1 ETH | ||||
15033008 | 880 days ago | 0.01 ETH | ||||
15033008 | 880 days ago | 0.01 ETH | ||||
15031681 | 880 days ago | 0.025 ETH | ||||
15031681 | 880 days ago | 0.025 ETH | ||||
15023125 | 882 days ago | 0.02 ETH | ||||
15023125 | 882 days ago | 0.02 ETH | ||||
15016283 | 883 days ago | 0.01 ETH | ||||
15016283 | 883 days ago | 0.01 ETH | ||||
15015873 | 883 days ago | 0.02 ETH | ||||
15015873 | 883 days ago | 0.02 ETH | ||||
15012581 | 883 days ago | 0.01 ETH | ||||
15012581 | 883 days ago | 0.01 ETH | ||||
15008785 | 884 days ago | 0.2 ETH | ||||
15008785 | 884 days ago | 0.2 ETH | ||||
15006138 | 885 days ago | 0.01 ETH | ||||
15006138 | 885 days ago | 0.01 ETH | ||||
15002076 | 885 days ago | 0.002 ETH | ||||
15002076 | 885 days ago | 0.002 ETH | ||||
14999054 | 886 days ago | 0.011 ETH | ||||
14999054 | 886 days ago | 0.011 ETH | ||||
14998239 | 886 days ago | 0.01 ETH |
Loading...
Loading
Contract Name:
WstETHAdapter
Compiler Version
v0.8.11+commit.d7f03943
Optimization Enabled:
Yes with 100 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity 0.8.11; // External references import { FixedMath } from "../../external/FixedMath.sol"; // Internal references import { BaseAdapter } from "../BaseAdapter.sol"; import { ERC20 } from "@rari-capital/solmate/src/tokens/ERC20.sol"; import { SafeTransferLib } from "@rari-capital/solmate/src/utils/SafeTransferLib.sol"; import { Errors } from "@sense-finance/v1-utils/src/libs/Errors.sol"; interface WstETHLike { /// @notice https://github.com/lidofinance/lido-dao/blob/master/contracts/0.6.12/WstETH.sol /// @dev returns the current exchange rate of stETH to wstETH in wei (18 decimals) function stEthPerToken() external view returns (uint256); function unwrap(uint256 _wstETHAmount) external returns (uint256); function wrap(uint256 _stETHAmount) external returns (uint256); } interface StETHLike { /// @notice Send funds to the pool with optional _referral parameter /// @dev This function is alternative way to submit funds. Supports optional referral address. /// @return Amount of StETH shares generated function submit(address _referral) external payable returns (uint256); /// @return the amount of tokens owned by the `_account`. /// /// @dev Balances are dynamic and equal the `_account`'s share in the amount of the /// total Ether controlled by the protocol. See `sharesOf`. function getPooledEthByShares(uint256 _sharesAmount) external view returns (uint256); ///@return the amount of tokens owned by the `_account`. /// ///@dev Balances are dynamic and equal the `_account`'s share in the amount of the ///total Ether controlled by the protocol. See `sharesOf`. function balanceOf(address _account) external view returns (uint256); } interface CurveStableSwapLike { function get_dy( int128 i, int128 j, uint256 dx ) external view returns (uint256); function exchange( int128 i, int128 j, uint256 dx, uint256 min_dy ) external payable returns (uint256); } interface WETHLike { function deposit() external payable; function withdraw(uint256 wad) external; } interface StEthPriceFeedLike { function safe_price_value() external view returns (uint256); } /// @notice Adapter contract for wstETH contract WstETHAdapter is BaseAdapter { using FixedMath for uint256; using SafeTransferLib for ERC20; address public constant CETH = 0x4Ddc2D193948926D02f9B1fE9e1daa0718270ED5; address public constant WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; address public constant WSTETH = 0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0; address public constant STETH = 0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84; address public constant CURVESINGLESWAP = 0xDC24316b9AE028F1497c275EB9192a3Ea0f67022; address public constant STETHPRICEFEED = 0xAb55Bf4DfBf469ebfe082b7872557D1F87692Fe6; // On 2022.02.28, a swap from 100k stETH ($250m+ worth) to ETH was quoted // by https://curve.fi/steth to incur 0.39% slippage, so we went with 0.5% // to capture practically all unwrap/wrap sizes through the Sense adapter." uint256 public constant SLIPPAGE_TOLERANCE = 0.005e18; /// @notice Cached scale value from the last call to `scale()` uint256 public override scaleStored; constructor( address _divider, address _oracle, uint256 _ifee, address _stake, uint256 _stakeSize, uint256 _minm, uint256 _maxm, uint16 _mode, uint64 _tilt ) BaseAdapter(_divider, WSTETH, WETH, _oracle, _ifee, _stake, _stakeSize, _minm, _maxm, _mode, _tilt, 31) { // approve wstETH contract to pull stETH (used on wrapUnderlying()) ERC20(STETH).approve(WSTETH, type(uint256).max); // approve Curve stETH/ETH pool to pull stETH (used on unwrapTarget()) ERC20(STETH).approve(CURVESINGLESWAP, type(uint256).max); // set an inital cached scale value scaleStored = _wstEthToEthRate(); } /// @return exRate Eth per wstEtH (natively in 18 decimals) function scale() external virtual override returns (uint256 exRate) { exRate = _wstEthToEthRate(); if (exRate != scaleStored) { // update value only if different than the previous scaleStored = exRate; } } function getUnderlyingPrice() external pure override returns (uint256 price) { price = 1e18; } function unwrapTarget(uint256 amount) external override returns (uint256 eth) { ERC20(WSTETH).safeTransferFrom(msg.sender, address(this), amount); // pull wstETH uint256 stEth = WstETHLike(WSTETH).unwrap(amount); // unwrap wstETH into stETH // exchange stETH to ETH exchange on Curve // to calculate the minDy, we use Lido's safe_price_value() which should prevent from flash loan / sandwhich attacks // and we are also adding a slippage tolerance of 0.5% uint256 stEthEth = StEthPriceFeedLike(STETHPRICEFEED).safe_price_value(); // returns the cached stETH/ETH safe price eth = CurveStableSwapLike(CURVESINGLESWAP).exchange( int128(1), int128(0), stEth, stEthEth.fmul(stEth).fmul(FixedMath.WAD - SLIPPAGE_TOLERANCE) ); // deposit ETH into WETH contract (bool success, ) = WETH.call{ value: eth }(""); if (!success) revert Errors.TransferFailed(); ERC20(WETH).safeTransfer(msg.sender, eth); // transfer WETH back to sender (periphery) } function wrapUnderlying(uint256 amount) external override returns (uint256 wstETH) { ERC20(WETH).safeTransferFrom(msg.sender, address(this), amount); // pull WETH WETHLike(WETH).withdraw(amount); // unwrap WETH into ETH StETHLike(STETH).submit{ value: amount }(address(0)); // stake ETH (returns wstETH) uint256 stEth = StETHLike(STETH).balanceOf(address(this)); ERC20(WSTETH).safeTransfer(msg.sender, wstETH = WstETHLike(WSTETH).wrap(stEth)); // transfer wstETH to msg.sender } function _wstEthToEthRate() internal view returns (uint256 exRate) { // In order to account for the stETH/ETH CurveStableSwap rate, // we use `safe_price_value` from Lido's stETH price feed. // https://docs.lido.fi/contracts/steth-price-feed#steth-price-feed-specification uint256 stEthEth = StEthPriceFeedLike(STETHPRICEFEED).safe_price_value(); // returns the cached stETH/ETH safe price uint256 wstETHstETH = StETHLike(STETH).getPooledEthByShares(1 ether); // stETH tokens per one wstETH exRate = stEthEth.fmul(wstETHstETH); } fallback() external payable { if (msg.sender != WETH && msg.sender != CURVESINGLESWAP) revert Errors.SenderNotEligible(); } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity 0.8.11; /// @title Fixed point arithmetic library /// @author Taken from https://github.com/Rari-Capital/solmate/blob/main/src/utils/FixedPointMathLib.sol library FixedMath { uint256 internal constant WAD = 1e18; uint256 internal constant RAY = 1e27; function fmul( uint256 x, uint256 y, uint256 baseUnit ) internal pure returns (uint256) { return mulDivDown(x, y, baseUnit); // Equivalent to (x * y) / baseUnit rounded down. } function fmul(uint256 x, uint256 y) internal pure returns (uint256) { return mulDivDown(x, y, WAD); // Equivalent to (x * y) / WAD rounded down. } function fmulUp( uint256 x, uint256 y, uint256 baseUnit ) internal pure returns (uint256) { return mulDivUp(x, y, baseUnit); // Equivalent to (x * y) / baseUnit rounded up. } function fmulUp(uint256 x, uint256 y) internal pure returns (uint256) { return mulDivUp(x, y, WAD); // Equivalent to (x * y) / WAD rounded up. } function fdiv( uint256 x, uint256 y, uint256 baseUnit ) internal pure returns (uint256) { return mulDivDown(x, baseUnit, y); // Equivalent to (x * baseUnit) / y rounded down. } function fdiv(uint256 x, uint256 y) internal pure returns (uint256) { return mulDivDown(x, WAD, y); // Equivalent to (x * WAD) / y rounded down. } function fdivUp( uint256 x, uint256 y, uint256 baseUnit ) internal pure returns (uint256) { return mulDivUp(x, baseUnit, y); // Equivalent to (x * baseUnit) / y rounded up. } function fdivUp(uint256 x, uint256 y) internal pure returns (uint256) { return mulDivUp(x, WAD, y); // Equivalent to (x * WAD) / y rounded up. } function mulDivDown( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 z) { assembly { // Store x * y in z for now. z := mul(x, y) // Equivalent to require(denominator != 0 && (x == 0 || (x * y) / x == y)) if iszero(and(iszero(iszero(denominator)), or(iszero(x), eq(div(z, x), y)))) { revert(0, 0) } // Divide z by the denominator. z := div(z, denominator) } } function mulDivUp( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 z) { assembly { // Store x * y in z for now. z := mul(x, y) // Equivalent to require(denominator != 0 && (x == 0 || (x * y) / x == y)) if iszero(and(iszero(iszero(denominator)), or(iszero(x), eq(div(z, x), y)))) { revert(0, 0) } // First, divide z - 1 by the denominator and add 1. // We allow z - 1 to underflow if z is 0, because we multiply the // end result by 0 if z is zero, ensuring we return 0 if z is zero. z := mul(iszero(iszero(z)), add(div(sub(z, 1), denominator), 1)) } } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity 0.8.11; // External references import { ERC20 } from "@rari-capital/solmate/src/tokens/ERC20.sol"; import { SafeTransferLib } from "@rari-capital/solmate/src/utils/SafeTransferLib.sol"; import { IERC3156FlashLender } from "../external/flashloan/IERC3156FlashLender.sol"; import { IERC3156FlashBorrower } from "../external/flashloan/IERC3156FlashBorrower.sol"; // Internal references import { Divider } from "../Divider.sol"; import { Errors } from "@sense-finance/v1-utils/src/libs/Errors.sol"; /// @title Assign value to Target tokens abstract contract BaseAdapter is IERC3156FlashLender { using SafeTransferLib for ERC20; /* ========== CONSTANTS ========== */ bytes32 public constant CALLBACK_SUCCESS = keccak256("ERC3156FlashBorrower.onFlashLoan"); /* ========== PUBLIC IMMUTABLES ========== */ /// @notice Sense core Divider address address public immutable divider; /// @notice Target token to divide address public immutable target; /// @notice Underlying for the Target address public immutable underlying; /// @notice Oracle address address public immutable oracle; /// @notice Token to stake at issuance address public immutable stake; /// @notice Amount to stake at issuance uint256 public immutable stakeSize; /// @notice Min maturity (seconds after block.timstamp) uint256 public immutable minm; /// @notice Max maturity (seconds after block.timstamp) uint256 public immutable maxm; /// @notice 0 for monthly, 1 for weekly uint256 public immutable mode; /// @notice Issuance fee uint256 public immutable ifee; /// @notice WAD number representing the percentage of the total /// principal that's set aside for Yield Tokens (e.g. 0.1e18 means that 10% of the principal is reserved). /// @notice If `0`, it means no principal is set aside for Yield Tokens uint256 public immutable tilt; /// @notice The number this function returns will be used to determine its access by checking for binary /// digits using the following scheme: <onRedeem(y/n)><collect(y/n)><combine(y/n)><issue(y/n)> /// (e.g. 0101 enables `collect` and `issue`, but not `combine`) uint256 public immutable level; /* ========== METADATA STORAGE ========== */ string public name; string public symbol; constructor( address _divider, address _target, address _underlying, address _oracle, uint256 _ifee, address _stake, uint256 _stakeSize, uint256 _minm, uint256 _maxm, uint256 _mode, uint256 _tilt, uint256 _level ) { // Sanity check if (_minm >= _maxm) revert Errors.InvalidMaturityOffsets(); divider = _divider; target = _target; underlying = _underlying; oracle = _oracle; ifee = _ifee; stake = _stake; stakeSize = _stakeSize; minm = _minm; maxm = _maxm; mode = _mode; tilt = _tilt; name = string(abi.encodePacked(ERC20(_target).name(), " Adapter")); symbol = string(abi.encodePacked(ERC20(_target).symbol(), "-adapter")); level = _level; ERC20(_target).approve(_divider, type(uint256).max); ERC20(_stake).approve(_divider, type(uint256).max); } /// @notice Loan `amount` target to `receiver`, and takes it back after the callback. /// @param receiver The contract receiving target, needs to implement the /// `onFlashLoan(address user, address adapter, uint256 maturity, uint256 amount)` interface. /// @param amount The amount of target lent. /// @param data (encoded adapter address, maturity and YT amount the use has sent in) function flashLoan( IERC3156FlashBorrower receiver, address, /* fee */ uint256 amount, bytes calldata data ) external returns (bool) { if (Divider(divider).periphery() != msg.sender) revert Errors.OnlyPeriphery(); ERC20(target).safeTransfer(address(receiver), amount); bytes32 keccak = IERC3156FlashBorrower(receiver).onFlashLoan(msg.sender, target, amount, 0, data); if (keccak != CALLBACK_SUCCESS) revert Errors.FlashCallbackFailed(); ERC20(target).safeTransferFrom(address(receiver), address(this), amount); return true; } /* ========== REQUIRED VALUE GETTERS ========== */ /// @notice Calculate and return this adapter's Scale value for the current timestamp. To be overriden by child contracts /// @dev For some Targets, such as cTokens, this is simply the exchange rate, or `supply cToken / supply underlying` /// @dev For other Targets, such as AMM LP shares, specialized logic will be required /// @dev This function _must_ return a WAD number representing the current exchange rate /// between the Target and the Underlying. /// @return value WAD Scale value function scale() external virtual returns (uint256); /// @notice Cached scale value getter /// @dev For situations where you need scale from a view function function scaleStored() external view virtual returns (uint256); /// @notice Returns the current price of the underlying in ETH terms function getUnderlyingPrice() external view virtual returns (uint256); /* ========== REQUIRED UTILITIES ========== */ /// @notice Deposits underlying `amount`in return for target. Must be overriden by child contracts /// @param amount Underlying amount /// @return amount of target returned function wrapUnderlying(uint256 amount) external virtual returns (uint256); /// @notice Deposits target `amount`in return for underlying. Must be overriden by child contracts /// @param amount Target amount /// @return amount of underlying returned function unwrapTarget(uint256 amount) external virtual returns (uint256); function flashFee(address token, uint256) external view returns (uint256) { if (token != target) revert Errors.TokenNotSupported(); return 0; } function maxFlashLoan(address token) external view override returns (uint256) { return ERC20(token).balanceOf(address(this)); } /* ========== OPTIONAL HOOKS ========== */ /// @notice Notification whenever the Divider adds or removes Target function notify( address, /* usr */ uint256, /* amt */ bool /* join */ ) public virtual { return; } /// @notice Hook called whenever a user redeems PT function onRedeem( uint256, /* uBal */ uint256, /* mscale */ uint256, /* maxscale */ uint256 /* tBal */ ) public virtual { return; } /* ========== PUBLIC STORAGE ACCESSORS ========== */ function getMaturityBounds() external view returns (uint256, uint256) { return (minm, maxm); } function getStakeAndTarget() external view returns ( address, address, uint256 ) { return (target, stake, stakeSize); } }
// 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/Rari-Capital/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 //////////////////////////////////////////////////////////////*/ bytes32 public constant PERMIT_TYPEHASH = keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); 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 { bytes32 digest = keccak256( abi.encodePacked( "\x19\x01", DOMAIN_SEPARATOR(), keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline)) ) ); address recoveredAddress = ecrecover(digest, v, r, s); require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER"); allowance[recoveredAddress][spender] = value; } emit Approval(owner, spender, value); } function DOMAIN_SEPARATOR() public view virtual returns (bytes32) { return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator(); } function computeDomainSeparator() internal view virtual returns (bytes32) { return keccak256( abi.encode( keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), keccak256(bytes(name)), keccak256("1"), block.chainid, address(this) ) ); } /*/////////////////////////////////////////////////////////////// INTERNAL MINT/BURN LOGIC //////////////////////////////////////////////////////////////*/ function _mint(address to, uint256 amount) internal virtual { totalSupply += amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(address(0), to, amount); } function _burn(address from, uint256 amount) internal virtual { balanceOf[from] -= amount; // Cannot underflow because a user's balance // will never be larger than the total supply. unchecked { totalSupply -= amount; } emit Transfer(from, address(0), amount); } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; import {ERC20} from "../tokens/ERC20.sol"; /// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values. /// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/utils/SafeTransferLib.sol) /// @author Modified from Gnosis (https://github.com/gnosis/gp-v2-contracts/blob/main/src/contracts/libraries/GPv2SafeERC20.sol) /// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer. library SafeTransferLib { /*/////////////////////////////////////////////////////////////// ETH OPERATIONS //////////////////////////////////////////////////////////////*/ function safeTransferETH(address to, uint256 amount) internal { bool callStatus; assembly { // Transfer the ETH and store if it succeeded or not. callStatus := call(gas(), to, amount, 0, 0, 0, 0) } require(callStatus, "ETH_TRANSFER_FAILED"); } /*/////////////////////////////////////////////////////////////// ERC20 OPERATIONS //////////////////////////////////////////////////////////////*/ function safeTransferFrom( ERC20 token, address from, address to, uint256 amount ) internal { bool callStatus; assembly { // Get a pointer to some free memory. let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata to memory piece by piece: mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000) // Begin with the function selector. mstore(add(freeMemoryPointer, 4), and(from, 0xffffffffffffffffffffffffffffffffffffffff)) // Mask and append the "from" argument. mstore(add(freeMemoryPointer, 36), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Mask and append the "to" argument. mstore(add(freeMemoryPointer, 68), amount) // Finally append the "amount" argument. No mask as it's a full 32 byte value. // Call the token and store if it succeeded or not. // We use 100 because the calldata length is 4 + 32 * 3. callStatus := call(gas(), token, 0, freeMemoryPointer, 100, 0, 0) } require(didLastOptionalReturnCallSucceed(callStatus), "TRANSFER_FROM_FAILED"); } function safeTransfer( ERC20 token, address to, uint256 amount ) internal { bool callStatus; assembly { // Get a pointer to some free memory. let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata to memory piece by piece: mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000) // Begin with the function selector. mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Mask and append the "to" argument. mstore(add(freeMemoryPointer, 36), amount) // Finally append the "amount" argument. No mask as it's a full 32 byte value. // Call the token and store if it succeeded or not. // We use 68 because the calldata length is 4 + 32 * 2. callStatus := call(gas(), token, 0, freeMemoryPointer, 68, 0, 0) } require(didLastOptionalReturnCallSucceed(callStatus), "TRANSFER_FAILED"); } function safeApprove( ERC20 token, address to, uint256 amount ) internal { bool callStatus; assembly { // Get a pointer to some free memory. let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata to memory piece by piece: mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000) // Begin with the function selector. mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Mask and append the "to" argument. mstore(add(freeMemoryPointer, 36), amount) // Finally append the "amount" argument. No mask as it's a full 32 byte value. // Call the token and store if it succeeded or not. // We use 68 because the calldata length is 4 + 32 * 2. callStatus := call(gas(), token, 0, freeMemoryPointer, 68, 0, 0) } require(didLastOptionalReturnCallSucceed(callStatus), "APPROVE_FAILED"); } /*/////////////////////////////////////////////////////////////// INTERNAL HELPER LOGIC //////////////////////////////////////////////////////////////*/ function didLastOptionalReturnCallSucceed(bool callStatus) private pure returns (bool success) { assembly { // Get how many bytes the call returned. let returnDataSize := returndatasize() // If the call reverted: if iszero(callStatus) { // Copy the revert message into memory. returndatacopy(0, 0, returnDataSize) // Revert with the same message. revert(0, returnDataSize) } switch returnDataSize case 32 { // Copy the return data into memory. returndatacopy(0, 0, returnDataSize) // Set success to whether it returned true. success := iszero(iszero(mload(0))) } case 0 { // There was no return data. success := 1 } default { // It returned some malformed input. success := 0 } } } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.4; library Errors { // Auth error CombineRestricted(); error IssuanceRestricted(); error NotAuthorized(); error OnlyYT(); error OnlyDivider(); error OnlyPeriphery(); error OnlyPermissionless(); error RedeemRestricted(); error Untrusted(); // Adapters error TokenNotSupported(); error FlashCallbackFailed(); error InvalidMaturityOffsets(); error SenderNotEligible(); error TargetMismatch(); error TargetNotSupported(); // Divider error AlreadySettled(); error CollectNotSettled(); error GuardCapReached(); error IssuanceFeeCapExceeded(); error IssueOnSettle(); error NotSettled(); // Input & validations error AlreadyInitialized(); error DuplicateSeries(); error ExistingValue(); error InvalidAdapter(); error InvalidMaturity(); error InvalidParam(); error OutOfWindowBoundaries(); error SeriesDoesNotExist(); error SwapTooSmall(); error TargetParamsNotSet(); error PoolParamsNotSet(); error PTParamsNotSet(); // Periphery error FactoryNotSupported(); error FlashBorrowFailed(); error FlashUntrustedBorrower(); error FlashUntrustedLoanInitiator(); error UnexpectedSwapAmount(); // Fuse error AdapterNotSet(); error FailedBecomeAdmin(); error FailedAddTargetMarket(); error FailedToAddPTMarket(); error FailedAddLpMarket(); error OracleNotReady(); error PoolAlreadyDeployed(); error PoolNotDeployed(); error PoolNotSet(); error SeriesNotQueued(); error TargetExists(); error TargetNotInFuse(); // Tokens error MintFailed(); error RedeemFailed(); error TransferFailed(); }
pragma solidity ^0.8.0; import "./IERC3156FlashBorrower.sol"; interface IERC3156FlashLender { /// @dev The amount of currency available to be lent. /// @param token The loan currency. /// @return The amount of `token` that can be borrowed. function maxFlashLoan(address token) external view returns (uint256); /// @dev The fee to be charged for a given loan. /// @param token The loan currency. /// @param amount The amount of tokens lent. /// @return The amount of `token` to be charged for the loan, on top of the returned principal. function flashFee(address token, uint256 amount) external view returns (uint256); /// @dev Initiate a flash loan. /// @param receiver The receiver of the tokens in the loan, and the receiver of the callback. /// @param token The loan currency. /// @param amount The amount of tokens lent. /// @param data Arbitrary data structure, intended to contain user-defined parameters. function flashLoan( IERC3156FlashBorrower receiver, address token, uint256 amount, bytes calldata data ) external returns (bool); }
pragma solidity ^0.8.0; interface IERC3156FlashBorrower { /// @dev Receive a flash loan. /// @param initiator The initiator of the loan. /// @param token The loan currency. /// @param amount The amount of tokens lent. /// @param fee The additional amount of tokens to repay. /// @param data Arbitrary data structure, intended to contain user-defined parameters. /// @return The keccak256 hash of "ERC3156FlashBorrower.onFlashLoan" function onFlashLoan( address initiator, address token, uint256 amount, uint256 fee, bytes calldata data ) external returns (bytes32); }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity 0.8.11; // External references import { Pausable } from "@openzeppelin/contracts/security/Pausable.sol"; import { ERC20 } from "@rari-capital/solmate/src/tokens/ERC20.sol"; import { SafeTransferLib } from "@rari-capital/solmate/src/utils/SafeTransferLib.sol"; import { ReentrancyGuard } from "@rari-capital/solmate/src/utils/ReentrancyGuard.sol"; import { DateTime } from "./external/DateTime.sol"; import { FixedMath } from "./external/FixedMath.sol"; // Internal references import { Errors } from "@sense-finance/v1-utils/src/libs/Errors.sol"; import { Levels } from "@sense-finance/v1-utils/src/libs/Levels.sol"; import { Trust } from "@sense-finance/v1-utils/src/Trust.sol"; import { YT } from "./tokens/YT.sol"; import { Token } from "./tokens/Token.sol"; import { BaseAdapter as Adapter } from "./adapters/BaseAdapter.sol"; /// @title Sense Divider: Divide Assets in Two /// @author fedealconada + jparklev /// @notice You can use this contract to issue, combine, and redeem Sense ERC20 Principal and Yield Tokens contract Divider is Trust, ReentrancyGuard, Pausable { using SafeTransferLib for ERC20; using FixedMath for uint256; using Levels for uint256; /* ========== PUBLIC CONSTANTS ========== */ /// @notice Buffer before and after the actual maturity in which only the sponsor can settle the Series uint256 public constant SPONSOR_WINDOW = 3 hours; /// @notice Buffer after the sponsor window in which anyone can settle the Series uint256 public constant SETTLEMENT_WINDOW = 3 hours; /// @notice 5% issuance fee cap uint256 public constant ISSUANCE_FEE_CAP = 0.05e18; /* ========== PUBLIC MUTABLE STORAGE ========== */ address public periphery; /// @notice Sense community multisig address public immutable cup; /// @notice Principal/Yield tokens deployer address public immutable tokenHandler; /// @notice Permissionless flag bool public permissionless; /// @notice Guarded launch flag bool public guarded = true; /// @notice Number of adapters (including turned off) uint248 public adapterCounter; /// @notice adapter ID -> adapter address mapping(uint256 => address) public adapterAddresses; /// @notice adapter data mapping(address => AdapterMeta) public adapterMeta; /// @notice adapter -> maturity -> Series mapping(address => mapping(uint256 => Series)) public series; /// @notice adapter -> maturity -> user -> lscale (last scale) mapping(address => mapping(uint256 => mapping(address => uint256))) public lscales; /* ========== DATA STRUCTURES ========== */ struct Series { // Principal ERC20 token address pt; // Timestamp of series initialization uint48 issuance; // Yield ERC20 token address yt; // % of underlying principal initially reserved for Yield uint96 tilt; // Actor who initialized the Series address sponsor; // Tracks fees due to the series' settler uint256 reward; // Scale at issuance uint256 iscale; // Scale at maturity uint256 mscale; // Max scale value from this series' lifetime uint256 maxscale; } struct AdapterMeta { // Adapter ID uint248 id; // Adapter enabled/disabled bool enabled; // Max amount of Target allowed to be issued uint256 guard; // Adapter level uint248 level; } constructor(address _cup, address _tokenHandler) Trust(msg.sender) { cup = _cup; tokenHandler = _tokenHandler; } /* ========== MUTATIVE FUNCTIONS ========== */ /// @notice Enable an adapter /// @dev when permissionless is disabled, only the Periphery can onboard adapters /// @dev after permissionless is enabled, anyone can onboard adapters /// @param adapter Adapter's address function addAdapter(address adapter) external whenNotPaused { if (!permissionless && msg.sender != periphery) revert Errors.OnlyPermissionless(); if (adapterMeta[adapter].id > 0 && !adapterMeta[adapter].enabled) revert Errors.InvalidAdapter(); _setAdapter(adapter, true); } /// @notice Initializes a new Series /// @dev Deploys two ERC20 contracts, one for PTs and the other one for YTs /// @dev Transfers some fixed amount of stake asset to this contract /// @param adapter Adapter to associate with the Series /// @param maturity Maturity date for the new Series, in units of unix time /// @param sponsor Sponsor of the Series that puts up a token stake and receives the issuance fees function initSeries( address adapter, uint256 maturity, address sponsor ) external nonReentrant whenNotPaused returns (address pt, address yt) { if (periphery != msg.sender) revert Errors.OnlyPeriphery(); if (!adapterMeta[adapter].enabled) revert Errors.InvalidAdapter(); if (_exists(adapter, maturity)) revert Errors.DuplicateSeries(); if (!_isValid(adapter, maturity)) revert Errors.InvalidMaturity(); // Transfer stake asset stake from caller to adapter (address target, address stake, uint256 stakeSize) = Adapter(adapter).getStakeAndTarget(); // Deploy Principal & Yield Tokens for this new Series (pt, yt) = TokenHandler(tokenHandler).deploy(adapter, adapterMeta[adapter].id, maturity); // Initialize the new Series struct uint256 scale = Adapter(adapter).scale(); series[adapter][maturity].pt = pt; series[adapter][maturity].issuance = uint48(block.timestamp); series[adapter][maturity].yt = yt; series[adapter][maturity].tilt = uint96(Adapter(adapter).tilt()); series[adapter][maturity].sponsor = sponsor; series[adapter][maturity].iscale = scale; series[adapter][maturity].maxscale = scale; ERC20(stake).safeTransferFrom(msg.sender, adapter, stakeSize); emit SeriesInitialized(adapter, maturity, pt, yt, sponsor, target); } /// @notice Settles a Series and transfers the settlement reward to the caller /// @dev The Series' sponsor has a grace period where only they can settle the Series /// @dev After that, the reward becomes MEV /// @param adapter Adapter to associate with the Series /// @param maturity Maturity date for the new Series function settleSeries(address adapter, uint256 maturity) external nonReentrant whenNotPaused { if (!adapterMeta[adapter].enabled) revert Errors.InvalidAdapter(); if (!_exists(adapter, maturity)) revert Errors.SeriesDoesNotExist(); if (_settled(adapter, maturity)) revert Errors.AlreadySettled(); if (!_canBeSettled(adapter, maturity)) revert Errors.OutOfWindowBoundaries(); // The maturity scale value is all a Series needs for us to consider it "settled" uint256 mscale = Adapter(adapter).scale(); series[adapter][maturity].mscale = mscale; if (mscale > series[adapter][maturity].maxscale) { series[adapter][maturity].maxscale = mscale; } // Reward the caller for doing the work of settling the Series at around the correct time (address target, address stake, uint256 stakeSize) = Adapter(adapter).getStakeAndTarget(); ERC20(target).safeTransferFrom(adapter, msg.sender, series[adapter][maturity].reward); ERC20(stake).safeTransferFrom(adapter, msg.sender, stakeSize); emit SeriesSettled(adapter, maturity, msg.sender); } /// @notice Mint Principal & Yield Tokens of a specific Series /// @param adapter Adapter address for the Series /// @param maturity Maturity date for the Series [unix time] /// @param tBal Balance of Target to deposit /// @dev The balance of PTs and YTs minted will be the same value in units of underlying (less fees) function issue( address adapter, uint256 maturity, uint256 tBal ) external nonReentrant whenNotPaused returns (uint256 uBal) { if (!adapterMeta[adapter].enabled) revert Errors.InvalidAdapter(); if (!_exists(adapter, maturity)) revert Errors.SeriesDoesNotExist(); if (_settled(adapter, maturity)) revert Errors.IssueOnSettle(); uint256 level = adapterMeta[adapter].level; if (level.issueRestricted() && msg.sender != adapter) revert Errors.IssuanceRestricted(); ERC20 target = ERC20(Adapter(adapter).target()); // Take the issuance fee out of the deposited Target, and put it towards the settlement reward uint256 issuanceFee = Adapter(adapter).ifee(); if (issuanceFee > ISSUANCE_FEE_CAP) revert Errors.IssuanceFeeCapExceeded(); uint256 fee = tBal.fmul(issuanceFee); unchecked { // Safety: bounded by the Target's total token supply series[adapter][maturity].reward += fee; } uint256 tBalSubFee = tBal - fee; // Ensure the caller won't hit the issuance cap with this action unchecked { // Safety: bounded by the Target's total token supply if (guarded && target.balanceOf(adapter) + tBal > adapterMeta[address(adapter)].guard) revert Errors.GuardCapReached(); } // Update values on adapter Adapter(adapter).notify(msg.sender, tBalSubFee, true); uint256 scale = level.collectDisabled() ? series[adapter][maturity].iscale : Adapter(adapter).scale(); // Determine the amount of Underlying equal to the Target being sent in (the principal) uBal = tBalSubFee.fmul(scale); // If the caller has not collected on YT before, use the current scale, otherwise // use the harmonic mean of the last and the current scale value lscales[adapter][maturity][msg.sender] = lscales[adapter][maturity][msg.sender] == 0 ? scale : _reweightLScale( adapter, maturity, YT(series[adapter][maturity].yt).balanceOf(msg.sender), uBal, msg.sender, scale ); // Mint equal amounts of PT and YT Token(series[adapter][maturity].pt).mint(msg.sender, uBal); YT(series[adapter][maturity].yt).mint(msg.sender, uBal); target.safeTransferFrom(msg.sender, adapter, tBal); emit Issued(adapter, maturity, uBal, msg.sender); } /// @notice Reconstitute Target by burning PT and YT /// @dev Explicitly burns YTs before maturity, and implicitly does it at/after maturity through `_collect()` /// @param adapter Adapter address for the Series /// @param maturity Maturity date for the Series /// @param uBal Balance of PT and YT to burn function combine( address adapter, uint256 maturity, uint256 uBal ) external nonReentrant whenNotPaused returns (uint256 tBal) { if (!adapterMeta[adapter].enabled) revert Errors.InvalidAdapter(); if (!_exists(adapter, maturity)) revert Errors.SeriesDoesNotExist(); uint256 level = adapterMeta[adapter].level; if (level.combineRestricted() && msg.sender != adapter) revert Errors.CombineRestricted(); // Burn the PT Token(series[adapter][maturity].pt).burn(msg.sender, uBal); // Collect whatever excess is due uint256 collected = _collect(msg.sender, adapter, maturity, uBal, uBal, address(0)); uint256 cscale = series[adapter][maturity].mscale; bool settled = _settled(adapter, maturity); if (!settled) { // If it's not settled, then YT won't be burned automatically in `_collect()` YT(series[adapter][maturity].yt).burn(msg.sender, uBal); // If collect has been restricted, use the initial scale, otherwise use the current scale cscale = level.collectDisabled() ? series[adapter][maturity].iscale : lscales[adapter][maturity][msg.sender]; } // Convert from units of Underlying to units of Target tBal = uBal.fdiv(cscale); ERC20(Adapter(adapter).target()).safeTransferFrom(adapter, msg.sender, tBal); // Notify only when Series is not settled as when it is, the _collect() call above would trigger a _redeemYT which will call notify if (!settled) Adapter(adapter).notify(msg.sender, tBal, false); unchecked { // Safety: bounded by the Target's total token supply tBal += collected; } emit Combined(adapter, maturity, tBal, msg.sender); } /// @notice Burn PT of a Series once it's been settled /// @dev The balance of redeemable Target is a function of the change in Scale /// @param adapter Adapter address for the Series /// @param maturity Maturity date for the Series /// @param uBal Amount of PT to burn, which should be equivalent to the amount of Underlying owed to the caller function redeem( address adapter, uint256 maturity, uint256 uBal ) external nonReentrant whenNotPaused returns (uint256 tBal) { // If a Series is settled, we know that it must have existed as well, so that check is unnecessary if (!_settled(adapter, maturity)) revert Errors.NotSettled(); uint256 level = adapterMeta[adapter].level; if (level.redeemRestricted() && msg.sender == adapter) revert Errors.RedeemRestricted(); // Burn the caller's PT Token(series[adapter][maturity].pt).burn(msg.sender, uBal); // Principal Token holder's share of the principal = (1 - part of the principal that belongs to Yield) uint256 zShare = FixedMath.WAD - series[adapter][maturity].tilt; // If Principal Token are at a loss and Yield have some principal to help cover the shortfall, // take what we can from Yield Token's principal if (series[adapter][maturity].mscale.fdiv(series[adapter][maturity].maxscale) >= zShare) { tBal = (uBal * zShare) / series[adapter][maturity].mscale; } else { tBal = uBal.fdiv(series[adapter][maturity].maxscale); } if (!level.redeemHookDisabled()) { Adapter(adapter).onRedeem(uBal, series[adapter][maturity].mscale, series[adapter][maturity].maxscale, tBal); } ERC20(Adapter(adapter).target()).safeTransferFrom(adapter, msg.sender, tBal); emit PTRedeemed(adapter, maturity, tBal); } function collect( address usr, address adapter, uint256 maturity, uint256 uBalTransfer, address to ) external nonReentrant onlyYT(adapter, maturity) whenNotPaused returns (uint256 collected) { uint256 uBal = YT(msg.sender).balanceOf(usr); return _collect(usr, adapter, maturity, uBal, uBalTransfer > 0 ? uBalTransfer : uBal, to); } /// @notice Collect YT excess before, at, or after maturity /// @dev If `to` is set, we copy the lscale value from usr to this address /// @param usr User who's collecting for their YTs /// @param adapter Adapter address for the Series /// @param maturity Maturity date for the Series /// @param uBal yield Token balance /// @param uBalTransfer original transfer value /// @param to address to set the lscale value from usr function _collect( address usr, address adapter, uint256 maturity, uint256 uBal, uint256 uBalTransfer, address to ) internal returns (uint256 collected) { if (!_exists(adapter, maturity)) revert Errors.SeriesDoesNotExist(); // If the adapter is disabled, its Yield Token can only collect // if associated Series has been settled, which implies that an admin // has backfilled it if (!adapterMeta[adapter].enabled && !_settled(adapter, maturity)) revert Errors.InvalidAdapter(); Series memory _series = series[adapter][maturity]; // Get the scale value from the last time this holder collected (default to maturity) uint256 lscale = lscales[adapter][maturity][usr]; uint256 level = adapterMeta[adapter].level; if (level.collectDisabled()) { // If this Series has been settled, we ensure everyone's YT will // collect yield accrued since issuance if (_settled(adapter, maturity)) { lscale = series[adapter][maturity].iscale; // If the Series is not settled, we ensure no collections can happen } else { return 0; } } // If the Series has been settled, this should be their last collect, so redeem the user's Yield Tokens for them if (_settled(adapter, maturity)) { _redeemYT(usr, adapter, maturity, uBal); } else { // If we're not settled and we're past maturity + the sponsor window, // anyone can settle this Series so revert until someone does if (block.timestamp > maturity + SPONSOR_WINDOW) { revert Errors.CollectNotSettled(); // Otherwise, this is a valid pre-settlement collect and we need to determine the scale value } else { uint256 cscale = Adapter(adapter).scale(); // If this is larger than the largest scale we've seen for this Series, use it if (cscale > _series.maxscale) { _series.maxscale = cscale; lscales[adapter][maturity][usr] = cscale; // If not, use the previously noted max scale value } else { lscales[adapter][maturity][usr] = _series.maxscale; } } } // Determine how much underlying has accrued since the last time this user collected, in units of Target. // (Or take the last time as issuance if they haven't yet) // // Reminder: `Underlying / Scale = Target` // So the following equation is saying, for some amount of Underlying `u`: // "Balance of Target that equaled `u` at the last collection _minus_ Target that equals `u` now" // // Because maxscale must be increasing, the Target balance needed to equal `u` decreases, and that "excess" // is what Yield holders are collecting uint256 tBalNow = uBal.fdivUp(_series.maxscale); // preventive round-up towards the protocol uint256 tBalPrev = uBal.fdiv(lscale); unchecked { collected = tBalPrev > tBalNow ? tBalPrev - tBalNow : 0; } ERC20(Adapter(adapter).target()).safeTransferFrom(adapter, usr, collected); Adapter(adapter).notify(usr, collected, false); // Distribute reward tokens // If this collect is a part of a token transfer to another address, set the receiver's // last collection to a synthetic scale weighted based on the scale on their last collect, // the time elapsed, and the current scale if (to != address(0)) { uint256 ytBal = YT(_series.yt).balanceOf(to); // If receiver holds yields, we set lscale to a computed "synthetic" lscales value that, // for the updated yield balance, still assigns the correct amount of yield. lscales[adapter][maturity][to] = ytBal > 0 ? _reweightLScale(adapter, maturity, ytBal, uBalTransfer, to, _series.maxscale) : _series.maxscale; uint256 tBalTransfer = uBalTransfer.fdiv(_series.maxscale); Adapter(adapter).notify(usr, tBalTransfer, false); Adapter(adapter).notify(to, tBalTransfer, true); } series[adapter][maturity] = _series; emit Collected(adapter, maturity, collected); } /// @notice calculate the harmonic mean of the current scale and the last scale, /// weighted by amounts associated with each function _reweightLScale( address adapter, uint256 maturity, uint256 ytBal, uint256 uBal, address receiver, uint256 scale ) internal view returns (uint256) { // Target Decimals * 18 Decimals [from fdiv] / (Target Decimals * 18 Decimals [from fdiv] / 18 Decimals) // = 18 Decimals, which is the standard for scale values return (ytBal + uBal).fdiv((ytBal.fdiv(lscales[adapter][maturity][receiver]) + uBal.fdiv(scale))); } function _redeemYT( address usr, address adapter, uint256 maturity, uint256 uBal ) internal { // Burn the users's YTs YT(series[adapter][maturity].yt).burn(usr, uBal); // Default principal for a YT uint256 tBal = 0; // Principal Token holder's share of the principal = (1 - part of the principal that belongs to Yield Tokens) uint256 zShare = FixedMath.WAD - series[adapter][maturity].tilt; // If PTs are at a loss and YTs had their principal cut to help cover the shortfall, // calculate how much YTs have left if (series[adapter][maturity].mscale.fdiv(series[adapter][maturity].maxscale) >= zShare) { tBal = uBal.fdiv(series[adapter][maturity].maxscale) - (uBal * zShare) / series[adapter][maturity].mscale; ERC20(Adapter(adapter).target()).safeTransferFrom(adapter, usr, tBal); } // Always notify the Adapter of the full Target balance that will no longer // have its rewards distributed Adapter(adapter).notify(usr, uBal.fdivUp(series[adapter][maturity].maxscale), false); emit YTRedeemed(adapter, maturity, tBal); } /* ========== ADMIN ========== */ /// @notice Enable or disable a adapter /// @param adapter Adapter's address /// @param isOn Flag setting this adapter to enabled or disabled function setAdapter(address adapter, bool isOn) public requiresTrust { _setAdapter(adapter, isOn); } /// @notice Set adapter's guard /// @param adapter Adapter address /// @param cap The max target that can be deposited on the Adapter function setGuard(address adapter, uint256 cap) external requiresTrust { adapterMeta[adapter].guard = cap; emit GuardChanged(adapter, cap); } /// @notice Set guarded mode /// @param _guarded bool function setGuarded(bool _guarded) external requiresTrust { guarded = _guarded; emit GuardedChanged(_guarded); } /// @notice Set periphery's contract /// @param _periphery Target address function setPeriphery(address _periphery) external requiresTrust { periphery = _periphery; emit PeripheryChanged(_periphery); } /// @notice Set paused flag /// @param _paused boolean function setPaused(bool _paused) external requiresTrust { _paused ? _pause() : _unpause(); } /// @notice Set permissioless mode /// @param _permissionless bool function setPermissionless(bool _permissionless) external requiresTrust { permissionless = _permissionless; emit PermissionlessChanged(_permissionless); } /// @notice Backfill a Series' Scale value at maturity if keepers failed to settle it /// @param adapter Adapter's address /// @param maturity Maturity date for the Series /// @param mscale Value to set as the Series' Scale value at maturity /// @param _usrs Values to set on lscales mapping /// @param _lscales Values to set on lscales mapping function backfillScale( address adapter, uint256 maturity, uint256 mscale, address[] calldata _usrs, uint256[] calldata _lscales ) external requiresTrust { if (!_exists(adapter, maturity)) revert Errors.SeriesDoesNotExist(); uint256 cutoff = maturity + SPONSOR_WINDOW + SETTLEMENT_WINDOW; // Admin can never backfill before maturity if (block.timestamp <= cutoff) revert Errors.OutOfWindowBoundaries(); // Set user's last scale values the Series (needed for the `collect` method) for (uint256 i = 0; i < _usrs.length; i++) { lscales[adapter][maturity][_usrs[i]] = _lscales[i]; } if (mscale > 0) { Series memory _series = series[adapter][maturity]; // Set the maturity scale for the Series (needed for `redeem` methods) series[adapter][maturity].mscale = mscale; if (mscale > _series.maxscale) { series[adapter][maturity].maxscale = mscale; } (address target, address stake, uint256 stakeSize) = Adapter(adapter).getStakeAndTarget(); address stakeDst = adapterMeta[adapter].enabled ? cup : _series.sponsor; ERC20(target).safeTransferFrom(adapter, cup, _series.reward); series[adapter][maturity].reward = 0; ERC20(stake).safeTransferFrom(adapter, stakeDst, stakeSize); } emit Backfilled(adapter, maturity, mscale, _usrs, _lscales); } /* ========== INTERNAL VIEWS ========== */ function _exists(address adapter, uint256 maturity) internal view returns (bool) { return series[adapter][maturity].pt != address(0); } function _settled(address adapter, uint256 maturity) internal view returns (bool) { return series[adapter][maturity].mscale > 0; } function _canBeSettled(address adapter, uint256 maturity) internal view returns (bool) { uint256 cutoff = maturity + SPONSOR_WINDOW + SETTLEMENT_WINDOW; // If the sender is the sponsor for the Series if (msg.sender == series[adapter][maturity].sponsor) { return maturity - SPONSOR_WINDOW <= block.timestamp && cutoff >= block.timestamp; } else { return maturity + SPONSOR_WINDOW < block.timestamp && cutoff >= block.timestamp; } } function _isValid(address adapter, uint256 maturity) internal view returns (bool) { (uint256 minm, uint256 maxm) = Adapter(adapter).getMaturityBounds(); if (maturity < block.timestamp + minm || maturity > block.timestamp + maxm) return false; (, , uint256 day, uint256 hour, uint256 minute, uint256 second) = DateTime.timestampToDateTime(maturity); if (hour != 0 || minute != 0 || second != 0) return false; uint256 mode = Adapter(adapter).mode(); if (mode == 0) { return day == 1; } if (mode == 1) { return DateTime.getDayOfWeek(maturity) == 1; } return false; } /* ========== INTERNAL UTILS ========== */ function _setAdapter(address adapter, bool isOn) internal { AdapterMeta memory am = adapterMeta[adapter]; if (am.enabled == isOn) revert Errors.ExistingValue(); am.enabled = isOn; // If this adapter is being added for the first time if (isOn && am.id == 0) { am.id = ++adapterCounter; adapterAddresses[am.id] = adapter; } // Set level and target (can only be done once); am.level = uint248(Adapter(adapter).level()); adapterMeta[adapter] = am; emit AdapterChanged(adapter, am.id, isOn); } /* ========== PUBLIC GETTERS ========== */ /// @notice Returns address of Principal Token function pt(address adapter, uint256 maturity) public view returns (address) { return series[adapter][maturity].pt; } /// @notice Returns address of Yield Token function yt(address adapter, uint256 maturity) public view returns (address) { return series[adapter][maturity].yt; } function mscale(address adapter, uint256 maturity) public view returns (uint256) { return series[adapter][maturity].mscale; } /* ========== MODIFIERS ========== */ modifier onlyYT(address adapter, uint256 maturity) { if (series[adapter][maturity].yt != msg.sender) revert Errors.OnlyYT(); _; } /* ========== LOGS ========== */ /// @notice Admin event Backfilled( address indexed adapter, uint256 indexed maturity, uint256 mscale, address[] _usrs, uint256[] _lscales ); event GuardChanged(address indexed adapter, uint256 cap); event AdapterChanged(address indexed adapter, uint256 indexed id, bool indexed isOn); event PeripheryChanged(address indexed periphery); /// @notice Series lifecycle /// *---- beginning event SeriesInitialized( address adapter, uint256 indexed maturity, address pt, address yt, address indexed sponsor, address indexed target ); /// -***- middle event Issued(address indexed adapter, uint256 indexed maturity, uint256 balance, address indexed sender); event Combined(address indexed adapter, uint256 indexed maturity, uint256 balance, address indexed sender); event Collected(address indexed adapter, uint256 indexed maturity, uint256 collected); /// ----* end event SeriesSettled(address indexed adapter, uint256 indexed maturity, address indexed settler); event PTRedeemed(address indexed adapter, uint256 indexed maturity, uint256 redeemed); event YTRedeemed(address indexed adapter, uint256 indexed maturity, uint256 redeemed); /// *----* misc event GuardedChanged(bool indexed guarded); event PermissionlessChanged(bool indexed permissionless); } contract TokenHandler is Trust { /// @notice Program state address public divider; constructor() Trust(msg.sender) {} function init(address _divider) external requiresTrust { if (divider != address(0)) revert Errors.AlreadyInitialized(); divider = _divider; } function deploy( address adapter, uint248 id, uint256 maturity ) external returns (address pt, address yt) { if (msg.sender != divider) revert Errors.OnlyDivider(); ERC20 target = ERC20(Adapter(adapter).target()); uint8 decimals = target.decimals(); string memory symbol = target.symbol(); (string memory d, string memory m, string memory y) = DateTime.toDateString(maturity); string memory date = DateTime.format(maturity); string memory datestring = string(abi.encodePacked(d, "-", m, "-", y)); string memory adapterId = DateTime.uintToString(id); pt = address( new Token( string(abi.encodePacked(date, " ", symbol, " Sense Principal Token, A", adapterId)), string(abi.encodePacked("sP-", symbol, ":", datestring, ":", adapterId)), decimals, divider ) ); yt = address( new YT( adapter, maturity, string(abi.encodePacked(date, " ", symbol, " Sense Yield Token, A", adapterId)), string(abi.encodePacked("sY-", symbol, ":", datestring, ":", adapterId)), decimals, divider ) ); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../utils/Context.sol"; /** * @dev Contract module which allows children to implement an emergency stop * mechanism that can be triggered by an authorized account. * * This module is used through inheritance. It will make available the * modifiers `whenNotPaused` and `whenPaused`, which can be applied to * the functions of your contract. Note that they will not be pausable by * simply including this module, only once the modifiers are put in place. */ abstract contract Pausable is Context { /** * @dev Emitted when the pause is triggered by `account`. */ event Paused(address account); /** * @dev Emitted when the pause is lifted by `account`. */ event Unpaused(address account); bool private _paused; /** * @dev Initializes the contract in unpaused state. */ constructor() { _paused = false; } /** * @dev Returns true if the contract is paused, and false otherwise. */ function paused() public view virtual returns (bool) { return _paused; } /** * @dev Modifier to make a function callable only when the contract is not paused. * * Requirements: * * - The contract must not be paused. */ modifier whenNotPaused() { require(!paused(), "Pausable: paused"); _; } /** * @dev Modifier to make a function callable only when the contract is paused. * * Requirements: * * - The contract must be paused. */ modifier whenPaused() { require(paused(), "Pausable: not paused"); _; } /** * @dev Triggers stopped state. * * Requirements: * * - The contract must not be paused. */ function _pause() internal virtual whenNotPaused { _paused = true; emit Paused(_msgSender()); } /** * @dev Returns to normal state. * * Requirements: * * - The contract must be paused. */ function _unpause() internal virtual whenPaused { _paused = false; emit Unpaused(_msgSender()); } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; /// @notice Gas optimized reentrancy protection for smart contracts. /// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/utils/ReentrancyGuard.sol) /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/security/ReentrancyGuard.sol) abstract contract ReentrancyGuard { uint256 private reentrancyStatus = 1; modifier nonReentrant() { require(reentrancyStatus == 1, "REENTRANCY"); reentrancyStatus = 2; _; reentrancyStatus = 1; } }
pragma solidity 0.8.11; /// @author Taken from: https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary library DateTime { uint256 constant SECONDS_PER_DAY = 24 * 60 * 60; uint256 constant SECONDS_PER_HOUR = 60 * 60; uint256 constant SECONDS_PER_MINUTE = 60; int256 constant OFFSET19700101 = 2440588; function timestampToDate(uint256 timestamp) internal pure returns ( uint256 year, uint256 month, uint256 day ) { (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY); } function timestampToDateTime(uint256 timestamp) internal pure returns ( uint256 year, uint256 month, uint256 day, uint256 hour, uint256 minute, uint256 second ) { (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY); uint256 secs = timestamp % SECONDS_PER_DAY; hour = secs / SECONDS_PER_HOUR; secs = secs % SECONDS_PER_HOUR; minute = secs / SECONDS_PER_MINUTE; second = secs % SECONDS_PER_MINUTE; } function toDateString(uint256 _timestamp) internal pure returns ( string memory d, string memory m, string memory y ) { (uint256 year, uint256 month, uint256 day) = timestampToDate(_timestamp); d = uintToString(day); m = uintToString(month); y = uintToString(year); // append a 0 to numbers < 10 so we should, e.g, 01 instead of just 1 if (day < 10) d = string(abi.encodePacked("0", d)); if (month < 10) m = string(abi.encodePacked("0", m)); } function format(uint256 _timestamp) internal pure returns (string memory datestring) { string[12] memory months = [ "Jan", "Feb", "Mar", "Apr", "May", "June", "July", "Aug", "Sept", "Oct", "Nov", "Dec" ]; (uint256 year, uint256 month, uint256 day) = timestampToDate(_timestamp); uint256 last = day % 10; string memory suffix = "th"; if (day < 11 || day > 20) { if (last == 1) suffix = "st"; if (last == 2) suffix = "nd"; if (last == 3) suffix = "rd"; } return string(abi.encodePacked(uintToString(day), suffix, " ", months[month - 1], " ", uintToString(year))); } function getDayOfWeek(uint256 timestamp) internal pure returns (uint256 dayOfWeek) { uint256 _days = timestamp / SECONDS_PER_DAY; dayOfWeek = ((_days + 3) % 7) + 1; } /// Taken from https://stackoverflow.com/questions/47129173/how-to-convert-uint-to-string-in-solidity function uintToString(uint256 _i) internal pure returns (string memory _uintAsString) { if (_i == 0) return "0"; uint256 j = _i; uint256 len; while (j != 0) { len++; j /= 10; } bytes memory bstr = new bytes(len); uint256 k = len; while (_i != 0) { k = k - 1; uint8 temp = (48 + uint8(_i - (_i / 10) * 10)); bytes1 b1 = bytes1(temp); bstr[k] = b1; _i /= 10; } return string(bstr); } // ------------------------------------------------------------------------ // Calculate the number of days from 1970/01/01 to year/month/day using // the date conversion algorithm from // http://aa.usno.navy.mil/faq/docs/JD_Formula.php // and subtracting the offset 2440588 so that 1970/01/01 is day 0 // // days = day // - 32075 // + 1461 * (year + 4800 + (month - 14) / 12) / 4 // + 367 * (month - 2 - (month - 14) / 12 * 12) / 12 // - 3 * ((year + 4900 + (month - 14) / 12) / 100) / 4 // - offset // ------------------------------------------------------------------------ function _daysFromDate( uint256 year, uint256 month, uint256 day ) internal pure returns (uint256 _days) { require(year >= 1970); int256 _year = int256(year); int256 _month = int256(month); int256 _day = int256(day); int256 __days = _day - 32075 + (1461 * (_year + 4800 + (_month - 14) / 12)) / 4 + (367 * (_month - 2 - ((_month - 14) / 12) * 12)) / 12 - (3 * ((_year + 4900 + (_month - 14) / 12) / 100)) / 4 - OFFSET19700101; _days = uint256(__days); } // ------------------------------------------------------------------------ // Calculate year/month/day from the number of days since 1970/01/01 using // the date conversion algorithm from // http://aa.usno.navy.mil/faq/docs/JD_Formula.php // and adding the offset 2440588 so that 1970/01/01 is day 0 // // int L = days + 68569 + offset // int N = 4 * L / 146097 // L = L - (146097 * N + 3) / 4 // year = 4000 * (L + 1) / 1461001 // L = L - 1461 * year / 4 + 31 // month = 80 * L / 2447 // dd = L - 2447 * month / 80 // L = month / 11 // month = month + 2 - 12 * L // year = 100 * (N - 49) + year + L // ------------------------------------------------------------------------ function _daysToDate(uint256 _days) internal pure returns ( uint256 year, uint256 month, uint256 day ) { int256 __days = int256(_days); int256 L = __days + 68569 + OFFSET19700101; int256 N = (4 * L) / 146097; L = L - (146097 * N + 3) / 4; int256 _year = (4000 * (L + 1)) / 1461001; L = L - (1461 * _year) / 4 + 31; int256 _month = (80 * L) / 2447; int256 _day = L - (2447 * _month) / 80; L = _month / 11; _month = _month + 2 - 12 * L; _year = 100 * (N - 49) + _year + L; year = uint256(_year); month = uint256(_month); day = uint256(_day); } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.7.0; library Levels { uint256 private constant _INIT_BIT = 0x1; uint256 private constant _ISSUE_BIT = 0x2; uint256 private constant _COMBINE_BIT = 0x4; uint256 private constant _COLLECT_BIT = 0x8; uint256 private constant _REDEEM_BIT = 0x10; uint256 private constant _REDEEM_HOOK_BIT = 0x20; function initRestricted(uint256 level) internal pure returns (bool) { return level & _INIT_BIT != _INIT_BIT; } function issueRestricted(uint256 level) internal pure returns (bool) { return level & _ISSUE_BIT != _ISSUE_BIT; } function combineRestricted(uint256 level) internal pure returns (bool) { return level & _COMBINE_BIT != _COMBINE_BIT; } function collectDisabled(uint256 level) internal pure returns (bool) { return level & _COLLECT_BIT != _COLLECT_BIT; } function redeemRestricted(uint256 level) internal pure returns (bool) { return level & _REDEEM_BIT != _REDEEM_BIT; } function redeemHookDisabled(uint256 level) internal pure returns (bool) { return level & _REDEEM_HOOK_BIT != _REDEEM_HOOK_BIT; } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.7.0; /// @notice Ultra minimal authorization logic for smart contracts. /// @author From https://github.com/Rari-Capital/solmate/blob/fab107565a51674f3a3b5bfdaacc67f6179b1a9b/src/auth/Trust.sol abstract contract Trust { event UserTrustUpdated(address indexed user, bool trusted); mapping(address => bool) public isTrusted; constructor(address initialUser) { isTrusted[initialUser] = true; emit UserTrustUpdated(initialUser, true); } function setIsTrusted(address user, bool trusted) public virtual requiresTrust { isTrusted[user] = trusted; emit UserTrustUpdated(user, trusted); } modifier requiresTrust() { require(isTrusted[msg.sender], "UNTRUSTED"); _; } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity 0.8.11; // Internal references import { Divider } from "../Divider.sol"; import { Token } from "./Token.sol"; /// @title Yield Token /// @notice Strips off excess before every transfer contract YT is Token { address public immutable adapter; address public immutable divider; uint256 public immutable maturity; constructor( address _adapter, uint256 _maturity, string memory _name, string memory _symbol, uint8 _decimals, address _divider ) Token(_name, _symbol, _decimals, _divider) { adapter = _adapter; maturity = _maturity; divider = _divider; } function collect() external returns (uint256 _collected) { return Divider(divider).collect(msg.sender, adapter, maturity, 0, address(0)); } function transfer(address to, uint256 value) public override returns (bool) { Divider(divider).collect(msg.sender, adapter, maturity, value, to); return super.transfer(to, value); } function transferFrom( address from, address to, uint256 value ) public override returns (bool) { if (value > 0) Divider(divider).collect(from, adapter, maturity, value, to); return super.transferFrom(from, to, value); } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity 0.8.11; // External references import { ERC20 } from "@rari-capital/solmate/src/tokens/ERC20.sol"; // Internal references import { Trust } from "@sense-finance/v1-utils/src/Trust.sol"; /// @title Base Token contract Token is ERC20, Trust { constructor( string memory _name, string memory _symbol, uint8 _decimals, address _trusted ) ERC20(_name, _symbol, _decimals) Trust(_trusted) {} /// @param usr The address to send the minted tokens /// @param amount The amount to be minted function mint(address usr, uint256 amount) public requiresTrust { _mint(usr, amount); } /// @param usr The address from where to burn tokens from /// @param amount The amount to be burned function burn(address usr, uint256 amount) public requiresTrust { _burn(usr, amount); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
{ "optimizer": { "enabled": true, "runs": 100 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "metadata": { "useLiteralContent": true }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_divider","type":"address"},{"internalType":"address","name":"_oracle","type":"address"},{"internalType":"uint256","name":"_ifee","type":"uint256"},{"internalType":"address","name":"_stake","type":"address"},{"internalType":"uint256","name":"_stakeSize","type":"uint256"},{"internalType":"uint256","name":"_minm","type":"uint256"},{"internalType":"uint256","name":"_maxm","type":"uint256"},{"internalType":"uint16","name":"_mode","type":"uint16"},{"internalType":"uint64","name":"_tilt","type":"uint64"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"FlashCallbackFailed","type":"error"},{"inputs":[],"name":"InvalidMaturityOffsets","type":"error"},{"inputs":[],"name":"OnlyPeriphery","type":"error"},{"inputs":[],"name":"SenderNotEligible","type":"error"},{"inputs":[],"name":"TokenNotSupported","type":"error"},{"inputs":[],"name":"TransferFailed","type":"error"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"CALLBACK_SUCCESS","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CETH","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CURVESINGLESWAP","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SLIPPAGE_TOLERANCE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STETH","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STETHPRICEFEED","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WETH","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WSTETH","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"divider","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"flashFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC3156FlashBorrower","name":"receiver","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"flashLoan","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getMaturityBounds","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStakeAndTarget","outputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getUnderlyingPrice","outputs":[{"internalType":"uint256","name":"price","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"ifee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"level","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"maxFlashLoan","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxm","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minm","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mode","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bool","name":"","type":"bool"}],"name":"notify","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"onRedeem","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"oracle","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"scale","outputs":[{"internalType":"uint256","name":"exRate","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"scaleStored","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stake","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stakeSize","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"target","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tilt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"underlying","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"unwrapTarget","outputs":[{"internalType":"uint256","name":"eth","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"wrapUnderlying","outputs":[{"internalType":"uint256","name":"wstETH","type":"uint256"}],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
6102006040523480156200001257600080fd5b506040516200205038038062002050833981016040819052620000359162000698565b88737f39c581f595b53c5cb19bd0b3f8da6c935e2ca073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc28a8a8a8a8a8a8a61ffff168a6001600160401b0316601f83851062000098576040516315a68d0760e11b815260040160405180910390fd5b6001600160a01b03808d166080528b811660a08190528b821660c0528a821660e0526101a08a9052908816610100526101208790526101408690526101608590526101808490526101c0839052604080516306fdde0360e01b815290516306fdde03916004808201926000929091908290030181865afa15801562000121573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526200014b919081019062000790565b6040516020016200015d919062000848565b6040516020818303038152906040526000908051906020019062000183929190620005d5565b508a6001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015620001c3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052620001ed919081019062000790565b604051602001620001ff919062000876565b6040516020818303038152906040526001908051906020019062000225929190620005d5565b506101e081905260405163095ea7b360e01b81526001600160a01b038d8116600483015260001960248301528c169063095ea7b3906044016020604051808303816000875af11580156200027d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002a39190620008bd565b5060405163095ea7b360e01b81526001600160a01b038d81166004830152600019602483015288169063095ea7b3906044016020604051808303816000875af1158015620002f5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200031b9190620008bd565b505060405163095ea7b360e01b815273ae7ab96520de3a18e5e111b5eaab095312d7fe849b5063095ea7b39a506200037b9950737f39c581f595b53c5cb19bd0b3f8da6c935e2ca0985060001997506004019550620008a4945050505050565b6020604051808303816000875af11580156200039b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620003c19190620008bd565b5060405163095ea7b360e01b815273dc24316b9ae028f1497c275eb9192a3ea0f670226004820152600019602482015273ae7ab96520de3a18e5e111b5eaab095312d7fe849063095ea7b3906044016020604051808303816000875af115801562000430573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620004569190620008bd565b506200046162000474565b6002555062000938975050505050505050565b60008073ab55bf4dfbf469ebfe082b7872557d1f87692fe66001600160a01b03166308c80d206040518163ffffffff1660e01b8152600401602060405180830381865afa158015620004ca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620004f09190620008e1565b604051630f451f7160e31b8152670de0b6b3a7640000600482015290915060009073ae7ab96520de3a18e5e111b5eaab095312d7fe8490637a28fb8890602401602060405180830381865afa1580156200054e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620005749190620008e1565b90506200059081836200059760201b620010821790919060201c565b9250505090565b6000620005ae8383670de0b6b3a7640000620005b5565b9392505050565b828202811515841585830485141716620005ce57600080fd5b0492915050565b828054620005e390620008fb565b90600052602060002090601f01602090048101928262000607576000855562000652565b82601f106200062257805160ff191683800117855562000652565b8280016001018555821562000652579182015b828111156200065257825182559160200191906001019062000635565b506200066092915062000664565b5090565b5b8082111562000660576000815560010162000665565b80516001600160a01b03811681146200069357600080fd5b919050565b60008060008060008060008060006101208a8c031215620006b857600080fd5b620006c38a6200067b565b9850620006d360208b016200067b565b975060408a01519650620006ea60608b016200067b565b955060808a0151945060a08a0151935060c08a0151925060e08a015161ffff811681146200071757600080fd5b6101008b01519092506001600160401b03811681146200073657600080fd5b809150509295985092959850929598565b634e487b7160e01b600052604160045260246000fd5b60005b838110156200077a57818101518382015260200162000760565b838111156200078a576000848401525b50505050565b600060208284031215620007a357600080fd5b81516001600160401b0380821115620007bb57600080fd5b818401915084601f830112620007d057600080fd5b815181811115620007e557620007e562000747565b604051601f8201601f19908116603f0116810190838211818310171562000810576200081062000747565b816040528281528760208487010111156200082a57600080fd5b6200083d8360208301602088016200075d565b979650505050505050565b600082516200085c8184602087016200075d565b671020b230b83a32b960c11b920191825250600801919050565b600082516200088a8184602087016200075d565b6716b0b230b83a32b960c11b920191825250600801919050565b6001600160a01b03929092168252602082015260400190565b600060208284031215620008d057600080fd5b81518015158114620005ae57600080fd5b600060208284031215620008f457600080fd5b5051919050565b600181811c908216806200091057607f821691505b602082108114156200093257634e487b7160e01b600052602260045260246000fd5b50919050565b60805160a05160c05160e05161010051610120516101405161016051610180516101a0516101c0516101e05161164062000a10600039600061060b0152600061073801526000610704015260006103b90152600081816102a4015261059b0152600081816105780152610825015260008181610379015261042101526000818161035201526104550152600061063f015260006105d701526000818161032d0152818161076c01528181610e3d01528181610e8d01528181610f4f015261100b0152600081816103ed0152610d8901526116406000f3fe6080604052600436106101b95760003560e01c8063613255ab116100ed578063b484972a11610090578063b484972a146106d2578063b8c15a9f146106f2578063c39a3b2914610726578063d4b839921461075a578063d9d98ce41461078e578063d9fb643a146107ae578063e00bfe50146107d6578063f51e181a146107fe578063fc024d2c14610813576101b9565b8063613255ab1461054557806364c56e3c146105655780636f307dc3146105c55780636fd5ae15146105f95780637dc0d1d01461062d5780638237e5381461066157806395d89b4114610695578063ad5c4648146106aa576101b9565b8063378efa3711610160578063378efa37146103db5780633a34330e1461040f5780633a4b66f114610443578063468f02d2146104775780634aae9fed146104925780634c203786146104b257806351c39ea1146104cd5780635cffe9de146104ed578063610968201461051d576101b9565b806306fdde031461021157806314282f581461023c578063162ba7331461025d578063167c3a4f146102925780632063b5cc146102d457806322677849146102fc57806327b327d014610312578063295a5212146103a7575b3373c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2148015906101f157503373dc24316b9ae028f1497c275eb9192a3ea0f6702214155b1561020f576040516304ae33a760e31b815260040160405180910390fd5b005b34801561021d57600080fd5b50610226610847565b6040516102339190611323565b60405180910390f35b34801561024857600080fd5b5061020f610257366004611378565b50505050565b34801561026957600080fd5b5061028573dc24316b9ae028f1497c275eb9192a3ea0f6702281565b60405161023391906113aa565b34801561029e57600080fd5b506102c67f000000000000000000000000000000000000000000000000000000000000000081565b604051908152602001610233565b3480156102e057600080fd5b5061028573ab55bf4dfbf469ebfe082b7872557d1f87692fe681565b34801561030857600080fd5b506102c660025481565b34801561031e57600080fd5b50604080516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811682527f00000000000000000000000000000000000000000000000000000000000000001660208201527f000000000000000000000000000000000000000000000000000000000000000091810191909152606001610233565b3480156103b357600080fd5b506102c67f000000000000000000000000000000000000000000000000000000000000000081565b3480156103e757600080fd5b506102857f000000000000000000000000000000000000000000000000000000000000000081565b34801561041b57600080fd5b506102c67f000000000000000000000000000000000000000000000000000000000000000081565b34801561044f57600080fd5b506102857f000000000000000000000000000000000000000000000000000000000000000081565b34801561048357600080fd5b50670de0b6b3a76400006102c6565b34801561049e57600080fd5b506102c66104ad3660046113be565b6108d5565b3480156104be57600080fd5b506102c66611c37937e0800081565b3480156104d957600080fd5b506102c66104e83660046113be565b610af8565b3480156104f957600080fd5b5061050d6105083660046113ef565b610d7b565b6040519015158152602001610233565b34801561052957600080fd5b50610285734ddc2d193948926d02f9b1fe9e1daa0718270ed581565b34801561055157600080fd5b506102c661056036600461148e565b610f84565b34801561057157600080fd5b50604080517f000000000000000000000000000000000000000000000000000000000000000081527f0000000000000000000000000000000000000000000000000000000000000000602082015201610233565b3480156105d157600080fd5b506102857f000000000000000000000000000000000000000000000000000000000000000081565b34801561060557600080fd5b506102c67f000000000000000000000000000000000000000000000000000000000000000081565b34801561063957600080fd5b506102857f000000000000000000000000000000000000000000000000000000000000000081565b34801561066d57600080fd5b506102c67f439148f0bbc682ca079e46d6e2c2f0c1e3b820f1a291b069d8882abf8cf18dd981565b3480156106a157600080fd5b50610226610ffa565b3480156106b657600080fd5b5061028573c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b3480156106de57600080fd5b5061020f6106ed3660046114ab565b505050565b3480156106fe57600080fd5b506102c67f000000000000000000000000000000000000000000000000000000000000000081565b34801561073257600080fd5b506102c67f000000000000000000000000000000000000000000000000000000000000000081565b34801561076657600080fd5b506102857f000000000000000000000000000000000000000000000000000000000000000081565b34801561079a57600080fd5b506102c66107a93660046114f2565b611007565b3480156107ba57600080fd5b50610285737f39c581f595b53c5cb19bd0b3f8da6c935e2ca081565b3480156107e257600080fd5b5061028573ae7ab96520de3a18e5e111b5eaab095312d7fe8481565b34801561080a57600080fd5b506102c6611064565b34801561081f57600080fd5b506102c67f000000000000000000000000000000000000000000000000000000000000000081565b600080546108549061151e565b80601f01602080910402602001604051908101604052809291908181526020018280546108809061151e565b80156108cd5780601f106108a2576101008083540402835291602001916108cd565b820191906000526020600020905b8154815290600101906020018083116108b057829003601f168201915b505050505081565b60006108f773c02aaa39b223fe8d0a0e5c4f27ead9083c756cc233308561109e565b604051632e1a7d4d60e01b81526004810183905273c02aaa39b223fe8d0a0e5c4f27ead9083c756cc290632e1a7d4d90602401600060405180830381600087803b15801561094457600080fd5b505af1158015610958573d6000803e3d6000fd5b505060405163a1903eab60e01b815273ae7ab96520de3a18e5e111b5eaab095312d7fe84925063a1903eab91508490610996906000906004016113aa565b60206040518083038185885af11580156109b4573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906109d99190611553565b506040516370a0823160e01b815260009073ae7ab96520de3a18e5e111b5eaab095312d7fe84906370a0823190610a149030906004016113aa565b602060405180830381865afa158015610a31573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a559190611553565b604051630ea598cb60e41b815260048101829052909150610af2903390737f39c581f595b53c5cb19bd0b3f8da6c935e2ca09063ea598cb0906024016020604051808303816000875af1158015610ab0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ad49190611553565b9350737f39c581f595b53c5cb19bd0b3f8da6c935e2ca09084611137565b50919050565b6000610b1a737f39c581f595b53c5cb19bd0b3f8da6c935e2ca033308561109e565b604051636f074d1f60e11b815260048101839052600090737f39c581f595b53c5cb19bd0b3f8da6c935e2ca09063de0e9a3e906024016020604051808303816000875af1158015610b6f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b939190611553565b9050600073ab55bf4dfbf469ebfe082b7872557d1f87692fe66001600160a01b03166308c80d206040518163ffffffff1660e01b8152600401602060405180830381865afa158015610be9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c0d9190611553565b905073dc24316b9ae028f1497c275eb9192a3ea0f67022633df021246001600085610c5a610c4a6611c37937e08000670de0b6b3a764000061156c565b610c54888a611082565b90611082565b6040516001600160e01b031960e087901b168152600f94850b60048201529290930b6024830152604482015260648101919091526084016020604051808303816000875af1158015610cb0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cd49190611553565b60405190935060009073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc29085908381818185875af1925050503d8060008114610d2d576040519150601f19603f3d011682016040523d82523d6000602084013e610d32565b606091505b5050905080610d54576040516312171d8360e31b815260040160405180910390fd5b610d7373c02aaa39b223fe8d0a0e5c4f27ead9083c756cc23386611137565b505050919050565b6000336001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166377aace1a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610de5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e099190611591565b6001600160a01b031614610e305760405163fb02114960e01b815260040160405180910390fd5b610e646001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168786611137565b6040516323e30c8b60e01b81526000906001600160a01b038816906323e30c8b90610ebd9033907f0000000000000000000000000000000000000000000000000000000000000000908a9087908b908b906004016115ae565b6020604051808303816000875af1158015610edc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f009190611553565b90507f439148f0bbc682ca079e46d6e2c2f0c1e3b820f1a291b069d8882abf8cf18dd98114610f425760405163081f7c8760e21b815260040160405180910390fd5b610f776001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001688308861109e565b5060019695505050505050565b6040516370a0823160e01b81526000906001600160a01b038316906370a0823190610fb39030906004016113aa565b602060405180830381865afa158015610fd0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ff49190611553565b92915050565b600180546108549061151e565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b03161461105b57604051633dd1b30560e01b815260040160405180910390fd5b50600092915050565b600061106e6111b0565b9050600254811461107f5760028190555b90565b60006110978383670de0b6b3a76400006112bd565b9392505050565b60006040516323b872dd60e01b81526001600160a01b03851660048201526001600160a01b038416602482015282604482015260008060648360008a5af19150506110e8816112dc565b6111305760405162461bcd60e51b81526020600482015260146024820152731514905394d1915497d19493d357d1905253115160621b60448201526064015b60405180910390fd5b5050505050565b600060405163a9059cbb60e01b81526001600160a01b03841660048201528260248201526000806044836000895af1915050611172816112dc565b6102575760405162461bcd60e51b815260206004820152600f60248201526e1514905394d1915497d19052531151608a1b6044820152606401611127565b60008073ab55bf4dfbf469ebfe082b7872557d1f87692fe66001600160a01b03166308c80d206040518163ffffffff1660e01b8152600401602060405180830381865afa158015611205573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112299190611553565b604051630f451f7160e31b8152670de0b6b3a7640000600482015290915060009073ae7ab96520de3a18e5e111b5eaab095312d7fe8490637a28fb8890602401602060405180830381865afa158015611286573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112aa9190611553565b90506112b68282611082565b9250505090565b8282028115158415858304851417166112d557600080fd5b0492915050565b60003d826112ee57806000803e806000fd5b8060208114611306578015611317576000925061131c565b816000803e6000511515925061131c565b600192505b5050919050565b600060208083528351808285015260005b8181101561135057858101830151858201604001528201611334565b81811115611362576000604083870101525b50601f01601f1916929092016040019392505050565b6000806000806080858703121561138e57600080fd5b5050823594602084013594506040840135936060013592509050565b6001600160a01b0391909116815260200190565b6000602082840312156113d057600080fd5b5035919050565b6001600160a01b03811681146113ec57600080fd5b50565b60008060008060006080868803121561140757600080fd5b8535611412816113d7565b94506020860135611422816113d7565b935060408601359250606086013567ffffffffffffffff8082111561144657600080fd5b818801915088601f83011261145a57600080fd5b81358181111561146957600080fd5b89602082850101111561147b57600080fd5b9699959850939650602001949392505050565b6000602082840312156114a057600080fd5b8135611097816113d7565b6000806000606084860312156114c057600080fd5b83356114cb816113d7565b925060208401359150604084013580151581146114e757600080fd5b809150509250925092565b6000806040838503121561150557600080fd5b8235611510816113d7565b946020939093013593505050565b600181811c9082168061153257607f821691505b60208210811415610af257634e487b7160e01b600052602260045260246000fd5b60006020828403121561156557600080fd5b5051919050565b60008282101561158c57634e487b7160e01b600052601160045260246000fd5b500390565b6000602082840312156115a357600080fd5b8151611097816113d7565b6001600160a01b03878116825286166020820152604081018590526060810184905260a06080820181905281018290526000828460c0840137600060c0848401015260c0601f19601f850116830101905097965050505050505056fea2646970667358221220356b12cb6a7e0d91963482adca61ea78b392492fe3d2fc7488459f1040f5777764736f6c634300080b003300000000000000000000000086ba3e96be68563e41c2f5769f1af9faf758e6e00000000000000000000000001887118e49e0f4a78bd71b792a49de03504a764d0000000000000000000000000000000000000000000000000008e1bc9bf04000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000000000000000000000000000003782dace9d9000000000000000000000000000000000000000000000000000000000000001badf00000000000000000000000000000000000000000000000000000000001ff46dd00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x6080604052600436106101b95760003560e01c8063613255ab116100ed578063b484972a11610090578063b484972a146106d2578063b8c15a9f146106f2578063c39a3b2914610726578063d4b839921461075a578063d9d98ce41461078e578063d9fb643a146107ae578063e00bfe50146107d6578063f51e181a146107fe578063fc024d2c14610813576101b9565b8063613255ab1461054557806364c56e3c146105655780636f307dc3146105c55780636fd5ae15146105f95780637dc0d1d01461062d5780638237e5381461066157806395d89b4114610695578063ad5c4648146106aa576101b9565b8063378efa3711610160578063378efa37146103db5780633a34330e1461040f5780633a4b66f114610443578063468f02d2146104775780634aae9fed146104925780634c203786146104b257806351c39ea1146104cd5780635cffe9de146104ed578063610968201461051d576101b9565b806306fdde031461021157806314282f581461023c578063162ba7331461025d578063167c3a4f146102925780632063b5cc146102d457806322677849146102fc57806327b327d014610312578063295a5212146103a7575b3373c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2148015906101f157503373dc24316b9ae028f1497c275eb9192a3ea0f6702214155b1561020f576040516304ae33a760e31b815260040160405180910390fd5b005b34801561021d57600080fd5b50610226610847565b6040516102339190611323565b60405180910390f35b34801561024857600080fd5b5061020f610257366004611378565b50505050565b34801561026957600080fd5b5061028573dc24316b9ae028f1497c275eb9192a3ea0f6702281565b60405161023391906113aa565b34801561029e57600080fd5b506102c67f0000000000000000000000000000000000000000000000000000000001ff46dd81565b604051908152602001610233565b3480156102e057600080fd5b5061028573ab55bf4dfbf469ebfe082b7872557d1f87692fe681565b34801561030857600080fd5b506102c660025481565b34801561031e57600080fd5b50604080516001600160a01b037f0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca0811682527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21660208201527f00000000000000000000000000000000000000000000000003782dace9d9000091810191909152606001610233565b3480156103b357600080fd5b506102c67f000000000000000000000000000000000000000000000000000000000000000081565b3480156103e757600080fd5b506102857f00000000000000000000000086ba3e96be68563e41c2f5769f1af9faf758e6e081565b34801561041b57600080fd5b506102c67f00000000000000000000000000000000000000000000000003782dace9d9000081565b34801561044f57600080fd5b506102857f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b34801561048357600080fd5b50670de0b6b3a76400006102c6565b34801561049e57600080fd5b506102c66104ad3660046113be565b6108d5565b3480156104be57600080fd5b506102c66611c37937e0800081565b3480156104d957600080fd5b506102c66104e83660046113be565b610af8565b3480156104f957600080fd5b5061050d6105083660046113ef565b610d7b565b6040519015158152602001610233565b34801561052957600080fd5b50610285734ddc2d193948926d02f9b1fe9e1daa0718270ed581565b34801561055157600080fd5b506102c661056036600461148e565b610f84565b34801561057157600080fd5b50604080517f00000000000000000000000000000000000000000000000000000000001badf081527f0000000000000000000000000000000000000000000000000000000001ff46dd602082015201610233565b3480156105d157600080fd5b506102857f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b34801561060557600080fd5b506102c67f000000000000000000000000000000000000000000000000000000000000001f81565b34801561063957600080fd5b506102857f0000000000000000000000001887118e49e0f4a78bd71b792a49de03504a764d81565b34801561066d57600080fd5b506102c67f439148f0bbc682ca079e46d6e2c2f0c1e3b820f1a291b069d8882abf8cf18dd981565b3480156106a157600080fd5b50610226610ffa565b3480156106b657600080fd5b5061028573c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b3480156106de57600080fd5b5061020f6106ed3660046114ab565b505050565b3480156106fe57600080fd5b506102c67f0000000000000000000000000000000000000000000000000008e1bc9bf0400081565b34801561073257600080fd5b506102c67f000000000000000000000000000000000000000000000000000000000000000081565b34801561076657600080fd5b506102857f0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca081565b34801561079a57600080fd5b506102c66107a93660046114f2565b611007565b3480156107ba57600080fd5b50610285737f39c581f595b53c5cb19bd0b3f8da6c935e2ca081565b3480156107e257600080fd5b5061028573ae7ab96520de3a18e5e111b5eaab095312d7fe8481565b34801561080a57600080fd5b506102c6611064565b34801561081f57600080fd5b506102c67f00000000000000000000000000000000000000000000000000000000001badf081565b600080546108549061151e565b80601f01602080910402602001604051908101604052809291908181526020018280546108809061151e565b80156108cd5780601f106108a2576101008083540402835291602001916108cd565b820191906000526020600020905b8154815290600101906020018083116108b057829003601f168201915b505050505081565b60006108f773c02aaa39b223fe8d0a0e5c4f27ead9083c756cc233308561109e565b604051632e1a7d4d60e01b81526004810183905273c02aaa39b223fe8d0a0e5c4f27ead9083c756cc290632e1a7d4d90602401600060405180830381600087803b15801561094457600080fd5b505af1158015610958573d6000803e3d6000fd5b505060405163a1903eab60e01b815273ae7ab96520de3a18e5e111b5eaab095312d7fe84925063a1903eab91508490610996906000906004016113aa565b60206040518083038185885af11580156109b4573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906109d99190611553565b506040516370a0823160e01b815260009073ae7ab96520de3a18e5e111b5eaab095312d7fe84906370a0823190610a149030906004016113aa565b602060405180830381865afa158015610a31573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a559190611553565b604051630ea598cb60e41b815260048101829052909150610af2903390737f39c581f595b53c5cb19bd0b3f8da6c935e2ca09063ea598cb0906024016020604051808303816000875af1158015610ab0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ad49190611553565b9350737f39c581f595b53c5cb19bd0b3f8da6c935e2ca09084611137565b50919050565b6000610b1a737f39c581f595b53c5cb19bd0b3f8da6c935e2ca033308561109e565b604051636f074d1f60e11b815260048101839052600090737f39c581f595b53c5cb19bd0b3f8da6c935e2ca09063de0e9a3e906024016020604051808303816000875af1158015610b6f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b939190611553565b9050600073ab55bf4dfbf469ebfe082b7872557d1f87692fe66001600160a01b03166308c80d206040518163ffffffff1660e01b8152600401602060405180830381865afa158015610be9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c0d9190611553565b905073dc24316b9ae028f1497c275eb9192a3ea0f67022633df021246001600085610c5a610c4a6611c37937e08000670de0b6b3a764000061156c565b610c54888a611082565b90611082565b6040516001600160e01b031960e087901b168152600f94850b60048201529290930b6024830152604482015260648101919091526084016020604051808303816000875af1158015610cb0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cd49190611553565b60405190935060009073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc29085908381818185875af1925050503d8060008114610d2d576040519150601f19603f3d011682016040523d82523d6000602084013e610d32565b606091505b5050905080610d54576040516312171d8360e31b815260040160405180910390fd5b610d7373c02aaa39b223fe8d0a0e5c4f27ead9083c756cc23386611137565b505050919050565b6000336001600160a01b03167f00000000000000000000000086ba3e96be68563e41c2f5769f1af9faf758e6e06001600160a01b03166377aace1a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610de5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e099190611591565b6001600160a01b031614610e305760405163fb02114960e01b815260040160405180910390fd5b610e646001600160a01b037f0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca0168786611137565b6040516323e30c8b60e01b81526000906001600160a01b038816906323e30c8b90610ebd9033907f0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca0908a9087908b908b906004016115ae565b6020604051808303816000875af1158015610edc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f009190611553565b90507f439148f0bbc682ca079e46d6e2c2f0c1e3b820f1a291b069d8882abf8cf18dd98114610f425760405163081f7c8760e21b815260040160405180910390fd5b610f776001600160a01b037f0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca01688308861109e565b5060019695505050505050565b6040516370a0823160e01b81526000906001600160a01b038316906370a0823190610fb39030906004016113aa565b602060405180830381865afa158015610fd0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ff49190611553565b92915050565b600180546108549061151e565b60007f0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca06001600160a01b0316836001600160a01b03161461105b57604051633dd1b30560e01b815260040160405180910390fd5b50600092915050565b600061106e6111b0565b9050600254811461107f5760028190555b90565b60006110978383670de0b6b3a76400006112bd565b9392505050565b60006040516323b872dd60e01b81526001600160a01b03851660048201526001600160a01b038416602482015282604482015260008060648360008a5af19150506110e8816112dc565b6111305760405162461bcd60e51b81526020600482015260146024820152731514905394d1915497d19493d357d1905253115160621b60448201526064015b60405180910390fd5b5050505050565b600060405163a9059cbb60e01b81526001600160a01b03841660048201528260248201526000806044836000895af1915050611172816112dc565b6102575760405162461bcd60e51b815260206004820152600f60248201526e1514905394d1915497d19052531151608a1b6044820152606401611127565b60008073ab55bf4dfbf469ebfe082b7872557d1f87692fe66001600160a01b03166308c80d206040518163ffffffff1660e01b8152600401602060405180830381865afa158015611205573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112299190611553565b604051630f451f7160e31b8152670de0b6b3a7640000600482015290915060009073ae7ab96520de3a18e5e111b5eaab095312d7fe8490637a28fb8890602401602060405180830381865afa158015611286573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112aa9190611553565b90506112b68282611082565b9250505090565b8282028115158415858304851417166112d557600080fd5b0492915050565b60003d826112ee57806000803e806000fd5b8060208114611306578015611317576000925061131c565b816000803e6000511515925061131c565b600192505b5050919050565b600060208083528351808285015260005b8181101561135057858101830151858201604001528201611334565b81811115611362576000604083870101525b50601f01601f1916929092016040019392505050565b6000806000806080858703121561138e57600080fd5b5050823594602084013594506040840135936060013592509050565b6001600160a01b0391909116815260200190565b6000602082840312156113d057600080fd5b5035919050565b6001600160a01b03811681146113ec57600080fd5b50565b60008060008060006080868803121561140757600080fd5b8535611412816113d7565b94506020860135611422816113d7565b935060408601359250606086013567ffffffffffffffff8082111561144657600080fd5b818801915088601f83011261145a57600080fd5b81358181111561146957600080fd5b89602082850101111561147b57600080fd5b9699959850939650602001949392505050565b6000602082840312156114a057600080fd5b8135611097816113d7565b6000806000606084860312156114c057600080fd5b83356114cb816113d7565b925060208401359150604084013580151581146114e757600080fd5b809150509250925092565b6000806040838503121561150557600080fd5b8235611510816113d7565b946020939093013593505050565b600181811c9082168061153257607f821691505b60208210811415610af257634e487b7160e01b600052602260045260246000fd5b60006020828403121561156557600080fd5b5051919050565b60008282101561158c57634e487b7160e01b600052601160045260246000fd5b500390565b6000602082840312156115a357600080fd5b8151611097816113d7565b6001600160a01b03878116825286166020820152604081018590526060810184905260a06080820181905281018290526000828460c0840137600060c0848401015260c0601f19601f850116830101905097965050505050505056fea2646970667358221220356b12cb6a7e0d91963482adca61ea78b392492fe3d2fc7488459f1040f5777764736f6c634300080b0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000086ba3e96be68563e41c2f5769f1af9faf758e6e00000000000000000000000001887118e49e0f4a78bd71b792a49de03504a764d0000000000000000000000000000000000000000000000000008e1bc9bf04000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000000000000000000000000000003782dace9d9000000000000000000000000000000000000000000000000000000000000001badf00000000000000000000000000000000000000000000000000000000001ff46dd00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : _divider (address): 0x86bA3E96Be68563E41c2f5769F1AF9fAf758e6E0
Arg [1] : _oracle (address): 0x1887118E49e0F4A78Bd71B792a49dE03504A764D
Arg [2] : _ifee (uint256): 2500000000000000
Arg [3] : _stake (address): 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
Arg [4] : _stakeSize (uint256): 250000000000000000
Arg [5] : _minm (uint256): 1814000
Arg [6] : _maxm (uint256): 33507037
Arg [7] : _mode (uint16): 0
Arg [8] : _tilt (uint64): 0
-----Encoded View---------------
9 Constructor Arguments found :
Arg [0] : 00000000000000000000000086ba3e96be68563e41c2f5769f1af9faf758e6e0
Arg [1] : 0000000000000000000000001887118e49e0f4a78bd71b792a49de03504a764d
Arg [2] : 0000000000000000000000000000000000000000000000000008e1bc9bf04000
Arg [3] : 000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
Arg [4] : 00000000000000000000000000000000000000000000000003782dace9d90000
Arg [5] : 00000000000000000000000000000000000000000000000000000000001badf0
Arg [6] : 0000000000000000000000000000000000000000000000000000000001ff46dd
Arg [7] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [8] : 0000000000000000000000000000000000000000000000000000000000000000
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|---|---|---|---|---|
ETH | 100.00% | $3,973.64 | 0.7163 | $2,846.37 |
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.