ETH Price: $3,068.34 (+0.50%)

Contract

0x543e186ae5c7FeA674C489F50215EE8036e87897
 

Overview

ETH Balance

0 ETH

ETH Value

$0.00

Token Holdings

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Value
Subscribe1166589062024-02-26 3:03:0951 days ago1708916589IN
0x543e186a...036e87897
0 ETH0.00000970.00523313
Claim1139349182023-12-25 1:43:33114 days ago1703468613IN
0x543e186a...036e87897
0 ETH0.000000860.0061722
Claim1139348952023-12-25 1:42:47114 days ago1703468567IN
0x543e186a...036e87897
0 ETH0.000001070.0061722
Subscribe1137925202023-12-21 18:36:57117 days ago1703183817IN
0x543e186a...036e87897
0 ETH0.000001010.0079346
Subscribe1137913752023-12-21 17:58:47117 days ago1703181527IN
0x543e186a...036e87897
0 ETH0.00000080.0062733
Subscribe1137913632023-12-21 17:58:23117 days ago1703181503IN
0x543e186a...036e87897
0 ETH0.00000080.0062733
Subscribe1137913222023-12-21 17:57:01117 days ago1703181421IN
0x543e186a...036e87897
0 ETH0.000003370.0233217
Subscribe1137911342023-12-21 17:50:45117 days ago1703181045IN
0x543e186a...036e87897
0 ETH0.000000620.0049127
Subscribe1137910962023-12-21 17:49:29117 days ago1703180969IN
0x543e186a...036e87897
0 ETH0.00000080.0062702
Claim1137910772023-12-21 17:48:51117 days ago1703180931IN
0x543e186a...036e87897
0 ETH0.000000520.0062702
Subscribe1137910012023-12-21 17:46:19117 days ago1703180779IN
0x543e186a...036e87897
0 ETH0.000002450.0062702
Subscribe1137908562023-12-21 17:41:29117 days ago1703180489IN
0x543e186a...036e87897
0 ETH0.000001290.0095032
Subscribe1137865702023-12-21 15:18:37117 days ago1703171917IN
0x543e186a...036e87897
0 ETH0.000001670.0075989
Subscribe1137423542023-12-20 14:44:45118 days ago1703083485IN
0x543e186a...036e87897
0 ETH0.000001290.0101268
Subscribe1137423362023-12-20 14:44:09118 days ago1703083449IN
0x543e186a...036e87897
0 ETH0.000001290.0101268
Subscribe1137423062023-12-20 14:43:09118 days ago1703083389IN
0x543e186a...036e87897
0 ETH0.000001290.0101268
Subscribe1137421352023-12-20 14:37:27118 days ago1703083047IN
0x543e186a...036e87897
0 ETH0.000004050.0317294
Subscribe1137418882023-12-20 14:29:13118 days ago1703082553IN
0x543e186a...036e87897
0 ETH0.000001110.0087257
Subscribe1137417332023-12-20 14:24:03118 days ago1703082243IN
0x543e186a...036e87897
0 ETH0.000000430.0034114
Subscribe1137388952023-12-20 12:49:27118 days ago1703076567IN
0x543e186a...036e87897
0 ETH0.000000720.0049865
Subscribe1137388112023-12-20 12:46:39118 days ago1703076399IN
0x543e186a...036e87897
0 ETH0.000001850.0049865
Claim1134321332023-12-13 10:24:03126 days ago1702463043IN
0x543e186a...036e87897
0 ETH0.00000330.0120713
Subscribe1134294102023-12-13 8:53:17126 days ago1702457597IN
0x543e186a...036e87897
0 ETH0.000020640.020794
Subscribe1119687162023-11-09 13:23:29159 days ago1699536209IN
0x543e186a...036e87897
0 ETH0.000001410.01106738
Subscribe1119661222023-11-09 11:57:01159 days ago1699531021IN
0x543e186a...036e87897
0 ETH0.00000260.0179867
View all transactions

View more zero value Internal Transactions in Advanced View mode

Advanced mode:

Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Subs

Compiler Version
v0.8.19+commit.7dd6d404

Optimization Enabled:
Yes with 4294967 runs

Other Settings:
paris EvmVersion, None license
File 1 of 8 : Subs.sol
pragma solidity ^0.8.19;

import {ERC20} from "solmate/src/tokens/ERC20.sol";
import {SafeTransferLib} from "solmate/src/utils/SafeTransferLib.sol";
import {BoringBatchable} from "./fork/BoringBatchable.sol";
import {AaveV3Adapter} from "./yield/AaveV3Adapter.sol";
import {FixedPointMathLib} from "solmate/src/utils/FixedPointMathLib.sol";

contract Subs is BoringBatchable, AaveV3Adapter {
    using SafeTransferLib for ERC20;
    using FixedPointMathLib for uint256;

    uint public immutable periodDuration;
    address public immutable feeCollector;
    uint public currentPeriod; // Invariant: currentPeriod < block.timestamp
    uint public sharesAccumulator;
    mapping(address => mapping(uint256 => uint256)) public receiverAmountToExpire;
    struct ReceiverBalance {
        uint256 balance;
        uint256 amountPerPeriod;
        uint256 lastUpdate; // Invariant: lastUpdate <= currentPeriod
    }
    mapping(address => ReceiverBalance) public receiverBalances;
    mapping(uint256 => uint256) public sharesPerPeriod;
    mapping(bytes32 => bool) public subs;

    event NewSubscription(address owner, uint initialPeriod, uint expirationDate, uint amountPerCycle, address receiver, uint256 accumulator, uint256 initialShares, bytes32 subId);
    event NewDelayedSubscription(address owner, uint initialPeriod, uint expirationDate, uint amountPerCycle, address receiver, uint256 accumulator, uint256 initialShares, bytes32 subId, uint instantPayment);
    event Unsubscribe(bytes32 subId);

    constructor(uint _periodDuration, address _vault, address _feeCollector, uint _currentPeriod, address rewardRecipient_,
        address stakingRewards_, uint minBalanceToTriggerDeposit_) AaveV3Adapter(_vault, rewardRecipient_, stakingRewards_, minBalanceToTriggerDeposit_){
        // periodDuration MUST NOT be a very small number, otherwise loops could end growing big and blowing up gas costs
        // At 500-600 cycles you start running into ethereum's gas limit per block, which would make it impossible to call the contract
        // We solve that by adding a method that lets users update state partially, so you can split a 20 years update into 4 calls that update 5 years each
        // however there's still the problem of gas costs growing so much that cost to do all those updates would be prohibitive,
        // So we enforce a minimum of 1 week for periodDuration, which keeps the max gas costs bounded (it would take >10yrs for it to grow bigger than the current gas limit per block)
        //require(_periodDuration >= 7 days, "periodDuration too smol");
        periodDuration = _periodDuration;
        currentPeriod = _currentPeriod;
        require(currentPeriod < block.timestamp);
        feeCollector = _feeCollector;
    }

    function _updateGlobal(uint limit) private {
        if(block.timestamp > currentPeriod + periodDuration){
            uint shares = convertToShares(DIVISOR);
            do {
                sharesPerPeriod[currentPeriod] = shares;
                currentPeriod += periodDuration;
                sharesAccumulator += shares; // This could be optimized with `sharesAccumulator += ((block.timestamp - currentPeriod - 1)/periodDuration)*shares;`, but not worth it
            } while(limit > currentPeriod + periodDuration);
        }
    }

    function min(uint a, uint b) pure internal returns (uint) {
        return a>b?b:a;
    } 

    function _updateReceiver(address receiver, uint limit) private {
        ReceiverBalance storage bal = receiverBalances[receiver];
        uint lastUpdate = bal.lastUpdate;
        if(lastUpdate + periodDuration < block.timestamp){
            _updateGlobal(limit); // if lastUpdate is up to date then currentPeriod must be up to date since lastUpdate is only updated after calling _updateGlobal()
            if(lastUpdate == 0){
                lastUpdate = currentPeriod;
            } else {
                // This optimization can increase costs a little on subscribe() but decreases costs a lot when _updateReceiver() hasnt been called in a long time
                uint balance = bal.balance;
                uint amountPerPeriod = bal.amountPerPeriod;
                uint limitToFill = min(currentPeriod, limit);
                do {
                    // here lastUpdate < currentPeriod is always true
                    amountPerPeriod -= receiverAmountToExpire[receiver][lastUpdate];
                    balance += (amountPerPeriod * sharesPerPeriod[lastUpdate]) / DIVISOR;
                    lastUpdate += periodDuration;
                } while (lastUpdate < limitToFill);
                bal.balance = balance;
                bal.amountPerPeriod = amountPerPeriod;
            }
            bal.lastUpdate = lastUpdate;
        }
    }

    // This allows partial updates in case an update to current timestamp results in gas costs higher than the block limit
    // By splitting this into multiple partial calls you could get around the block limit and ensure that any funds can still be withdrawn even if called after >10yr
    function partialUpdateReceiver(address receiver, uint limit) external {
        require(limit < block.timestamp, "limit too big");
        _updateReceiver(receiver, limit);
    }

    function getSubId(address owner, uint initialPeriod, uint expirationDate,
        uint amountPerCycle, address receiver, uint256 accumulator, uint256 initialShares) public pure returns (bytes32 id){
        id = keccak256(
            abi.encode(
                owner,
                initialPeriod,
                expirationDate, // needed to undo receiverAmountToExpire
                amountPerCycle,
                receiver,
                accumulator,
                initialShares
            )
        );
    }

    function _subscribe(address receiver, uint amountPerCycle, uint256 amountForFuture, uint claimableThisPeriod) internal
        returns (uint expirationDate, uint256, bytes32) {
        uint amount = amountForFuture + claimableThisPeriod;
        asset.safeTransferFrom(msg.sender, address(this), amount);
        // If subscribed when timestamp == currentPeriod with cycles == 0, this will revert, which is fine since such subscription is for 0 seconds
        (uint shares, uint cycles) = deposit(amount, amountPerCycle); // Limit loss from deposit to 1% of cycle cost
        uint expiration = currentPeriod + periodDuration*cycles;
        // Setting receiverAmountToExpire here makes the implicit assumption than all calls to convertToShares(DIVISOR) within _updateGlobal() in the future will return a lower number than the one returned right now,
        // in other words, that the underlying vault will never lose money and its pricePerShare() will not go down
        // If vault were to lose money, contract will keep working, but it will have bad debt, so the last users to withdraw won't be able to
        receiverAmountToExpire[receiver][expiration] += amountPerCycle;
        receiverBalances[receiver].amountPerPeriod += amountPerCycle;
        receiverBalances[receiver].balance += (shares * claimableThisPeriod) / amount; // if claimableThisPeriod = 0 && cycles == 0 this will revert, but thats fine since thats a useless sub
        uint sharesLeft = (amountForFuture * shares) / amount;
        bytes32 subId = getSubId(msg.sender, currentPeriod, expiration, amountPerCycle, receiver, sharesAccumulator, sharesLeft);
        require(subs[subId] == false, "duplicated sub");
        subs[subId] = true;
        return (expiration, sharesLeft, subId);
    }

    function subscribe(address receiver, uint amountPerCycle, uint256 amountForFuture) external {
        _updateReceiver(receiver, block.timestamp);
        // block.timestamp <= currentPeriod + periodDuration is enforced in _updateGlobal() and currentPeriod <= block.timestamp
        // so 0 <= (currentPeriod + periodDuration - block.timestamp) <= periodDuration
        // thus this will never underflow and claimableThisPeriod <= amountPerCycle
        uint claimableThisPeriod = (amountPerCycle * (currentPeriod + periodDuration - block.timestamp)) / periodDuration;
        (uint expirationDate, uint256 sharesLeft, bytes32 subId) = _subscribe(receiver, amountPerCycle, amountForFuture, claimableThisPeriod);
        emit NewSubscription(msg.sender, currentPeriod, expirationDate, amountPerCycle, receiver, sharesAccumulator, sharesLeft, subId);
    }

    // Copy of subscribe() but with claimableThisPeriod set by the user
    // This is for users that have unsubscribed during the current period but want to subscribe again
    // If they call subscribe() they would have to pay for the remaining of the current period, which they have already paid for
    // This function allows them to delay the subscription till the beginning of the next period to avoid that
    // Also, it can be used for users that are upgrading their subscription
    // ---
    // This could be gas optimized by copying over the code of _subscribe() and removing operations associated with claimableThisPeriod
    // like setting receiverBalances[receiver].balance. This saves 200 gas for subscribe() and 3k gas for subscribeForNextPeriod()
    // However that adds a lot of code that could introduce bugs, and subscribeForNextPeriod() should be rarely called
    // So I don't think that optimization is worth the security trade-offs
    function subscribeForNextPeriod(address receiver, uint amountPerCycle, uint256 amountForFuture, uint256 instantPayment) external {
        _updateReceiver(receiver, block.timestamp);
        (uint expirationDate, uint256 sharesLeft, bytes32 subId) = _subscribe(receiver, amountPerCycle, amountForFuture, instantPayment);
        emit NewDelayedSubscription(msg.sender, currentPeriod, expirationDate, amountPerCycle, receiver, sharesAccumulator, sharesLeft, subId, instantPayment);
    }

    function unsubscribe(uint initialPeriod, uint expirationDate, uint amountPerCycle, address receiver, uint256 accumulator, uint256 initialShares) external {
        _updateGlobal(block.timestamp);
        bytes32 subId = getSubId(msg.sender, initialPeriod, expirationDate, amountPerCycle, receiver, accumulator, initialShares);
        require(subs[subId] == true, "sub doesn't exist");
        delete subs[subId];
        if(expirationDate >= block.timestamp){
            // Most common case, solved in O(1)
            uint sharesPaid = (sharesAccumulator - accumulator).mulDivUp(amountPerCycle, DIVISOR);
            // sharesLeft can underflow if either share price goes down or because of rounding
            // however that's fine because in those cases there's nothing left to withdraw
            uint sharesLeft = initialShares - sharesPaid;
            redeem(sharesLeft, msg.sender);
            receiverAmountToExpire[receiver][expirationDate] -= amountPerCycle;
            receiverAmountToExpire[receiver][currentPeriod] += amountPerCycle;
        } else {
            // Uncommon case, its just claiming yield generated after sub expired
            uint subsetAccumulator = 0;
            while(initialPeriod < expirationDate){
                subsetAccumulator += sharesPerPeriod[initialPeriod];
                initialPeriod += periodDuration;
            }
            redeem(initialShares - subsetAccumulator.mulDivUp(amountPerCycle, DIVISOR), msg.sender);
        }
        emit Unsubscribe(subId);
    }

    function claim(uint256 amount) external {
        _updateReceiver(msg.sender, block.timestamp);
        receiverBalances[msg.sender].balance -= amount;
        redeem((amount * 99) / 100, msg.sender);
        receiverBalances[feeCollector].balance += amount / 100;
    }
}

