Overview
ETH Balance
0 ETH
Eth Value
$0.00Token Holdings
More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 1 from a total of 1 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
0x61010060 | 15264477 | 825 days ago | IN | 0 ETH | 0.05519818 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
WstETHAdapter
Compiler Version
v0.8.11+commit.d7f03943
Optimization Enabled:
Yes with 15000 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 "../../abstract/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 Exchanges wstETH to stETH function unwrap(uint256 _wstETHAmount) external returns (uint256); /// @notice Exchanges stETH to wstETH function wrap(uint256 _stETHAmount) external returns (uint256); } interface StETHLike { /// @notice Get amount of stETH for a one wstETH function getPooledEthByShares(uint256 _sharesAmount) external view returns (uint256); } interface PriceOracleLike { function latestRoundData() external view returns ( uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound ); } /// @notice Adapter contract for wstETH contract WstETHAdapter is BaseAdapter { using FixedMath for uint256; using SafeTransferLib for ERC20; address public constant WSTETH = 0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0; address public constant STETH = 0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84; address public constant STETH_USD_PRICEFEED = 0xCfE54B5cD566aB89272946F602D76Ea879CAb4a8; // Chainlink stETH-USD price feed address public constant ETH_USD_PRICEFEED = 0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419; // Chainlink ETH-USD price feed /// @notice Cached scale value from the last call to `scale()` uint256 public override scaleStored; constructor( address _divider, address _target, uint128 _ifee, BaseAdapter.AdapterParams memory _adapterParams ) BaseAdapter(_divider, _target, STETH, _ifee, _adapterParams) { // approve wstETH contract to pull stETH (used on wrapUnderlying()) ERC20(STETH).approve(WSTETH, type(uint256).max); // set an inital cached scale value scaleStored = StETHLike(STETH).getPooledEthByShares(1 ether); } /// @return exRate Eth per wstEtH (natively in 18 decimals) function scale() external virtual override returns (uint256 exRate) { exRate = StETHLike(STETH).getPooledEthByShares(1 ether); if (exRate != scaleStored) { // update value only if different than the previous scaleStored = exRate; } } /// @dev To calculate stETH-ETH price we use Chainlink's stETH-USD and ETH-USD price feeds. function getUnderlyingPrice() external view override returns (uint256 price) { (, int256 stethPrice, , uint256 stethUpdatedAt, ) = PriceOracleLike(STETH_USD_PRICEFEED).latestRoundData(); (, int256 ethPrice, , uint256 ethUpdatedAt, ) = PriceOracleLike(ETH_USD_PRICEFEED).latestRoundData(); if (block.timestamp - stethUpdatedAt > 2 hours) revert Errors.InvalidPrice(); if (block.timestamp - ethUpdatedAt > 2 hours) revert Errors.InvalidPrice(); price = uint256(stethPrice).fdiv(uint256(ethPrice)); if (price < 0) revert Errors.InvalidPrice(); } function unwrapTarget(uint256 amount) external override returns (uint256 stETH) { ERC20(WSTETH).safeTransferFrom(msg.sender, address(this), amount); // pull wstETH // unwrap wstETH into stETH and transfer it back to sender ERC20(STETH).safeTransfer(msg.sender, stETH = WstETHLike(WSTETH).unwrap(amount)); } function wrapUnderlying(uint256 amount) external override returns (uint256 wstETH) { ERC20(STETH).safeTransferFrom(msg.sender, address(this), amount); // pull STETH // wrap stETH into wstETH and transfer it back to sender ERC20(WSTETH).safeTransfer(msg.sender, wstETH = WstETHLike(WSTETH).wrap(amount)); } }
// 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 Issuance fee uint128 public immutable ifee; /// @notice adapter params AdapterParams public adapterParams; /* ========== DATA STRUCTURES ========== */ struct AdapterParams { /// @notice Oracle address address oracle; /// @notice Token to stake at issuance address stake; /// @notice Amount to stake at issuance uint256 stakeSize; /// @notice Min maturity (seconds after block.timstamp) uint256 minm; /// @notice Max maturity (seconds after block.timstamp) uint256 maxm; /// @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 uint64 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`) uint48 level; /// @notice 0 for monthly, 1 for weekly uint16 mode; } /* ========== METADATA STORAGE ========== */ string public name; string public symbol; constructor( address _divider, address _target, address _underlying, uint128 _ifee, AdapterParams memory _adapterParams ) { divider = _divider; target = _target; underlying = _underlying; ifee = _ifee; adapterParams = _adapterParams; name = string(abi.encodePacked(ERC20(_target).name(), " Adapter")); symbol = string(abi.encodePacked(ERC20(_target).symbol(), "-adapter")); ERC20(_target).approve(divider, type(uint256).max); ERC20(_adapterParams.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 virtual returns (uint256, uint256) { return (adapterParams.minm, adapterParams.maxm); } function getStakeAndTarget() external view returns ( address, address, uint256 ) { return (target, adapterParams.stake, adapterParams.stakeSize); } function mode() external view returns (uint256) { return adapterParams.mode; } function tilt() external view returns (uint256) { return adapterParams.tilt; } function level() external view returns (uint256) { return adapterParams.level; } }
// 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 //////////////////////////////////////////////////////////////*/ uint256 internal immutable INITIAL_CHAIN_ID; bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR; mapping(address => uint256) public nonces; /*////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////*/ constructor( string memory _name, string memory _symbol, uint8 _decimals ) { name = _name; symbol = _symbol; decimals = _decimals; INITIAL_CHAIN_ID = block.chainid; INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator(); } /*////////////////////////////////////////////////////////////// ERC20 LOGIC //////////////////////////////////////////////////////////////*/ function approve(address spender, uint256 amount) public virtual returns (bool) { allowance[msg.sender][spender] = amount; emit Approval(msg.sender, spender, amount); return true; } function transfer(address to, uint256 amount) public virtual returns (bool) { balanceOf[msg.sender] -= amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(msg.sender, to, amount); return true; } function transferFrom( address from, address to, uint256 amount ) public virtual returns (bool) { uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals. if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount; balanceOf[from] -= amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(from, to, amount); return true; } /*////////////////////////////////////////////////////////////// EIP-2612 LOGIC //////////////////////////////////////////////////////////////*/ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) public virtual { require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED"); // Unchecked because the only math done is incrementing // the owner's nonce which cannot realistically overflow. unchecked { address recoveredAddress = ecrecover( keccak256( abi.encodePacked( "\x19\x01", DOMAIN_SEPARATOR(), keccak256( abi.encode( keccak256( "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)" ), owner, spender, value, nonces[owner]++, deadline ) ) ) ), v, r, s ); require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER"); allowance[recoveredAddress][spender] = value; } emit Approval(owner, spender, value); } function DOMAIN_SEPARATOR() public view virtual returns (bytes32) { return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator(); } function computeDomainSeparator() internal view virtual returns (bytes32) { return keccak256( abi.encode( keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), keccak256(bytes(name)), keccak256("1"), block.chainid, address(this) ) ); } /*////////////////////////////////////////////////////////////// INTERNAL MINT/BURN LOGIC //////////////////////////////////////////////////////////////*/ function _mint(address to, uint256 amount) internal virtual { totalSupply += amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(address(0), to, amount); } function _burn(address from, uint256 amount) internal virtual { balanceOf[from] -= amount; // Cannot underflow because a user's balance // will never be larger than the total supply. unchecked { totalSupply -= amount; } emit Transfer(from, address(0), amount); } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; import {ERC20} from "../tokens/ERC20.sol"; /// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values. /// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/utils/SafeTransferLib.sol) /// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer. /// @dev Note that none of the functions in this library check that a token has code at all! That responsibility is delegated to the caller. library SafeTransferLib { event Debug(bool one, bool two, uint256 retsize); /*////////////////////////////////////////////////////////////// ETH OPERATIONS //////////////////////////////////////////////////////////////*/ function safeTransferETH(address to, uint256 amount) internal { bool success; assembly { // Transfer the ETH and store if it succeeded or not. success := call(gas(), to, amount, 0, 0, 0, 0) } require(success, "ETH_TRANSFER_FAILED"); } /*////////////////////////////////////////////////////////////// ERC20 OPERATIONS //////////////////////////////////////////////////////////////*/ function safeTransferFrom( ERC20 token, address from, address to, uint256 amount ) internal { bool success; assembly { // Get a pointer to some free memory. let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000) mstore(add(freeMemoryPointer, 4), from) // Append the "from" argument. mstore(add(freeMemoryPointer, 36), to) // Append the "to" argument. mstore(add(freeMemoryPointer, 68), amount) // Append the "amount" argument. success := and( // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())), // We use 100 because the length of our calldata totals up like so: 4 + 32 * 3. // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space. // Counterintuitively, this call must be positioned second to the or() call in the // surrounding and() call or else returndatasize() will be zero during the computation. call(gas(), token, 0, freeMemoryPointer, 100, 0, 32) ) } require(success, "TRANSFER_FROM_FAILED"); } function safeTransfer( ERC20 token, address to, uint256 amount ) internal { bool success; assembly { // Get a pointer to some free memory. let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000) mstore(add(freeMemoryPointer, 4), to) // Append the "to" argument. mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. success := and( // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())), // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2. // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space. // Counterintuitively, this call must be positioned second to the or() call in the // surrounding and() call or else returndatasize() will be zero during the computation. call(gas(), token, 0, freeMemoryPointer, 68, 0, 32) ) } require(success, "TRANSFER_FAILED"); } function safeApprove( ERC20 token, address to, uint256 amount ) internal { bool success; assembly { // Get a pointer to some free memory. let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000) mstore(add(freeMemoryPointer, 4), to) // Append the "to" argument. mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. success := and( // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())), // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2. // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space. // Counterintuitively, this call must be positioned second to the or() call in the // surrounding and() call or else returndatasize() will be zero during the computation. call(gas(), token, 0, freeMemoryPointer, 68, 0, 32) ) } require(success, "APPROVE_FAILED"); } }
// SPDX-License-Identifier: 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 SenderNotEligible(); error TargetMismatch(); error TargetNotSupported(); error InvalidAdapterType(); error PriceOracleNotFound(); // 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 NotImplemented(); error OutOfWindowBoundaries(); error SeriesDoesNotExist(); error SwapTooSmall(); error TargetParamsNotSet(); error PoolParamsNotSet(); error PTParamsNotSet(); error AttemptFailed(); error InvalidPrice(); error BadContractInteration(); // Periphery error FactoryNotSupported(); error FlashBorrowFailed(); error FlashUntrustedBorrower(); error FlashUntrustedLoanInitiator(); error UnexpectedSwapAmount(); error TooMuchLeftoverTarget(); // 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/abstract/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 locked = 1; modifier nonReentrant() { require(locked == 1, "REENTRANCY"); locked = 2; _; locked = 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": 15000 }, "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":"_target","type":"address"},{"internalType":"uint128","name":"_ifee","type":"uint128"},{"components":[{"internalType":"address","name":"oracle","type":"address"},{"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":"uint64","name":"tilt","type":"uint64"},{"internalType":"uint48","name":"level","type":"uint48"},{"internalType":"uint16","name":"mode","type":"uint16"}],"internalType":"struct BaseAdapter.AdapterParams","name":"_adapterParams","type":"tuple"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"FlashCallbackFailed","type":"error"},{"inputs":[],"name":"InvalidPrice","type":"error"},{"inputs":[],"name":"OnlyPeriphery","type":"error"},{"inputs":[],"name":"TokenNotSupported","type":"error"},{"inputs":[],"name":"CALLBACK_SUCCESS","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ETH_USD_PRICEFEED","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STETH","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STETH_USD_PRICEFEED","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":"adapterParams","outputs":[{"internalType":"address","name":"oracle","type":"address"},{"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":"uint64","name":"tilt","type":"uint64"},{"internalType":"uint48","name":"level","type":"uint48"},{"internalType":"uint16","name":"mode","type":"uint16"}],"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":"view","type":"function"},{"inputs":[],"name":"ifee","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"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":"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":"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":"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":"stETH","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
6101006040523480156200001257600080fd5b5060405162001cd038038062001cd08339810160408190526200003591620005b9565b6001600160a01b03808516608090815281851660a081815273ae7ab96520de3a18e5e111b5eaab095312d7fe8460c08181526001600160801b03881660e09081528751600080549189166001600160a01b031992831617815560208a01516001805491909a1692169190911790975560408089015160025560608901516003559588015160049081559388015160058054938a0151928a015161ffff16600160701b0261ffff60701b1965ffffffffffff90941668010000000000000000026001600160701b03199095166001600160401b0390931692909217939093179190911617905583516306fdde0360e01b815293518995899592948994899491936306fdde0393838301939092908290030181865afa1580156200015b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052620001859190810190620006f3565b604051602001620001979190620007ab565b60405160208183030381529060405260069080519060200190620001bd9291906200048a565b50836001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015620001fd573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052620002279190810190620006f3565b604051602001620002399190620007d9565b604051602081830303815290604052600790805190602001906200025f9291906200048a565b5060805160405163095ea7b360e01b81526001600160a01b03918216600482015260001960248201529085169063095ea7b3906044016020604051808303816000875af1158015620002b5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002db919062000807565b50602081015160805160405163095ea7b360e01b81526001600160a01b039182166004820152600019602482015291169063095ea7b3906044016020604051808303816000875af115801562000335573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200035b919062000807565b505060405163095ea7b360e01b8152737f39c581f595b53c5cb19bd0b3f8da6c935e2ca06004820152600019602482015273ae7ab96520de3a18e5e111b5eaab095312d7fe84945063095ea7b393506044019150620003b79050565b6020604051808303816000875af1158015620003d7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620003fd919062000807565b50604051630f451f7160e31b8152670de0b6b3a7640000600482015273ae7ab96520de3a18e5e111b5eaab095312d7fe8490637a28fb8890602401602060405180830381865afa15801562000456573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200047c919062000832565b600855506200088992505050565b82805462000498906200084c565b90600052602060002090601f016020900481019282620004bc576000855562000507565b82601f10620004d757805160ff191683800117855562000507565b8280016001018555821562000507579182015b8281111562000507578251825591602001919060010190620004ea565b506200051592915062000519565b5090565b5b808211156200051557600081556001016200051a565b80516001600160a01b03811681146200054857600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60405161010081016001600160401b03811182821017156200058957620005896200054d565b60405290565b805165ffffffffffff811681146200054857600080fd5b805161ffff811681146200054857600080fd5b600080600080848603610160811215620005d257600080fd5b620005dd8662000530565b9450620005ed6020870162000530565b60408701519094506001600160801b03811681146200060b57600080fd5b9250610100605f1982018113156200062257600080fd5b6200062c62000563565b91506200063c6060880162000530565b82526200064c6080880162000530565b602083015260a0870151604083015260c0870151606083015260e087015160808301528601516001600160401b03811681146200068857600080fd5b60a08201526200069c61012087016200058f565b60c0820152620006b06101408701620005a6565b60e0820152939692955090935050565b60005b83811015620006dd578181015183820152602001620006c3565b83811115620006ed576000848401525b50505050565b6000602082840312156200070657600080fd5b81516001600160401b03808211156200071e57600080fd5b818401915084601f8301126200073357600080fd5b8151818111156200074857620007486200054d565b604051601f8201601f19908116603f011681019083821181831017156200077357620007736200054d565b816040528281528760208487010111156200078d57600080fd5b620007a0836020830160208801620006c0565b979650505050505050565b60008251620007bf818460208701620006c0565b671020b230b83a32b960c11b920191825250600801919050565b60008251620007ed818460208701620006c0565b6716b0b230b83a32b960c11b920191825250600801919050565b6000602082840312156200081a57600080fd5b815180151581146200082b57600080fd5b9392505050565b6000602082840312156200084557600080fd5b5051919050565b600181811c908216806200086157607f821691505b602082108114156200088357634e487b7160e01b600052602260045260246000fd5b50919050565b60805160a05160c05160e0516113e3620008ed60003960006104e0015260006104400152600081816103010152818161053a01528181610ab201528181610b2801528181610c100152610ced01526000818161035a01526109be01526113e36000f3fe608060405234801561001057600080fd5b50600436106101b95760003560e01c806364c56e3c116100f9578063b8c15a9f11610097578063d9d98ce411610071578063d9d98ce41461055c578063d9fb643a1461056f578063e00bfe501461058a578063f51e181a146105a557600080fd5b8063b8c15a9f146104db578063c39a3b2914610523578063d4b839921461053557600080fd5b80638237e538116100d35780638237e5381461047e57806395d89b41146104a5578063985579a4146104ad578063b484972a146104c857600080fd5b806364c56e3c146104205780636f307dc31461043b5780636fd5ae151461046257600080fd5b8063378efa37116101665780634aae9fed116101405780634aae9fed146103c457806351c39ea1146103d75780635cffe9de146103ea578063613255ab1461040d57600080fd5b8063378efa371461035557806340cc63e1146103a1578063468f02d2146103bc57600080fd5b8063226778491161019757806322677849146102c957806327b327d0146102e0578063295a52121461033757600080fd5b806306fdde03146101be578063083118d5146101dc57806314282f58146102b3575b600080fd5b6101c66105ad565b6040516101d39190610fe3565b60405180910390f35b60005460015460025460035460045460055461024a9573ffffffffffffffffffffffffffffffffffffffff90811695169392919067ffffffffffffffff81169068010000000000000000810465ffffffffffff16906e010000000000000000000000000000900461ffff1688565b6040805173ffffffffffffffffffffffffffffffffffffffff998a168152989097166020890152958701949094526060860192909252608085015267ffffffffffffffff1660a084015265ffffffffffff1660c083015261ffff1660e0820152610100016101d3565b6102c76102c1366004611056565b50505050565b005b6102d260085481565b6040519081526020016101d3565b6001546002546040805173ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000008116825290931660208401528201526060016101d3565b6005546e010000000000000000000000000000900461ffff166102d2565b61037c7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101d3565b61037c735f4ec3df9cbd43714fe2740f5e3616155c5b841981565b6102d261063b565b6102d26103d2366004611088565b6107f4565b6102d26103e5366004611088565b6108ce565b6103fd6103f83660046110c6565b6109a3565b60405190151581526020016101d3565b6102d261041b366004611165565b610c45565b600354600454604080519283526020830191909152016101d3565b61037c7f000000000000000000000000000000000000000000000000000000000000000081565b60055468010000000000000000900465ffffffffffff166102d2565b6102d27f439148f0bbc682ca079e46d6e2c2f0c1e3b820f1a291b069d8882abf8cf18dd981565b6101c6610cdc565b61037c73cfe54b5cd566ab89272946f602d76ea879cab4a881565b6102c76104d6366004611182565b505050565b6105027f000000000000000000000000000000000000000000000000000000000000000081565b6040516fffffffffffffffffffffffffffffffff90911681526020016101d3565b60055467ffffffffffffffff166102d2565b61037c7f000000000000000000000000000000000000000000000000000000000000000081565b6102d261056a3660046111c9565b610ce9565b61037c737f39c581f595b53c5cb19bd0b3f8da6c935e2ca081565b61037c73ae7ab96520de3a18e5e111b5eaab095312d7fe8481565b6102d2610d79565b600680546105ba906111f5565b80601f01602080910402602001604051908101604052809291908181526020018280546105e6906111f5565b80156106335780601f1061060857610100808354040283529160200191610633565b820191906000526020600020905b81548152906001019060200180831161061657829003601f168201915b505050505081565b600080600073cfe54b5cd566ab89272946f602d76ea879cab4a873ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa15801561069f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106c39190611263565b50935050925050600080735f4ec3df9cbd43714fe2740f5e3616155c5b841973ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa15801561072c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107509190611263565b50935050925050611c20834261076691906112b3565b111561079d576040517ebfc92100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611c206107aa82426112b3565b11156107e1576040517ebfc92100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6107eb8483610e24565b94505050505090565b600061081673ae7ab96520de3a18e5e111b5eaab095312d7fe84333085610e40565b6040517fea598cb0000000000000000000000000000000000000000000000000000000008152600481018390526108c9903390737f39c581f595b53c5cb19bd0b3f8da6c935e2ca09063ea598cb0906024016020604051808303816000875af1158015610887573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108ab91906112f1565b9250737f39c581f595b53c5cb19bd0b3f8da6c935e2ca09083610f0b565b919050565b60006108f0737f39c581f595b53c5cb19bd0b3f8da6c935e2ca0333085610e40565b6040517fde0e9a3e000000000000000000000000000000000000000000000000000000008152600481018390526108c9903390737f39c581f595b53c5cb19bd0b3f8da6c935e2ca09063de0e9a3e906024016020604051808303816000875af1158015610961573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061098591906112f1565b925073ae7ab96520de3a18e5e111b5eaab095312d7fe849083610f0b565b60003373ffffffffffffffffffffffffffffffffffffffff167f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166377aace1a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a27573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a4b919061130a565b73ffffffffffffffffffffffffffffffffffffffff1614610a98576040517ffb02114900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610ad973ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168786610f0b565b6040517f23e30c8b00000000000000000000000000000000000000000000000000000000815260009073ffffffffffffffffffffffffffffffffffffffff8816906323e30c8b90610b589033907f0000000000000000000000000000000000000000000000000000000000000000908a9087908b908b90600401611327565b6020604051808303816000875af1158015610b77573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b9b91906112f1565b90507f439148f0bbc682ca079e46d6e2c2f0c1e3b820f1a291b069d8882abf8cf18dd98114610bf6576040517f207df21c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610c3873ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016883088610e40565b5060019695505050505050565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009073ffffffffffffffffffffffffffffffffffffffff8316906370a0823190602401602060405180830381865afa158015610cb2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cd691906112f1565b92915050565b600780546105ba906111f5565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614610d70576040517f3dd1b30500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50600092915050565b6040517f7a28fb88000000000000000000000000000000000000000000000000000000008152670de0b6b3a7640000600482015260009073ae7ab96520de3a18e5e111b5eaab095312d7fe8490637a28fb8890602401602060405180830381865afa158015610dec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e1091906112f1565b90506008548114610e215760088190555b90565b6000610e3983670de0b6b3a764000084610fc4565b9392505050565b60006040517f23b872dd0000000000000000000000000000000000000000000000000000000081528460048201528360248201528260448201526020600060648360008a5af13d15601f3d1160016000511416171691505080610f04576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5452414e534645525f46524f4d5f4641494c454400000000000000000000000060448201526064015b60405180910390fd5b5050505050565b60006040517fa9059cbb000000000000000000000000000000000000000000000000000000008152836004820152826024820152602060006044836000895af13d15601f3d11600160005114161716915050806102c1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5452414e534645525f4641494c454400000000000000000000000000000000006044820152606401610efb565b828202811515841585830485141716610fdc57600080fd5b0492915050565b600060208083528351808285015260005b8181101561101057858101830151858201604001528201610ff4565b81811115611022576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b6000806000806080858703121561106c57600080fd5b5050823594602084013594506040840135936060013592509050565b60006020828403121561109a57600080fd5b5035919050565b73ffffffffffffffffffffffffffffffffffffffff811681146110c357600080fd5b50565b6000806000806000608086880312156110de57600080fd5b85356110e9816110a1565b945060208601356110f9816110a1565b935060408601359250606086013567ffffffffffffffff8082111561111d57600080fd5b818801915088601f83011261113157600080fd5b81358181111561114057600080fd5b89602082850101111561115257600080fd5b9699959850939650602001949392505050565b60006020828403121561117757600080fd5b8135610e39816110a1565b60008060006060848603121561119757600080fd5b83356111a2816110a1565b925060208401359150604084013580151581146111be57600080fd5b809150509250925092565b600080604083850312156111dc57600080fd5b82356111e7816110a1565b946020939093013593505050565b600181811c9082168061120957607f821691505b60208210811415611243577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b805169ffffffffffffffffffff811681146108c957600080fd5b600080600080600060a0868803121561127b57600080fd5b61128486611249565b94506020860151935060408601519250606086015191506112a760808701611249565b90509295509295909350565b6000828210156112ec577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b500390565b60006020828403121561130357600080fd5b5051919050565b60006020828403121561131c57600080fd5b8151610e39816110a1565b600073ffffffffffffffffffffffffffffffffffffffff808916835280881660208401525085604083015284606083015260a060808301528260a0830152828460c0840137600060c0848401015260c07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f850116830101905097965050505050505056fea264697066735822122019a07943a88d6e771fa48c8e3ea76e9c59bbc7fa1c05636b7041a4c126e4837b64736f6c634300080b003300000000000000000000000086ba3e96be68563e41c2f5769f1af9faf758e6e00000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000000000000000000000000000003782dace9d9000000000000000000000000000000000000000000000000000000000000002820a80000000000000000000000000000000000000000000000000000000012cf4ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001f0000000000000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101b95760003560e01c806364c56e3c116100f9578063b8c15a9f11610097578063d9d98ce411610071578063d9d98ce41461055c578063d9fb643a1461056f578063e00bfe501461058a578063f51e181a146105a557600080fd5b8063b8c15a9f146104db578063c39a3b2914610523578063d4b839921461053557600080fd5b80638237e538116100d35780638237e5381461047e57806395d89b41146104a5578063985579a4146104ad578063b484972a146104c857600080fd5b806364c56e3c146104205780636f307dc31461043b5780636fd5ae151461046257600080fd5b8063378efa37116101665780634aae9fed116101405780634aae9fed146103c457806351c39ea1146103d75780635cffe9de146103ea578063613255ab1461040d57600080fd5b8063378efa371461035557806340cc63e1146103a1578063468f02d2146103bc57600080fd5b8063226778491161019757806322677849146102c957806327b327d0146102e0578063295a52121461033757600080fd5b806306fdde03146101be578063083118d5146101dc57806314282f58146102b3575b600080fd5b6101c66105ad565b6040516101d39190610fe3565b60405180910390f35b60005460015460025460035460045460055461024a9573ffffffffffffffffffffffffffffffffffffffff90811695169392919067ffffffffffffffff81169068010000000000000000810465ffffffffffff16906e010000000000000000000000000000900461ffff1688565b6040805173ffffffffffffffffffffffffffffffffffffffff998a168152989097166020890152958701949094526060860192909252608085015267ffffffffffffffff1660a084015265ffffffffffff1660c083015261ffff1660e0820152610100016101d3565b6102c76102c1366004611056565b50505050565b005b6102d260085481565b6040519081526020016101d3565b6001546002546040805173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca08116825290931660208401528201526060016101d3565b6005546e010000000000000000000000000000900461ffff166102d2565b61037c7f00000000000000000000000086ba3e96be68563e41c2f5769f1af9faf758e6e081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101d3565b61037c735f4ec3df9cbd43714fe2740f5e3616155c5b841981565b6102d261063b565b6102d26103d2366004611088565b6107f4565b6102d26103e5366004611088565b6108ce565b6103fd6103f83660046110c6565b6109a3565b60405190151581526020016101d3565b6102d261041b366004611165565b610c45565b600354600454604080519283526020830191909152016101d3565b61037c7f000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe8481565b60055468010000000000000000900465ffffffffffff166102d2565b6102d27f439148f0bbc682ca079e46d6e2c2f0c1e3b820f1a291b069d8882abf8cf18dd981565b6101c6610cdc565b61037c73cfe54b5cd566ab89272946f602d76ea879cab4a881565b6102c76104d6366004611182565b505050565b6105027f000000000000000000000000000000000000000000000000000000000000000081565b6040516fffffffffffffffffffffffffffffffff90911681526020016101d3565b60055467ffffffffffffffff166102d2565b61037c7f0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca081565b6102d261056a3660046111c9565b610ce9565b61037c737f39c581f595b53c5cb19bd0b3f8da6c935e2ca081565b61037c73ae7ab96520de3a18e5e111b5eaab095312d7fe8481565b6102d2610d79565b600680546105ba906111f5565b80601f01602080910402602001604051908101604052809291908181526020018280546105e6906111f5565b80156106335780601f1061060857610100808354040283529160200191610633565b820191906000526020600020905b81548152906001019060200180831161061657829003601f168201915b505050505081565b600080600073cfe54b5cd566ab89272946f602d76ea879cab4a873ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa15801561069f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106c39190611263565b50935050925050600080735f4ec3df9cbd43714fe2740f5e3616155c5b841973ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa15801561072c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107509190611263565b50935050925050611c20834261076691906112b3565b111561079d576040517ebfc92100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611c206107aa82426112b3565b11156107e1576040517ebfc92100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6107eb8483610e24565b94505050505090565b600061081673ae7ab96520de3a18e5e111b5eaab095312d7fe84333085610e40565b6040517fea598cb0000000000000000000000000000000000000000000000000000000008152600481018390526108c9903390737f39c581f595b53c5cb19bd0b3f8da6c935e2ca09063ea598cb0906024016020604051808303816000875af1158015610887573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108ab91906112f1565b9250737f39c581f595b53c5cb19bd0b3f8da6c935e2ca09083610f0b565b919050565b60006108f0737f39c581f595b53c5cb19bd0b3f8da6c935e2ca0333085610e40565b6040517fde0e9a3e000000000000000000000000000000000000000000000000000000008152600481018390526108c9903390737f39c581f595b53c5cb19bd0b3f8da6c935e2ca09063de0e9a3e906024016020604051808303816000875af1158015610961573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061098591906112f1565b925073ae7ab96520de3a18e5e111b5eaab095312d7fe849083610f0b565b60003373ffffffffffffffffffffffffffffffffffffffff167f00000000000000000000000086ba3e96be68563e41c2f5769f1af9faf758e6e073ffffffffffffffffffffffffffffffffffffffff166377aace1a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a27573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a4b919061130a565b73ffffffffffffffffffffffffffffffffffffffff1614610a98576040517ffb02114900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610ad973ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca0168786610f0b565b6040517f23e30c8b00000000000000000000000000000000000000000000000000000000815260009073ffffffffffffffffffffffffffffffffffffffff8816906323e30c8b90610b589033907f0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca0908a9087908b908b90600401611327565b6020604051808303816000875af1158015610b77573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b9b91906112f1565b90507f439148f0bbc682ca079e46d6e2c2f0c1e3b820f1a291b069d8882abf8cf18dd98114610bf6576040517f207df21c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610c3873ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca016883088610e40565b5060019695505050505050565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015260009073ffffffffffffffffffffffffffffffffffffffff8316906370a0823190602401602060405180830381865afa158015610cb2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cd691906112f1565b92915050565b600780546105ba906111f5565b60007f0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614610d70576040517f3dd1b30500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50600092915050565b6040517f7a28fb88000000000000000000000000000000000000000000000000000000008152670de0b6b3a7640000600482015260009073ae7ab96520de3a18e5e111b5eaab095312d7fe8490637a28fb8890602401602060405180830381865afa158015610dec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e1091906112f1565b90506008548114610e215760088190555b90565b6000610e3983670de0b6b3a764000084610fc4565b9392505050565b60006040517f23b872dd0000000000000000000000000000000000000000000000000000000081528460048201528360248201528260448201526020600060648360008a5af13d15601f3d1160016000511416171691505080610f04576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5452414e534645525f46524f4d5f4641494c454400000000000000000000000060448201526064015b60405180910390fd5b5050505050565b60006040517fa9059cbb000000000000000000000000000000000000000000000000000000008152836004820152826024820152602060006044836000895af13d15601f3d11600160005114161716915050806102c1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5452414e534645525f4641494c454400000000000000000000000000000000006044820152606401610efb565b828202811515841585830485141716610fdc57600080fd5b0492915050565b600060208083528351808285015260005b8181101561101057858101830151858201604001528201610ff4565b81811115611022576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b6000806000806080858703121561106c57600080fd5b5050823594602084013594506040840135936060013592509050565b60006020828403121561109a57600080fd5b5035919050565b73ffffffffffffffffffffffffffffffffffffffff811681146110c357600080fd5b50565b6000806000806000608086880312156110de57600080fd5b85356110e9816110a1565b945060208601356110f9816110a1565b935060408601359250606086013567ffffffffffffffff8082111561111d57600080fd5b818801915088601f83011261113157600080fd5b81358181111561114057600080fd5b89602082850101111561115257600080fd5b9699959850939650602001949392505050565b60006020828403121561117757600080fd5b8135610e39816110a1565b60008060006060848603121561119757600080fd5b83356111a2816110a1565b925060208401359150604084013580151581146111be57600080fd5b809150509250925092565b600080604083850312156111dc57600080fd5b82356111e7816110a1565b946020939093013593505050565b600181811c9082168061120957607f821691505b60208210811415611243577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b805169ffffffffffffffffffff811681146108c957600080fd5b600080600080600060a0868803121561127b57600080fd5b61128486611249565b94506020860151935060408601519250606086015191506112a760808701611249565b90509295509295909350565b6000828210156112ec577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b500390565b60006020828403121561130357600080fd5b5051919050565b60006020828403121561131c57600080fd5b8151610e39816110a1565b600073ffffffffffffffffffffffffffffffffffffffff808916835280881660208401525085604083015284606083015260a060808301528260a0830152828460c0840137600060c0848401015260c07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f850116830101905097965050505050505056fea264697066735822122019a07943a88d6e771fa48c8e3ea76e9c59bbc7fa1c05636b7041a4c126e4837b64736f6c634300080b0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000086ba3e96be68563e41c2f5769f1af9faf758e6e00000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000000000000000000000000000003782dace9d9000000000000000000000000000000000000000000000000000000000000002820a80000000000000000000000000000000000000000000000000000000012cf4ec00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001f0000000000000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : _divider (address): 0x86bA3E96Be68563E41c2f5769F1AF9fAf758e6E0
Arg [1] : _target (address): 0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0
Arg [2] : _ifee (uint128): 0
Arg [3] : _adapterParams (tuple): System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput]
-----Encoded View---------------
11 Constructor Arguments found :
Arg [0] : 00000000000000000000000086ba3e96be68563e41c2f5769f1af9faf758e6e0
Arg [1] : 0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca0
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [4] : 000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
Arg [5] : 00000000000000000000000000000000000000000000000003782dace9d90000
Arg [6] : 00000000000000000000000000000000000000000000000000000000002820a8
Arg [7] : 0000000000000000000000000000000000000000000000000000000012cf4ec0
Arg [8] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [9] : 000000000000000000000000000000000000000000000000000000000000001f
Arg [10] : 0000000000000000000000000000000000000000000000000000000000000000
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.