File 2 of 8 : BoringBatchable.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma experimental ABIEncoderV2;

// solhint-disable avoid-low-level-calls
// solhint-disable no-inline-assembly

// WARNING!!!
// Combining BoringBatchable with msg.value can cause double spending issues
// https://www.paradigm.xyz/2021/08/two-rights-might-make-a-wrong/

interface IERC20Permit{
     /// @notice EIP 2612
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;
}

contract BaseBoringBatchable {
    /// @dev Helper function to extract a useful revert message from a failed call.
    /// If the returned data is malformed or not correctly abi encoded then this call can fail itself.
    function _getRevertMsg(bytes memory _returnData) internal pure returns (string memory) {
        // If the _res length is less than 68, then the transaction failed silently (without a revert message)
        if (_returnData.length < 68) return "Transaction reverted silently";

        assembly {
            // Slice the sighash.
            _returnData := add(_returnData, 0x04)
        }
        return abi.decode(_returnData, (string)); // All that remains is the revert string
    }

    /// @notice Allows batched call to self (this contract).
    /// @param calls An array of inputs for each call.
    /// @param revertOnFail If True then reverts after a failed call and stops doing further calls.
    // F1: External is ok here because this is the batch function, adding it to a batch makes no sense
    // F2: Calls in the batch may be payable, delegatecall operates in the same context, so each call in the batch has access to msg.value
    // C3: The length of the loop is fully under user control, so can't be exploited
    // C7: Delegatecall is only used on the same contract, so it's safe
    function batch(bytes[] calldata calls, bool revertOnFail) external payable {
        for (uint256 i = 0; i < calls.length; i++) {
            (bool success, bytes memory result) = address(this).delegatecall(calls[i]);
            if (!success && revertOnFail) {
                revert(_getRevertMsg(result));
            }
        }
    }
}

contract BoringBatchable is BaseBoringBatchable {
    /// @notice Call wrapper that performs `ERC20.permit` on `token`.
    /// Lookup `IERC20.permit`.
    // F6: Parameters can be used front-run the permit and the user's permit will fail (due to nonce or other revert)
    //     if part of a batch this could be used to grief once as the second call would not need the permit
    function permitToken(
        IERC20Permit token,
        address from,
        address to,
        uint256 amount,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) public {
        token.permit(from, to, amount, deadline, v, r, s);
    }
}

File 3 of 8 : AaveV3Adapter.sol
pragma solidity ^0.8.19;

import {ERC20} from "solmate/src/tokens/ERC20.sol";
import {SafeTransferLib} from "solmate/src/utils/SafeTransferLib.sol";
import {FixedPointMathLib} from "solmate/src/utils/FixedPointMathLib.sol";
import {BaseAdapter} from "./BaseAdapter.sol";

interface IPool {
    function supply(address asset, uint256 amount, address onBehalfOf, uint16 referralCode) external;
    function withdraw(address asset, uint256 amount, address to) external returns (uint256);
}

interface AToken {
    function UNDERLYING_ASSET_ADDRESS() view external returns (address);
    function POOL() view external returns (address);
}

interface IRewardsController {
    function claimAllRewards(address[] calldata assets, address to) external
        returns (address[] memory rewardsList, uint256[] memory claimedAmounts);
}

contract AaveV3Adapter is BaseAdapter {
    ERC20 public immutable aToken;
    IPool public immutable lendingPool;
    IRewardsController public immutable rewardsController;

    constructor(
        address aToken_,
        address rewardRecipient_,
        address rewardsController_,
        uint minBalanceToTriggerDeposit_
    ) BaseAdapter(AToken(aToken_).UNDERLYING_ASSET_ADDRESS(), rewardRecipient_, minBalanceToTriggerDeposit_) {
        lendingPool = IPool(AToken(aToken_).POOL());
        aToken = ERC20(aToken_);
        rewardsController = IRewardsController(rewardsController_);
        asset.approve(address(lendingPool), type(uint256).max);
    }

    // If the rewards are donated back to the vault, this mechanism is vulnerable to an attack where someone joins the pool, rewards are distributed, and then he leaves
    // this would allow that attacker to steal a part of the yield from everyone else
    // We solve this by donating to the pool at random times and keeping the txs private so its impossible to predict when a donation will happen and deposit right before
    function claimRewards() external {
        require(msg.sender == rewardRecipient, "not rewardRecipient");
        address[] memory assets = new address[](1);
        assets[0] = address(aToken);
        rewardsController.claimAllRewards(assets, rewardRecipient);
    }

    function forceDeposit(uint assets) internal override {
        lendingPool.supply(address(asset), assets, address(this), 0);
    }

    function forceRedeem(uint assets, address receiver) internal override {
        lendingPool.withdraw(address(asset), assets, receiver);
    }

    function totalAssets() public view override returns (uint256) {
        return aToken.balanceOf(address(this)) + asset.balanceOf(address(this));
    }

    function refreshApproval() external override {
        asset.approve(address(lendingPool), 0);
        asset.approve(address(lendingPool), type(uint256).max);
    }
}

File 4 of 8 : BaseAdapter.sol
pragma solidity ^0.8.19;

import {ERC20} from "solmate/src/tokens/ERC20.sol";
import {SafeTransferLib} from "solmate/src/utils/SafeTransferLib.sol";
import {FixedPointMathLib} from "solmate/src/utils/FixedPointMathLib.sol";
import {Owned} from "solmate/src/auth/Owned.sol";

abstract contract BaseAdapter is Owned {
    using SafeTransferLib for ERC20;
    using FixedPointMathLib for uint256;

    ERC20 public immutable asset;
    address public rewardRecipient;
    uint public immutable DIVISOR; // This is just a constant to query convertToShares and then divide result, vault.convertToShares(DIVISOR) must never revert
    uint public totalSupply;
    uint public minBalanceToTriggerDeposit; // Threshold after which we'll trigger a deposit to yield source, also doubles as a pause button for new deposits if set to type(uint256).max

    constructor(
        address asset_,
        address rewardRecipient_,
        uint minBalanceToTriggerDeposit_
    ) Owned(msg.sender) {
        asset = ERC20(asset_);
        rewardRecipient = rewardRecipient_;
        DIVISOR = 10**asset.decimals(); // Even if decimals() changes later this will still work fine
        minBalanceToTriggerDeposit = minBalanceToTriggerDeposit_;
    }

    function setRewardRecipient(address _rewardRecipient) external onlyOwner() {
        rewardRecipient = _rewardRecipient;
    }

    function setMinBalanceToTriggerDeposit(uint _minBalanceToTriggerDeposit) external onlyOwner() {
        minBalanceToTriggerDeposit = _minBalanceToTriggerDeposit;
    }

    // Why is this not caller-restricted?
    // - forceDeposit() can be triggered anyway by making a deposit that increases balance enough, and then withdrawing it
    // - redeem() doesn't support withdrawing money from both asset and vault, so in the case where the last user wants to withdraw
    //    and only 50% of money is in the vault, owner could increase minBalanceToTriggerDeposit to max to prevent new vault deposits
    //    and prevent the user from getting the money, asking for a ransom. With this method user can simply call this to solve the situation
    function triggerDeposit(uint maxToPull) external {
        forceDepositAndCheck(asset.balanceOf(address(this)), msg.sender, maxToPull);
    }

    // In some cases totalAssets() after coins are deposited into the yield vault, this could be used in an attack so this function ensures this never happens
    function forceDepositAndCheck(uint amount, address receiver, uint maxToPull) internal {
        uint oldTotalAssets = totalAssets();
        forceDeposit(amount);
        uint newTotalAssets = totalAssets();
        if(newTotalAssets < oldTotalAssets){
            uint pullAmount = oldTotalAssets - newTotalAssets;
            require(pullAmount < maxToPull, ">maxToPull");
            asset.transferFrom(receiver, address(this), pullAmount);
        }
    }

    function forceDeposit(uint assets) internal virtual;

    // Yield buffer
    //   Most of the gas cost in calls to subscribe() comes moving the coins into the yield-generating vault
    //   For small subscriptions this means that users might end up paying more in gas costs than the yield they generate,
    //   so to greatly reduce gas costs and amortize them among all users we've implemented a yield buffer
    //   When new coins are deposited they'll be simply stored in the contract, with no extra gas costs,
    //   then, when enough coins accumulate (or when we trigger it), all coins will be moved to the yield vault, thus aggregating all these user deposits
    //   into a single large deposit for which we pay O(1) gas, thus amortizing costs.
    //   This means that some money will sit idle and not earn any yield, but thats ok because we can set an upper bound and make it a small % of total TVL.
    //   The min balance to trigger a deposit is configurable by owner so we can change it depending on gas costs, yield APYs and contract activity.
    //   This also applies for withdrawals, if we have enough money in the buffer we'll just use that so we don't have to pull money from vault
    function deposit(uint256 assets, uint256 amountPerCycle) internal returns (uint shares, uint cycles) {
        uint assetBalance = asset.balanceOf(address(this));
        uint newTotalAssets;
        require(minBalanceToTriggerDeposit < type(uint256).max, "paused"); // this only pauses new deposits, users can still withdraw all their money
        if(assetBalance > minBalanceToTriggerDeposit){
            // Handle cases where totalAssets() drops after a deposit into yield source
            uint oldTotalAssets = totalAssets();
            forceDeposit(assetBalance);
            newTotalAssets = totalAssets();
            if(newTotalAssets < oldTotalAssets){
                assets -= oldTotalAssets-newTotalAssets;
            }
        } else {
            newTotalAssets = totalAssets();
        }
        cycles = assets/amountPerCycle;
        shares = totalSupply == 0 ? assets : assets.mulDivDown(totalSupply, newTotalAssets - assets);
        totalSupply += shares;
    }

    function forceRedeem(uint assets, address receiver) internal virtual;

    function redeem(uint256 shares, address receiver) internal {
        uint assets = convertToAssets(shares);
        totalSupply -= shares;
        if(assets <= asset.balanceOf(address(this))){
            asset.safeTransfer(receiver, assets);
        } else {
            forceRedeem(assets, receiver);
        }
    }

    function totalAssets() public view virtual returns (uint256);

    function convertToShares(uint256 assets) public view returns (uint256) {
        uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero.

        return supply == 0 ? assets : assets.mulDivDown(supply, totalAssets());
    }

    function convertToAssets(uint256 shares) public view returns (uint256) {
        uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero.

        return supply == 0 ? shares : shares.mulDivDown(totalAssets(), supply);
    }

    function refreshApproval() external virtual;
}

File 5 of 8 : Owned.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @notice Simple single owner authorization mixin.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/auth/Owned.sol)
abstract contract Owned {
    /*//////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

    event OwnershipTransferred(address indexed user, address indexed newOwner);

    /*//////////////////////////////////////////////////////////////
                            OWNERSHIP STORAGE
    //////////////////////////////////////////////////////////////*/

    address public owner;

    modifier onlyOwner() virtual {
        require(msg.sender == owner, "UNAUTHORIZED");

        _;
    }

    /*//////////////////////////////////////////////////////////////
                               CONSTRUCTOR
    //////////////////////////////////////////////////////////////*/

    constructor(address _owner) {
        owner = _owner;

        emit OwnershipTransferred(address(0), _owner);
    }

    /*//////////////////////////////////////////////////////////////
                             OWNERSHIP LOGIC
    //////////////////////////////////////////////////////////////*/

    function transferOwnership(address newOwner) public virtual onlyOwner {
        owner = newOwner;

        emit OwnershipTransferred(msg.sender, newOwner);
    }
}

File 6 of 8 : ERC20.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol)
/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)
/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.
abstract contract ERC20 {
    /*//////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

    event Transfer(address indexed from, address indexed to, uint256 amount);

    event Approval(address indexed owner, address indexed spender, uint256 amount);

    /*//////////////////////////////////////////////////////////////
                            METADATA STORAGE
    //////////////////////////////////////////////////////////////*/

    string public name;

    string public symbol;

    uint8 public immutable decimals;

    /*//////////////////////////////////////////////////////////////
                              ERC20 STORAGE
    //////////////////////////////////////////////////////////////*/

    uint256 public totalSupply;

    mapping(address => uint256) public balanceOf;

    mapping(address => mapping(address => uint256)) public allowance;

    /*//////////////////////////////////////////////////////////////
                            EIP-2612 STORAGE
    //////////////////////////////////////////////////////////////*/

    uint256 internal immutable INITIAL_CHAIN_ID;

    bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;

    mapping(address => uint256) public nonces;

    /*//////////////////////////////////////////////////////////////
                               CONSTRUCTOR
    //////////////////////////////////////////////////////////////*/

    constructor(
        string memory _name,
        string memory _symbol,
        uint8 _decimals
    ) {
        name = _name;
        symbol = _symbol;
        decimals = _decimals;

        INITIAL_CHAIN_ID = block.chainid;
        INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
    }

    /*//////////////////////////////////////////////////////////////
                               ERC20 LOGIC
    //////////////////////////////////////////////////////////////*/

    function approve(address spender, uint256 amount) public virtual returns (bool) {
        allowance[msg.sender][spender] = amount;

        emit Approval(msg.sender, spender, amount);

        return true;
    }

    function transfer(address to, uint256 amount) public virtual returns (bool) {
        balanceOf[msg.sender] -= amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(msg.sender, to, amount);

        return true;
    }

    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) public virtual returns (bool) {
        uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.

        if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;

        balanceOf[from] -= amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(from, to, amount);

        return true;
    }

    /*//////////////////////////////////////////////////////////////
                             EIP-2612 LOGIC
    //////////////////////////////////////////////////////////////*/

    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) public virtual {
        require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED");

        // Unchecked because the only math done is incrementing
        // the owner's nonce which cannot realistically overflow.
        unchecked {
            address recoveredAddress = ecrecover(
                keccak256(
                    abi.encodePacked(
                        "\x19\x01",
                        DOMAIN_SEPARATOR(),
                        keccak256(
                            abi.encode(
                                keccak256(
                                    "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
                                ),
                                owner,
                                spender,
                                value,
                                nonces[owner]++,
                                deadline
                            )
                        )
                    )
                ),
                v,
                r,
                s
            );

            require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER");

            allowance[recoveredAddress][spender] = value;
        }

        emit Approval(owner, spender, value);
    }

    function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
        return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();
    }

    function computeDomainSeparator() internal view virtual returns (bytes32) {
        return
            keccak256(
                abi.encode(
                    keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
                    keccak256(bytes(name)),
                    keccak256("1"),
                    block.chainid,
                    address(this)
                )
            );
    }

    /*//////////////////////////////////////////////////////////////
                        INTERNAL MINT/BURN LOGIC
    //////////////////////////////////////////////////////////////*/

    function _mint(address to, uint256 amount) internal virtual {
        totalSupply += amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(address(0), to, amount);
    }

    function _burn(address from, uint256 amount) internal virtual {
        balanceOf[from] -= amount;

        // Cannot underflow because a user's balance
        // will never be larger than the total supply.
        unchecked {
            totalSupply -= amount;
        }

        emit Transfer(from, address(0), amount);
    }
}

File 7 of 8 : FixedPointMathLib.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @notice Arithmetic library with operations for fixed-point numbers.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol)
/// @author Inspired by USM (https://github.com/usmfum/USM/blob/master/contracts/WadMath.sol)
library FixedPointMathLib {
    /*//////////////////////////////////////////////////////////////
                    SIMPLIFIED FIXED POINT OPERATIONS
    //////////////////////////////////////////////////////////////*/

    uint256 internal constant MAX_UINT256 = 2**256 - 1;

    uint256 internal constant WAD = 1e18; // The scalar of ETH and most ERC20s.

    function mulWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulDivDown(x, y, WAD); // Equivalent to (x * y) / WAD rounded down.
    }

    function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulDivUp(x, y, WAD); // Equivalent to (x * y) / WAD rounded up.
    }

    function divWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulDivDown(x, WAD, y); // Equivalent to (x * WAD) / y rounded down.
    }

    function divWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulDivUp(x, WAD, y); // Equivalent to (x * WAD) / y rounded up.
    }

    /*//////////////////////////////////////////////////////////////
                    LOW LEVEL FIXED POINT OPERATIONS
    //////////////////////////////////////////////////////////////*/

    function mulDivDown(
        uint256 x,
        uint256 y,
        uint256 denominator
    ) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y))
            if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) {
                revert(0, 0)
            }

            // Divide x * y by the denominator.
            z := div(mul(x, y), denominator)
        }
    }

    function mulDivUp(
        uint256 x,
        uint256 y,
        uint256 denominator
    ) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y))
            if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) {
                revert(0, 0)
            }

            // If x * y modulo the denominator is strictly greater than 0,
            // 1 is added to round up the division of x * y by the denominator.
            z := add(gt(mod(mul(x, y), denominator), 0), div(mul(x, y), denominator))
        }
    }

    function rpow(
        uint256 x,
        uint256 n,
        uint256 scalar
    ) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            switch x
            case 0 {
                switch n
                case 0 {
                    // 0 ** 0 = 1
                    z := scalar
                }
                default {
                    // 0 ** n = 0
                    z := 0
                }
            }
            default {
                switch mod(n, 2)
                case 0 {
                    // If n is even, store scalar in z for now.
                    z := scalar
                }
                default {
                    // If n is odd, store x in z for now.
                    z := x
                }

                // Shifting right by 1 is like dividing by 2.
                let half := shr(1, scalar)

                for {
                    // Shift n right by 1 before looping to halve it.
                    n := shr(1, n)
                } n {
                    // Shift n right by 1 each iteration to halve it.
                    n := shr(1, n)
                } {
                    // Revert immediately if x ** 2 would overflow.
                    // Equivalent to iszero(eq(div(xx, x), x)) here.
                    if shr(128, x) {
                        revert(0, 0)
                    }

                    // Store x squared.
                    let xx := mul(x, x)

                    // Round to the nearest number.
                    let xxRound := add(xx, half)

                    // Revert if xx + half overflowed.
                    if lt(xxRound, xx) {
                        revert(0, 0)
                    }

                    // Set x to scaled xxRound.
                    x := div(xxRound, scalar)

                    // If n is even:
                    if mod(n, 2) {
                        // Compute z * x.
                        let zx := mul(z, x)

                        // If z * x overflowed:
                        if iszero(eq(div(zx, x), z)) {
                            // Revert if x is non-zero.
                            if iszero(iszero(x)) {
                                revert(0, 0)
                            }
                        }

                        // Round to the nearest number.
                        let zxRound := add(zx, half)

                        // Revert if zx + half overflowed.
                        if lt(zxRound, zx) {
                            revert(0, 0)
                        }

                        // Return properly scaled zxRound.
                        z := div(zxRound, scalar)
                    }
                }
            }
        }
    }

    /*//////////////////////////////////////////////////////////////
                        GENERAL NUMBER UTILITIES
    //////////////////////////////////////////////////////////////*/

    function sqrt(uint256 x) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            let y := x // We start y at x, which will help us make our initial estimate.

            z := 181 // The "correct" value is 1, but this saves a multiplication later.

            // This segment is to get a reasonable initial estimate for the Babylonian method. With a bad
            // start, the correct # of bits increases ~linearly each iteration instead of ~quadratically.

            // We check y >= 2^(k + 8) but shift right by k bits
            // each branch to ensure that if x >= 256, then y >= 256.
            if iszero(lt(y, 0x10000000000000000000000000000000000)) {
                y := shr(128, y)
                z := shl(64, z)
            }
            if iszero(lt(y, 0x1000000000000000000)) {
                y := shr(64, y)
                z := shl(32, z)
            }
            if iszero(lt(y, 0x10000000000)) {
                y := shr(32, y)
                z := shl(16, z)
            }
            if iszero(lt(y, 0x1000000)) {
                y := shr(16, y)
                z := shl(8, z)
            }

            // Goal was to get z*z*y within a small factor of x. More iterations could
            // get y in a tighter range. Currently, we will have y in [256, 256*2^16).
            // We ensured y >= 256 so that the relative difference between y and y+1 is small.
            // That's not possible if x < 256 but we can just verify those cases exhaustively.

            // Now, z*z*y <= x < z*z*(y+1), and y <= 2^(16+8), and either y >= 256, or x < 256.
            // Correctness can be checked exhaustively for x < 256, so we assume y >= 256.
            // Then z*sqrt(y) is within sqrt(257)/sqrt(256) of sqrt(x), or about 20bps.

            // For s in the range [1/256, 256], the estimate f(s) = (181/1024) * (s+1) is in the range
            // (1/2.84 * sqrt(s), 2.84 * sqrt(s)), with largest error when s = 1 and when s = 256 or 1/256.

            // Since y is in [256, 256*2^16), let a = y/65536, so that a is in [1/256, 256). Then we can estimate
            // sqrt(y) using sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2^18.

            // There is no overflow risk here since y < 2^136 after the first branch above.
            z := shr(18, mul(z, add(y, 65536))) // A mul() is saved from starting z at 181.

            // Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough.
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))
            z := shr(1, add(z, div(x, z)))

            // If x+1 is a perfect square, the Babylonian method cycles between
            // floor(sqrt(x)) and ceil(sqrt(x)). This statement ensures we return floor.
            // See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division
            // Since the ceil is rare, we save gas on the assignment and repeat division in the rare case.
            // If you don't care whether the floor or ceil square root is returned, you can remove this statement.
            z := sub(z, lt(div(x, z), z))
        }
    }

    function unsafeMod(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // Mod x by y. Note this will return
            // 0 instead of reverting if y is zero.
            z := mod(x, y)
        }
    }

    function unsafeDiv(uint256 x, uint256 y) internal pure returns (uint256 r) {
        /// @solidity memory-safe-assembly
        assembly {
            // Divide x by y. Note this will return
            // 0 instead of reverting if y is zero.
            r := div(x, y)
        }
    }

    function unsafeDivUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            // Add 1 to x * y if x % y > 0. Note this will
            // return 0 instead of reverting if y is zero.
            z := add(gt(mod(x, y), 0), div(x, y))
        }
    }
}

File 8 of 8 : SafeTransferLib.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

import {ERC20} from "../tokens/ERC20.sol";

/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)
/// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer.
/// @dev Note that none of the functions in this library check that a token has code at all! That responsibility is delegated to the caller.
library SafeTransferLib {
    /*//////////////////////////////////////////////////////////////
                             ETH OPERATIONS
    //////////////////////////////////////////////////////////////*/

    function safeTransferETH(address to, uint256 amount) internal {
        bool success;

        /// @solidity memory-safe-assembly
        assembly {
            // Transfer the ETH and store if it succeeded or not.
            success := call(gas(), to, amount, 0, 0, 0, 0)
        }

        require(success, "ETH_TRANSFER_FAILED");
    }

    /*//////////////////////////////////////////////////////////////
                            ERC20 OPERATIONS
    //////////////////////////////////////////////////////////////*/

    function safeTransferFrom(
        ERC20 token,
        address from,
        address to,
        uint256 amount
    ) internal {
        bool success;

        /// @solidity memory-safe-assembly
        assembly {
            // Get a pointer to some free memory.
            let freeMemoryPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
            mstore(add(freeMemoryPointer, 4), and(from, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "from" argument.
            mstore(add(freeMemoryPointer, 36), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.
            mstore(add(freeMemoryPointer, 68), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.

            success := and(
                // Set success to whether the call reverted, if not we check it either
                // returned exactly 1 (can't just be non-zero data), or had no return data.
                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
                // We use 100 because the length of our calldata totals up like so: 4 + 32 * 3.
                // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
                // Counterintuitively, this call must be positioned second to the or() call in the
                // surrounding and() call or else returndatasize() will be zero during the computation.
                call(gas(), token, 0, freeMemoryPointer, 100, 0, 32)
            )
        }

        require(success, "TRANSFER_FROM_FAILED");
    }

    function safeTransfer(
        ERC20 token,
        address to,
        uint256 amount
    ) internal {
        bool success;

        /// @solidity memory-safe-assembly
        assembly {
            // Get a pointer to some free memory.
            let freeMemoryPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)
            mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.
            mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.

            success := and(
                // Set success to whether the call reverted, if not we check it either
                // returned exactly 1 (can't just be non-zero data), or had no return data.
                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
                // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
                // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
                // Counterintuitively, this call must be positioned second to the or() call in the
                // surrounding and() call or else returndatasize() will be zero during the computation.
                call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
            )
        }

        require(success, "TRANSFER_FAILED");
    }

    function safeApprove(
        ERC20 token,
        address to,
        uint256 amount
    ) internal {
        bool success;

        /// @solidity memory-safe-assembly
        assembly {
            // Get a pointer to some free memory.
            let freeMemoryPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000)
            mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.
            mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.

            success := and(
                // Set success to whether the call reverted, if not we check it either
                // returned exactly 1 (can't just be non-zero data), or had no return data.
                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
                // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
                // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
                // Counterintuitively, this call must be positioned second to the or() call in the
                // surrounding and() call or else returndatasize() will be zero during the computation.
                call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
            )
        }

        require(success, "APPROVE_FAILED");
    }
}

Settings
{
  "evmVersion": "paris",
  "libraries": {},
  "metadata": {
    "bytecodeHash": "ipfs",
    "useLiteralContent": true
  },
  "optimizer": {
    "enabled": true,
    "runs": 4294967
  },
  "remappings": [],
  "viaIR": true,
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  }
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"uint256","name":"_periodDuration","type":"uint256"},{"internalType":"address","name":"_vault","type":"address"},{"internalType":"address","name":"_feeCollector","type":"address"},{"internalType":"uint256","name":"_currentPeriod","type":"uint256"},{"internalType":"address","name":"rewardRecipient_","type":"address"},{"internalType":"address","name":"stakingRewards_","type":"address"},{"internalType":"uint256","name":"minBalanceToTriggerDeposit_","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"initialPeriod","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"expirationDate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountPerCycle","type":"uint256"},{"indexed":false,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"accumulator","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"initialShares","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"subId","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"instantPayment","type":"uint256"}],"name":"NewDelayedSubscription","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"initialPeriod","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"expirationDate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountPerCycle","type":"uint256"},{"indexed":false,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"accumulator","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"initialShares","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"subId","type":"bytes32"}],"name":"NewSubscription","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"subId","type":"bytes32"}],"name":"Unsubscribe","type":"event"},{"inputs":[],"name":"DIVISOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"aToken","outputs":[{"internalType":"contract ERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"asset","outputs":[{"internalType":"contract ERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"calls","type":"bytes[]"},{"internalType":"bool","name":"revertOnFail","type":"bool"}],"name":"batch","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"convertToAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"convertToShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentPeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeCollector","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"initialPeriod","type":"uint256"},{"internalType":"uint256","name":"expirationDate","type":"uint256"},{"internalType":"uint256","name":"amountPerCycle","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"accumulator","type":"uint256"},{"internalType":"uint256","name":"initialShares","type":"uint256"}],"name":"getSubId","outputs":[{"internalType":"bytes32","name":"id","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"lendingPool","outputs":[{"internalType":"contract IPool","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minBalanceToTriggerDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"limit","type":"uint256"}],"name":"partialUpdateReceiver","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"periodDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20Permit","name":"token","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permitToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"receiverAmountToExpire","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"receiverBalances","outputs":[{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"amountPerPeriod","type":"uint256"},{"internalType":"uint256","name":"lastUpdate","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"refreshApproval","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rewardRecipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardsController","outputs":[{"internalType":"contract IRewardsController","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_minBalanceToTriggerDeposit","type":"uint256"}],"name":"setMinBalanceToTriggerDeposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_rewardRecipient","type":"address"}],"name":"setRewardRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"sharesAccumulator","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"sharesPerPeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"subs","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"amountPerCycle","type":"uint256"},{"internalType":"uint256","name":"amountForFuture","type":"uint256"}],"name":"subscribe","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"amountPerCycle","type":"uint256"},{"internalType":"uint256","name":"amountForFuture","type":"uint256"},{"internalType":"uint256","name":"instantPayment","type":"uint256"}],"name":"subscribeForNextPeriod","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"totalAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"maxToPull","type":"uint256"}],"name":"triggerDeposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"initialPeriod","type":"uint256"},{"internalType":"uint256","name":"expirationDate","type":"uint256"},{"internalType":"uint256","name":"amountPerCycle","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"accumulator","type":"uint256"},{"internalType":"uint256","name":"initialShares","type":"uint256"}],"name":"unsubscribe","outputs":[],"stateMutability":"nonpayable","type":"function"}]

610160604081815234620002bd5760e0826200301180380380916200002582856200041e565b833981010312620002bd578151906020906200004382850162000458565b916200005182860162000458565b92606086015191620000666080880162000458565b9160c06200007760a08a0162000458565b98015185516358b50cef60e11b81526004946001600160a01b039384169392919085828881885afa9182156200041357849287928992600092620003cb575b5060008054336001600160a01b0319918216811783558e5197889695879594919283927f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a31692836080521690600154161760015563313ce56760e01b82525afa908115620003c0576000916200037d575b5060ff16604d81116200036857600a0a60a0526003558551633a9ae92360e11b815283818681865afa9081156200035d576000916200030d575b50916044828594936000969416928360e05260c052806101009c168c5260805116918851958693849263095ea7b360e01b845289840152811960248401525af1801562000302579084939291620002c2575b505061012095865255421115620002bd576101409182525191612ba393846200046e8539608051848181610477015281816109a101528181610f7101528181611ce1015281816123a00152818161256c01528181612659015281816127e201526128b8015260a0518481816107260152818161155c01528181611692015281816119760152611aaa015260c0518481816107b101528181610de10152612355015260e051848181610e5001528181610f3b0152818161251101526128ea01525183818161082f0152610c1801525182818161062901528181610eaa01528181611631015281816118fd01528181611a700152611d1d01525181818161090401526111130152f35b600080fd5b9080929350813d8311620002fa575b620002dd81836200041e565b81010312620002bd575180151503620002bd5781903880620001b6565b503d620002d1565b85513d6000823e3d90fd5b908482813d831162000355575b6200032681836200041e565b8101031262000352575091604482859493620003456000979562000458565b9395505092945062000164565b80fd5b503d6200031a565b87513d6000823e3d90fd5b601186634e487b7160e01b6000525260246000fd5b8581813d8311620003b8575b6200039581836200041e565b81010312620003b457519060ff8216820362000352575060ff6200012a565b5080fd5b503d62000389565b88513d6000823e3d90fd5b9384919550809293503d83116200040b575b620003e981836200041e565b810103126200035257508387819362000403899462000458565b9192620000b6565b503d620003dd565b89513d6000823e3d90fd5b601f909101601f19168101906001600160401b038211908210176200044257604052565b634e487b7160e01b600052604160045260246000fd5b51906001600160a01b0382168203620002bd5756fe6080604052600436101561001257600080fd5b60003560e01c806301e1d11414610237578063060406181461023257806307a2d13a1461022d5780631468026d1461022857806317f333401461022357806318160ddd1461021e57806319d10f09146102195780631ac805411461021457806322d4a1751461020f5780633410fe6e1461020a578063372500ab14610205578063379607f51461020057806338d52e0f146101fb578063535a05e2146101f65780635fb030c1146101f157806363076b53146101ec5780636b82b985146101e75780636bb65f53146101e25780637c516e94146101dd5780638da5cb5b146101d8578063a0c1f15e146101d3578063a59a9973146101ce578063b470aade146101c9578063bf33a1f5146101c4578063c0d672c0146101bf578063c415b95c146101ba578063c6e6f592146101b5578063cd4216f5146101b0578063d2423b51146101ab578063d4cfe597146101a6578063d8dc8be8146101a1578063dd6748361461019c578063e521136f146101975763f2fde38b1461019257600080fd5b61177e565b6116ef565b611437565b61138a565b611330565b6111b9565b611173565b611137565b6110c8565b611051565b610ecd565b610e74565b610e05565b610d96565b610d44565b610c3c565b610bcd565b610b7e565b610aab565b610a2b565b6109c5565b610956565b610882565b610749565b6106f0565b6105db565b610419565b6103cf565b610393565b610341565b610305565b6102c9565b61028d565b61024c565b600091031261024757565b600080fd5b346102475760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610247576020610285612307565b604051908152f35b346102475760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610247576020600454604051908152f35b346102475760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261024757602061028560043561294c565b346102475760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610247576020600554604051908152f35b346102475760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261024757602073ffffffffffffffffffffffffffffffffffffffff60015416604051908152f35b346102475760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610247576020600254604051908152f35b346102475760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102475760043560005260086020526020604060002054604051908152f35b34610247576020807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610247576040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168282602481845afa9182156105845760009261058e575b506104d56104cf612307565b926124f9565b6104dd612307565b8281106104e657005b82039182116105895761054d83916000936105046004358210612494565b6040517f23b872dd000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481019190915293849283919082906064820190565b03925af180156105845761055e575b005b8161055c92903d1061057d575b6105758183611bb7565b81019061241a565b503d61056b565b6120aa565b611833565b6105af919250833d85116105b6575b6105a78183611bb7565b8101906122f8565b90386104c3565b503d61059d565b73ffffffffffffffffffffffffffffffffffffffff81160361024757565b346102475760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261024757600435610616816105bd565b60243561062342836118c8565b600454907f00000000000000000000000000000000000000000000000000000000000000009182810180911161058957428103908111610589577f4eea731ae1fda3da326d839452cf98ef0b814e2e0c09bc8122100e44c4f0649b936106b76106ad610100956106a873ffffffffffffffffffffffffffffffffffffffff958761187c565b61188f565b6044358584611ccb565b93909260045495600554936040519733895260208901526040880152606087015216608085015260a084015260c083015260e0820152a1005b346102475760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102475760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b34610247576000807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261087f5761082b8173ffffffffffffffffffffffffffffffffffffffff8060015416906107a38233146120b6565b6107ab612133565b6107f5827f0000000000000000000000000000000000000000000000000000000000000000166107da8361214d565b9073ffffffffffffffffffffffffffffffffffffffff169052565b836040518096819582947fbb492bf500000000000000000000000000000000000000000000000000000000845260048401612287565b03927f0000000000000000000000000000000000000000000000000000000000000000165af180156105845761085f575080f35b61087a903d8084833e6108728183611bb7565b8101906121e7565b505080f35b80fd5b346102475760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610247576004356108be42336118c8565b336000526007602052604060002080549082820391821161058957556063810281810460631482151715610589576108fa90606433910461279a565b61095260646109497f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166000526007602052604060002090565b92048254611862565b9055005b346102475760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261024757602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346102475760e07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610247576020610285600435610a05816105bd565b60843590610a12826105bd565b60c4359160a43591606435906044359060243590611bf8565b346102475760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102475773ffffffffffffffffffffffffffffffffffffffff600435610a7b816105bd565b16600052600760205260606040600020805490600260018201549101549060405192835260208301526040820152f35b346102475760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610247577f11bab01132823da8b48084f6ff9218de015cdce052fb4e35672e33d1142ee340610120600435610b0a816105bd565b6024359073ffffffffffffffffffffffffffffffffffffffff60643591610b3142826118c8565b610b3f836044358684611ccb565b939092600454966005549360405198338a5260208a01526040890152606088015216608086015260a085015260c084015260e0830152610100820152a1005b346102475760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610247576004356000526009602052602060ff604060002054166040519015158152f35b346102475760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261024757602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b34610247576101007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261024757600435610c78816105bd565b602435610c84816105bd565b60443591610c91836105bd565b60a4359160ff83168093036102475773ffffffffffffffffffffffffffffffffffffffff80921690813b1561024757600060e49281958560405198899788967fd505accf00000000000000000000000000000000000000000000000000000000885216600487015216602485015260643560448501526084356064850152608484015260c43560a4840152833560c48401525af1801561058457610d3157005b80610d3e61055c92611b82565b8061023c565b346102475760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261024757602073ffffffffffffffffffffffffffffffffffffffff60005416604051908152f35b346102475760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261024757602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346102475760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261024757602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346102475760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102475760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b34610247576000807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261087f576040517f095ea7b30000000000000000000000000000000000000000000000000000000080825273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000008116600484018190526000602485015260209392917f000000000000000000000000000000000000000000000000000000000000000016848460448189855af192831561058457611005948694611034575b508660405180968195829483526004830160207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9193929373ffffffffffffffffffffffffffffffffffffffff60408201951681520152565b03925af1801561058457611017578280f35b8161102d92903d1061057d576105758183611bb7565b5038808280f35b61104a90853d871161057d576105758183611bb7565b5038610fac565b346102475760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102475773ffffffffffffffffffffffffffffffffffffffff6004356110a1816105bd565b16600052600660205260406000206024356000526020526020604060002054604051908152f35b346102475760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261024757602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346102475760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610247576020610285600435612933565b346102475760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610247576020600354604051908152f35b8015150361024757565b6040807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102475767ffffffffffffffff90600480358381116102475736602382011215610247578082013593808511610247576024600595368282891b86010111610247579581359361122f856111af565b6000917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbd82360301925b89811061126257005b8481831b8401013584811215610247578301858101359087821161024757604401813603811361024757600091829161129f8d5180938193611f0d565b0390305af46112ac611f55565b901580611329575b6112e857507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff811461058957600101611259565b886113256112f68c93611ff2565b92519283927f08c379a00000000000000000000000000000000000000000000000000000000084528301611fa8565b0390fd5b50876112b4565b346102475760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102475761138273ffffffffffffffffffffffffffffffffffffffff60005416331461242f565b600435600355005b346102475760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610247576004356113c5816105bd565b602435428110156113d95761055c916118c8565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f6c696d697420746f6f20626967000000000000000000000000000000000000006044820152fd5b346102475760c07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102475760643560043560443560243561147b846105bd565b60a43560843561149982828887878a61149342611a69565b33611bf8565b946114c560016114bd6114b6896000526009602052604060002090565b5460ff1690565b151514611ea8565b6115046114dc876000526009602052604060002090565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008154169055565b42841061162957506115f87f893fd01daa6afc79c31ef343da6349fe3770d6be153aebf639378d0f1c69795e966115c561162497969561158c611611966115876115536116099860055461186f565b9161158133938c7f00000000000000000000000000000000000000000000000000000000000000009161299a565b9061186f565b61279a565b6115b68373ffffffffffffffffffffffffffffffffffffffff166000526006602052604060002090565b90600052602052604060002090565b6115d086825461186f565b905573ffffffffffffffffffffffffffffffffffffffff166000526006602052604060002090565b600454600052602052604060002090565b918254611862565b90555b6040519081529081906020820190565b0390a1005b6000965091927f000000000000000000000000000000000000000000000000000000000000000091505b8083106116bc5750505061162492916115876116b7926115817f893fd01daa6afc79c31ef343da6349fe3770d6be153aebf639378d0f1c69795e9733947f00000000000000000000000000000000000000000000000000000000000000009161299a565b611614565b909195826116e26116e8926116db8a6000526008602052604060002090565b5490611862565b97611862565b9190611653565b346102475760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102475760043561172a816105bd565b73ffffffffffffffffffffffffffffffffffffffff9061174f8260005416331461242f565b167fffffffffffffffffffffffff00000000000000000000000000000000000000006001541617600155600080f35b346102475760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610247576004356117b9816105bd565b7fffffffffffffffffffffffff000000000000000000000000000000000000000060009182549073ffffffffffffffffffffffffffffffffffffffff90611803828416331461242f565b1691829116178255337f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08380a380f35b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b9190820180921161058957565b9190820391821161058957565b8181029291811591840414171561058957565b8115611899570490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6118f28173ffffffffffffffffffffffffffffffffffffffff166000526007602052604060002090565b9160028301918254937f0000000000000000000000000000000000000000000000000000000000000000906119278287611862565b4211611936575b505050505050565b61193f84611a69565b8561195a575050600454935050505b5538808080808061192e565b8054916001908180840195611973875498600454611b42565b827f0000000000000000000000000000000000000000000000000000000000000000935b6119a9575b505050505050555561194e565b9a84979991929394959b15611a47575b600091816119e78673ffffffffffffffffffffffffffffffffffffffff166000526006602052604060002090565b600091825260205260409020546119fd9161186f565b9985611a13836000526008602052604060002090565b54611a1e908d61187c565b90611a289161188f565b611a3191611862565b97611a3b91611862565b9a949392919085611997565b90918093949550811015611a60579086949392916119b9565b9981989661199c565b60048054907f000000000000000000000000000000000000000000000000000000000000000091828101809111610589574211611aa557505050565b611ace7f0000000000000000000000000000000000000000000000000000000000000000612933565b92600180805b611ae057505050505050565b15611b2a575b60009085611aff85546000526008602052604060002090565b55835485810180911161058957600455611b23611b1e87600554611862565b600555565b9081611ad4565b8254848101809111610589578211611ae6578061192e565b81811115611b4e575090565b905090565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b67ffffffffffffffff8111611b9657604052565b611b53565b6040810190811067ffffffffffffffff821117611b9657604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117611b9657604052565b9194929593909560405195602087019773ffffffffffffffffffffffffffffffffffffffff80951689526040880152606087015260808601521660a084015260c083015260e082015260e08152610100810181811067ffffffffffffffff821117611b965760405251902090565b15611c6d57565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f6475706c696361746564207375620000000000000000000000000000000000006044820152fd5b9093918381019081811161058957611d058230337f00000000000000000000000000000000000000000000000000000000000000006129d6565b81611d108782612621565b60045491929190611d41907f000000000000000000000000000000000000000000000000000000000000000061187c565b611d4a91611862565b9687611d768773ffffffffffffffffffffffffffffffffffffffff166000526006602052604060002090565b60009182526020526040902089815490611d8f91611862565b9055611dbb8673ffffffffffffffffffffffffffffffffffffffff166000526007602052604060002090565b60010189815490611dcb91611862565b9055611dd7908361187c565b90611de19161188f565b611e0b8573ffffffffffffffffffffffffffffffffffffffff166000526007602052604060002090565b90815490611e1891611862565b9055611e239161187c565b90611e2d9161188f565b80946004549260055491863395611e4396611bf8565b91611e58836000526009602052604060002090565b5460ff1615611e6690611c66565b611e7a836000526009602052604060002090565b80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055929190565b15611eaf57565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f73756220646f65736e27742065786973740000000000000000000000000000006044820152fd5b908092918237016000815290565b67ffffffffffffffff8111611b9657601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b3d15611f80573d90611f6682611f1b565b91611f746040519384611bb7565b82523d6000602084013e565b606090565b60005b838110611f985750506000910152565b8181015183820152602001611f88565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f60409360208452611feb8151809281602088015260208888019101611f85565b0116010190565b6044815110612070576004810151810190602081602484019303126102475760248101519067ffffffffffffffff821161024757018160438201121561024757602481015161204081611f1b565b9261204e6040519485611bb7565b818452604482840101116102475761206d916044602085019101611f85565b90565b5060405161207d81611b9b565b601d81527f5472616e73616374696f6e2072657665727465642073696c656e746c79000000602082015290565b6040513d6000823e3d90fd5b156120bd57565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f6e6f7420726577617264526563697069656e74000000000000000000000000006044820152fd5b67ffffffffffffffff8111611b965760051b60200190565b6040519061214082611b9b565b6001825260203681840137565b80511561215a5760200190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b81601f82011215610247578051916121a08361211b565b926121ae6040519485611bb7565b808452602092838086019260051b820101928311610247578301905b8282106121d8575050505090565b815181529083019083016121ca565b9190916040818403126102475780519267ffffffffffffffff938481116102475782019381601f860112156102475784516122218161211b565b9061222f6040519283611bb7565b808252602096878084019260051b820101918583116102475788809201905b83821061226e5750505050948301519081116102475761206d9201612189565b828091835161227c816105bd565b81520191019061224e565b90929192604082016040835281518091526060830160208093019160005b848282106122ce5750505073ffffffffffffffffffffffffffffffffffffffff91509416910152565b845173ffffffffffffffffffffffffffffffffffffffff16845293840193909201916001016122a5565b90816020910312610247575190565b6040517f70a082310000000000000000000000000000000000000000000000000000000080825230600483015260209173ffffffffffffffffffffffffffffffffffffffff919083816024817f000000000000000000000000000000000000000000000000000000000000000087165afa9182156105845784916000936123fb575b5060405190815230600482015292839060249082907f0000000000000000000000000000000000000000000000000000000000000000165afa9182156105845761206d936000936123dc575b5050611862565b6123f3929350803d106105b6576105a78183611bb7565b9038806123d5565b612413919350823d84116105b6576105a78183611bb7565b9138612389565b90816020910312610247575161206d816111af565b1561243657565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152fd5b1561249b57565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600a60248201527f3e6d6178546f50756c6c000000000000000000000000000000000000000000006044820152fd5b73ffffffffffffffffffffffffffffffffffffffff807f00000000000000000000000000000000000000000000000000000000000000001691823b156102475760846000928360405195869485937f617ba0370000000000000000000000000000000000000000000000000000000085527f000000000000000000000000000000000000000000000000000000000000000016600485015260248401523060448401528160648401525af18015610584576125b15750565b6125ba90611b82565b565b156125c357565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600660248201527f70617573656400000000000000000000000000000000000000000000000000006044820152fd5b6040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152909290916020836024817f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff165afa9283156105845760009361277a575b506003546126ce7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82106125bc565b831115612761576126e66126e0612307565b936124f9565b6126ee612307565b92808410612740575b506127236127096125ba925b8661188f565b9360025495868015600014612728575090505b8095611862565b600255565b6127358261273b9461186f565b91612966565b61271c565b6127096127586125ba9396611581876127239561186f565b959250506126f7565b91506125ba612723612709612774612307565b94612703565b61279391935060203d81116105b6576105a78183611bb7565b913861269f565b6127a38161294c565b90600254908103908111610589576002556040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201527f0000000000000000000000000000000000000000000000000000000000000000929060208160248173ffffffffffffffffffffffffffffffffffffffff88165afa9081156105845760009161284c575b508211612841576125ba92612aa6565b906125ba925061286a565b612864915060203d81116105b6576105a78183611bb7565b38612831565b600091606460209260405194859384927f69328dec00000000000000000000000000000000000000000000000000000000845273ffffffffffffffffffffffffffffffffffffffff918291827f000000000000000000000000000000000000000000000000000000000000000016600487015260248601521660448401527f0000000000000000000000000000000000000000000000000000000000000000165af18015610584576129195750565b6129309060203d81116105b6576105a78183611bb7565b50565b6002548061293f575090565b9061206d91612735612307565b60025480612958575090565b61206d91612964612307565b905b817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04811182021583021561024757020490565b817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048111820215830215610247570290808204910615150190565b9160008093602095606494604051947f23b872dd00000000000000000000000000000000000000000000000000000000865273ffffffffffffffffffffffffffffffffffffffff809216600487015216602485015260448401525af13d15601f3d1160016000511416171615612a4857565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5452414e534645525f46524f4d5f4641494c45440000000000000000000000006044820152fd5b6000918260449260209573ffffffffffffffffffffffffffffffffffffffff604051947fa9059cbb00000000000000000000000000000000000000000000000000000000865216600485015260248401525af13d15601f3d1160016000511416171615612b0f57565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5452414e534645525f4641494c454400000000000000000000000000000000006044820152fdfea2646970667358221220ba98d175866b13becef4b0b1df219101001b2a68e8bf7f3c8ebb3c7f651c0b2a64736f6c63430008130033000000000000000000000000000000000000000000000000000000000001518000000000000000000000000082e64f49ed5ec1bc6e43dad4fc8af9bb3a2312ee0000000000000000000000009fe36b2d3cc3fb56f35225c2912ee5283464842e00000000000000000000000000000000000000000000000000000000653094e80000000000000000000000009fe36b2d3cc3fb56f35225c2912ee5283464842e000000000000000000000000929ec64c34a17401f460460d4b9390518e5b473e00000000000000000000000000000000000000000000003635c9adc5dea00000

Deployed Bytecode

0x6080604052600436101561001257600080fd5b60003560e01c806301e1d11414610237578063060406181461023257806307a2d13a1461022d5780631468026d1461022857806317f333401461022357806318160ddd1461021e57806319d10f09146102195780631ac805411461021457806322d4a1751461020f5780633410fe6e1461020a578063372500ab14610205578063379607f51461020057806338d52e0f146101fb578063535a05e2146101f65780635fb030c1146101f157806363076b53146101ec5780636b82b985146101e75780636bb65f53146101e25780637c516e94146101dd5780638da5cb5b146101d8578063a0c1f15e146101d3578063a59a9973146101ce578063b470aade146101c9578063bf33a1f5146101c4578063c0d672c0146101bf578063c415b95c146101ba578063c6e6f592146101b5578063cd4216f5146101b0578063d2423b51146101ab578063d4cfe597146101a6578063d8dc8be8146101a1578063dd6748361461019c578063e521136f146101975763f2fde38b1461019257600080fd5b61177e565b6116ef565b611437565b61138a565b611330565b6111b9565b611173565b611137565b6110c8565b611051565b610ecd565b610e74565b610e05565b610d96565b610d44565b610c3c565b610bcd565b610b7e565b610aab565b610a2b565b6109c5565b610956565b610882565b610749565b6106f0565b6105db565b610419565b6103cf565b610393565b610341565b610305565b6102c9565b61028d565b61024c565b600091031261024757565b600080fd5b346102475760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610247576020610285612307565b604051908152f35b346102475760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610247576020600454604051908152f35b346102475760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261024757602061028560043561294c565b346102475760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610247576020600554604051908152f35b346102475760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261024757602073ffffffffffffffffffffffffffffffffffffffff60015416604051908152f35b346102475760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610247576020600254604051908152f35b346102475760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102475760043560005260086020526020604060002054604051908152f35b34610247576020807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610247576040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201527f000000000000000000000000da10009cbd5d07dd0cecc66161fc93d7c9000da173ffffffffffffffffffffffffffffffffffffffff168282602481845afa9182156105845760009261058e575b506104d56104cf612307565b926124f9565b6104dd612307565b8281106104e657005b82039182116105895761054d83916000936105046004358210612494565b6040517f23b872dd000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481019190915293849283919082906064820190565b03925af180156105845761055e575b005b8161055c92903d1061057d575b6105758183611bb7565b81019061241a565b503d61056b565b6120aa565b611833565b6105af919250833d85116105b6575b6105a78183611bb7565b8101906122f8565b90386104c3565b503d61059d565b73ffffffffffffffffffffffffffffffffffffffff81160361024757565b346102475760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261024757600435610616816105bd565b60243561062342836118c8565b600454907f00000000000000000000000000000000000000000000000000000000000151809182810180911161058957428103908111610589577f4eea731ae1fda3da326d839452cf98ef0b814e2e0c09bc8122100e44c4f0649b936106b76106ad610100956106a873ffffffffffffffffffffffffffffffffffffffff958761187c565b61188f565b6044358584611ccb565b93909260045495600554936040519733895260208901526040880152606087015216608085015260a084015260c083015260e0820152a1005b346102475760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102475760206040517f0000000000000000000000000000000000000000000000000de0b6b3a76400008152f35b34610247576000807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261087f5761082b8173ffffffffffffffffffffffffffffffffffffffff8060015416906107a38233146120b6565b6107ab612133565b6107f5827f00000000000000000000000082e64f49ed5ec1bc6e43dad4fc8af9bb3a2312ee166107da8361214d565b9073ffffffffffffffffffffffffffffffffffffffff169052565b836040518096819582947fbb492bf500000000000000000000000000000000000000000000000000000000845260048401612287565b03927f000000000000000000000000929ec64c34a17401f460460d4b9390518e5b473e165af180156105845761085f575080f35b61087a903d8084833e6108728183611bb7565b8101906121e7565b505080f35b80fd5b346102475760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610247576004356108be42336118c8565b336000526007602052604060002080549082820391821161058957556063810281810460631482151715610589576108fa90606433910461279a565b61095260646109497f0000000000000000000000009fe36b2d3cc3fb56f35225c2912ee5283464842e73ffffffffffffffffffffffffffffffffffffffff166000526007602052604060002090565b92048254611862565b9055005b346102475760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261024757602060405173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000da10009cbd5d07dd0cecc66161fc93d7c9000da1168152f35b346102475760e07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610247576020610285600435610a05816105bd565b60843590610a12826105bd565b60c4359160a43591606435906044359060243590611bf8565b346102475760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102475773ffffffffffffffffffffffffffffffffffffffff600435610a7b816105bd565b16600052600760205260606040600020805490600260018201549101549060405192835260208301526040820152f35b346102475760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610247577f11bab01132823da8b48084f6ff9218de015cdce052fb4e35672e33d1142ee340610120600435610b0a816105bd565b6024359073ffffffffffffffffffffffffffffffffffffffff60643591610b3142826118c8565b610b3f836044358684611ccb565b939092600454966005549360405198338a5260208a01526040890152606088015216608086015260a085015260c084015260e0830152610100820152a1005b346102475760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610247576004356000526009602052602060ff604060002054166040519015158152f35b346102475760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261024757602060405173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000929ec64c34a17401f460460d4b9390518e5b473e168152f35b34610247576101007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261024757600435610c78816105bd565b602435610c84816105bd565b60443591610c91836105bd565b60a4359160ff83168093036102475773ffffffffffffffffffffffffffffffffffffffff80921690813b1561024757600060e49281958560405198899788967fd505accf00000000000000000000000000000000000000000000000000000000885216600487015216602485015260643560448501526084356064850152608484015260c43560a4840152833560c48401525af1801561058457610d3157005b80610d3e61055c92611b82565b8061023c565b346102475760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261024757602073ffffffffffffffffffffffffffffffffffffffff60005416604051908152f35b346102475760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261024757602060405173ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000082e64f49ed5ec1bc6e43dad4fc8af9bb3a2312ee168152f35b346102475760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261024757602060405173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000794a61358d6845594f94dc1db02a252b5b4814ad168152f35b346102475760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102475760206040517f00000000000000000000000000000000000000000000000000000000000151808152f35b34610247576000807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261087f576040517f095ea7b30000000000000000000000000000000000000000000000000000000080825273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000794a61358d6845594f94dc1db02a252b5b4814ad8116600484018190526000602485015260209392917f000000000000000000000000da10009cbd5d07dd0cecc66161fc93d7c9000da116848460448189855af192831561058457611005948694611034575b508660405180968195829483526004830160207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9193929373ffffffffffffffffffffffffffffffffffffffff60408201951681520152565b03925af1801561058457611017578280f35b8161102d92903d1061057d576105758183611bb7565b5038808280f35b61104a90853d871161057d576105758183611bb7565b5038610fac565b346102475760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102475773ffffffffffffffffffffffffffffffffffffffff6004356110a1816105bd565b16600052600660205260406000206024356000526020526020604060002054604051908152f35b346102475760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261024757602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000009fe36b2d3cc3fb56f35225c2912ee5283464842e168152f35b346102475760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610247576020610285600435612933565b346102475760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610247576020600354604051908152f35b8015150361024757565b6040807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102475767ffffffffffffffff90600480358381116102475736602382011215610247578082013593808511610247576024600595368282891b86010111610247579581359361122f856111af565b6000917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbd82360301925b89811061126257005b8481831b8401013584811215610247578301858101359087821161024757604401813603811361024757600091829161129f8d5180938193611f0d565b0390305af46112ac611f55565b901580611329575b6112e857507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff811461058957600101611259565b886113256112f68c93611ff2565b92519283927f08c379a00000000000000000000000000000000000000000000000000000000084528301611fa8565b0390fd5b50876112b4565b346102475760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102475761138273ffffffffffffffffffffffffffffffffffffffff60005416331461242f565b600435600355005b346102475760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610247576004356113c5816105bd565b602435428110156113d95761055c916118c8565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f6c696d697420746f6f20626967000000000000000000000000000000000000006044820152fd5b346102475760c07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102475760643560043560443560243561147b846105bd565b60a43560843561149982828887878a61149342611a69565b33611bf8565b946114c560016114bd6114b6896000526009602052604060002090565b5460ff1690565b151514611ea8565b6115046114dc876000526009602052604060002090565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008154169055565b42841061162957506115f87f893fd01daa6afc79c31ef343da6349fe3770d6be153aebf639378d0f1c69795e966115c561162497969561158c611611966115876115536116099860055461186f565b9161158133938c7f0000000000000000000000000000000000000000000000000de0b6b3a76400009161299a565b9061186f565b61279a565b6115b68373ffffffffffffffffffffffffffffffffffffffff166000526006602052604060002090565b90600052602052604060002090565b6115d086825461186f565b905573ffffffffffffffffffffffffffffffffffffffff166000526006602052604060002090565b600454600052602052604060002090565b918254611862565b90555b6040519081529081906020820190565b0390a1005b6000965091927f000000000000000000000000000000000000000000000000000000000001518091505b8083106116bc5750505061162492916115876116b7926115817f893fd01daa6afc79c31ef343da6349fe3770d6be153aebf639378d0f1c69795e9733947f0000000000000000000000000000000000000000000000000de0b6b3a76400009161299a565b611614565b909195826116e26116e8926116db8a6000526008602052604060002090565b5490611862565b97611862565b9190611653565b346102475760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102475760043561172a816105bd565b73ffffffffffffffffffffffffffffffffffffffff9061174f8260005416331461242f565b167fffffffffffffffffffffffff00000000000000000000000000000000000000006001541617600155600080f35b346102475760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610247576004356117b9816105bd565b7fffffffffffffffffffffffff000000000000000000000000000000000000000060009182549073ffffffffffffffffffffffffffffffffffffffff90611803828416331461242f565b1691829116178255337f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08380a380f35b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b9190820180921161058957565b9190820391821161058957565b8181029291811591840414171561058957565b8115611899570490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6118f28173ffffffffffffffffffffffffffffffffffffffff166000526007602052604060002090565b9160028301918254937f0000000000000000000000000000000000000000000000000000000000015180906119278287611862565b4211611936575b505050505050565b61193f84611a69565b8561195a575050600454935050505b5538808080808061192e565b8054916001908180840195611973875498600454611b42565b827f0000000000000000000000000000000000000000000000000de0b6b3a7640000935b6119a9575b505050505050555561194e565b9a84979991929394959b15611a47575b600091816119e78673ffffffffffffffffffffffffffffffffffffffff166000526006602052604060002090565b600091825260205260409020546119fd9161186f565b9985611a13836000526008602052604060002090565b54611a1e908d61187c565b90611a289161188f565b611a3191611862565b97611a3b91611862565b9a949392919085611997565b90918093949550811015611a60579086949392916119b9565b9981989661199c565b60048054907f000000000000000000000000000000000000000000000000000000000001518091828101809111610589574211611aa557505050565b611ace7f0000000000000000000000000000000000000000000000000de0b6b3a7640000612933565b92600180805b611ae057505050505050565b15611b2a575b60009085611aff85546000526008602052604060002090565b55835485810180911161058957600455611b23611b1e87600554611862565b600555565b9081611ad4565b8254848101809111610589578211611ae6578061192e565b81811115611b4e575090565b905090565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b67ffffffffffffffff8111611b9657604052565b611b53565b6040810190811067ffffffffffffffff821117611b9657604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117611b9657604052565b9194929593909560405195602087019773ffffffffffffffffffffffffffffffffffffffff80951689526040880152606087015260808601521660a084015260c083015260e082015260e08152610100810181811067ffffffffffffffff821117611b965760405251902090565b15611c6d57565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f6475706c696361746564207375620000000000000000000000000000000000006044820152fd5b9093918381019081811161058957611d058230337f000000000000000000000000da10009cbd5d07dd0cecc66161fc93d7c9000da16129d6565b81611d108782612621565b60045491929190611d41907f000000000000000000000000000000000000000000000000000000000001518061187c565b611d4a91611862565b9687611d768773ffffffffffffffffffffffffffffffffffffffff166000526006602052604060002090565b60009182526020526040902089815490611d8f91611862565b9055611dbb8673ffffffffffffffffffffffffffffffffffffffff166000526007602052604060002090565b60010189815490611dcb91611862565b9055611dd7908361187c565b90611de19161188f565b611e0b8573ffffffffffffffffffffffffffffffffffffffff166000526007602052604060002090565b90815490611e1891611862565b9055611e239161187c565b90611e2d9161188f565b80946004549260055491863395611e4396611bf8565b91611e58836000526009602052604060002090565b5460ff1615611e6690611c66565b611e7a836000526009602052604060002090565b80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055929190565b15611eaf57565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f73756220646f65736e27742065786973740000000000000000000000000000006044820152fd5b908092918237016000815290565b67ffffffffffffffff8111611b9657601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b3d15611f80573d90611f6682611f1b565b91611f746040519384611bb7565b82523d6000602084013e565b606090565b60005b838110611f985750506000910152565b8181015183820152602001611f88565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f60409360208452611feb8151809281602088015260208888019101611f85565b0116010190565b6044815110612070576004810151810190602081602484019303126102475760248101519067ffffffffffffffff821161024757018160438201121561024757602481015161204081611f1b565b9261204e6040519485611bb7565b818452604482840101116102475761206d916044602085019101611f85565b90565b5060405161207d81611b9b565b601d81527f5472616e73616374696f6e2072657665727465642073696c656e746c79000000602082015290565b6040513d6000823e3d90fd5b156120bd57565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f6e6f7420726577617264526563697069656e74000000000000000000000000006044820152fd5b67ffffffffffffffff8111611b965760051b60200190565b6040519061214082611b9b565b6001825260203681840137565b80511561215a5760200190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b81601f82011215610247578051916121a08361211b565b926121ae6040519485611bb7565b808452602092838086019260051b820101928311610247578301905b8282106121d8575050505090565b815181529083019083016121ca565b9190916040818403126102475780519267ffffffffffffffff938481116102475782019381601f860112156102475784516122218161211b565b9061222f6040519283611bb7565b808252602096878084019260051b820101918583116102475788809201905b83821061226e5750505050948301519081116102475761206d9201612189565b828091835161227c816105bd565b81520191019061224e565b90929192604082016040835281518091526060830160208093019160005b848282106122ce5750505073ffffffffffffffffffffffffffffffffffffffff91509416910152565b845173ffffffffffffffffffffffffffffffffffffffff16845293840193909201916001016122a5565b90816020910312610247575190565b6040517f70a082310000000000000000000000000000000000000000000000000000000080825230600483015260209173ffffffffffffffffffffffffffffffffffffffff919083816024817f00000000000000000000000082e64f49ed5ec1bc6e43dad4fc8af9bb3a2312ee87165afa9182156105845784916000936123fb575b5060405190815230600482015292839060249082907f000000000000000000000000da10009cbd5d07dd0cecc66161fc93d7c9000da1165afa9182156105845761206d936000936123dc575b5050611862565b6123f3929350803d106105b6576105a78183611bb7565b9038806123d5565b612413919350823d84116105b6576105a78183611bb7565b9138612389565b90816020910312610247575161206d816111af565b1561243657565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152fd5b1561249b57565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600a60248201527f3e6d6178546f50756c6c000000000000000000000000000000000000000000006044820152fd5b73ffffffffffffffffffffffffffffffffffffffff807f000000000000000000000000794a61358d6845594f94dc1db02a252b5b4814ad1691823b156102475760846000928360405195869485937f617ba0370000000000000000000000000000000000000000000000000000000085527f000000000000000000000000da10009cbd5d07dd0cecc66161fc93d7c9000da116600485015260248401523060448401528160648401525af18015610584576125b15750565b6125ba90611b82565b565b156125c357565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600660248201527f70617573656400000000000000000000000000000000000000000000000000006044820152fd5b6040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152909290916020836024817f000000000000000000000000da10009cbd5d07dd0cecc66161fc93d7c9000da173ffffffffffffffffffffffffffffffffffffffff165afa9283156105845760009361277a575b506003546126ce7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82106125bc565b831115612761576126e66126e0612307565b936124f9565b6126ee612307565b92808410612740575b506127236127096125ba925b8661188f565b9360025495868015600014612728575090505b8095611862565b600255565b6127358261273b9461186f565b91612966565b61271c565b6127096127586125ba9396611581876127239561186f565b959250506126f7565b91506125ba612723612709612774612307565b94612703565b61279391935060203d81116105b6576105a78183611bb7565b913861269f565b6127a38161294c565b90600254908103908111610589576002556040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201527f000000000000000000000000da10009cbd5d07dd0cecc66161fc93d7c9000da1929060208160248173ffffffffffffffffffffffffffffffffffffffff88165afa9081156105845760009161284c575b508211612841576125ba92612aa6565b906125ba925061286a565b612864915060203d81116105b6576105a78183611bb7565b38612831565b600091606460209260405194859384927f69328dec00000000000000000000000000000000000000000000000000000000845273ffffffffffffffffffffffffffffffffffffffff918291827f000000000000000000000000da10009cbd5d07dd0cecc66161fc93d7c9000da116600487015260248601521660448401527f000000000000000000000000794a61358d6845594f94dc1db02a252b5b4814ad165af18015610584576129195750565b6129309060203d81116105b6576105a78183611bb7565b50565b6002548061293f575090565b9061206d91612735612307565b60025480612958575090565b61206d91612964612307565b905b817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04811182021583021561024757020490565b817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048111820215830215610247570290808204910615150190565b9160008093602095606494604051947f23b872dd00000000000000000000000000000000000000000000000000000000865273ffffffffffffffffffffffffffffffffffffffff809216600487015216602485015260448401525af13d15601f3d1160016000511416171615612a4857565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5452414e534645525f46524f4d5f4641494c45440000000000000000000000006044820152fd5b6000918260449260209573ffffffffffffffffffffffffffffffffffffffff604051947fa9059cbb00000000000000000000000000000000000000000000000000000000865216600485015260248401525af13d15601f3d1160016000511416171615612b0f57565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5452414e534645525f4641494c454400000000000000000000000000000000006044820152fdfea2646970667358221220ba98d175866b13becef4b0b1df219101001b2a68e8bf7f3c8ebb3c7f651c0b2a64736f6c63430008130033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

000000000000000000000000000000000000000000000000000000000001518000000000000000000000000082e64f49ed5ec1bc6e43dad4fc8af9bb3a2312ee0000000000000000000000009fe36b2d3cc3fb56f35225c2912ee5283464842e00000000000000000000000000000000000000000000000000000000653094e80000000000000000000000009fe36b2d3cc3fb56f35225c2912ee5283464842e000000000000000000000000929ec64c34a17401f460460d4b9390518e5b473e00000000000000000000000000000000000000000000003635c9adc5dea00000

-----Decoded View---------------
Arg [0] : _periodDuration (uint256): 86400
Arg [1] : _vault (address): 0x82E64f49Ed5EC1bC6e43DAD4FC8Af9bb3A2312EE
Arg [2] : _feeCollector (address): 0x9fE36b2d3cC3Fb56F35225c2912EE5283464842e
Arg [3] : _currentPeriod (uint256): 1697682664
Arg [4] : rewardRecipient_ (address): 0x9fE36b2d3cC3Fb56F35225c2912EE5283464842e
Arg [5] : stakingRewards_ (address): 0x929EC64c34a17401F460460D4B9390518E5B473e
Arg [6] : minBalanceToTriggerDeposit_ (uint256): 1000000000000000000000

-----Encoded View---------------
7 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000015180
Arg [1] : 00000000000000000000000082e64f49ed5ec1bc6e43dad4fc8af9bb3a2312ee
Arg [2] : 0000000000000000000000009fe36b2d3cc3fb56f35225c2912ee5283464842e
Arg [3] : 00000000000000000000000000000000000000000000000000000000653094e8
Arg [4] : 0000000000000000000000009fe36b2d3cc3fb56f35225c2912ee5283464842e
Arg [5] : 000000000000000000000000929ec64c34a17401f460460d4b9390518e5b473e
Arg [6] : 00000000000000000000000000000000000000000000003635c9adc5dea00000


Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Txn Hash Block Value Eth2 PubKey Valid
View All Deposits
[ 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.