ETH Price: $3,333.77 (+3.92%)

Contract

0x167c606be99DBf5A8aF61E1983E5B309e8FA2Ae7
 
Transaction Hash
Method
Block
From
To
Withdraw215503242025-01-04 9:49:4712 days ago1735984187IN
0x167c606b...9e8FA2Ae7
0 ETH0.001853317.2
Withdraw214284622024-12-18 9:16:1129 days ago1734513371IN
0x167c606b...9e8FA2Ae7
0 ETH0.0030373711.8
Withdraw212146092024-11-18 12:29:2358 days ago1731932963IN
0x167c606b...9e8FA2Ae7
0 ETH0.0027102210.52903663
Withdraw211286702024-11-06 12:40:3570 days ago1730896835IN
0x167c606b...9e8FA2Ae7
0 ETH0.0055350520.53534996
Withdraw207581562024-09-15 19:37:47122 days ago1726429067IN
0x167c606b...9e8FA2Ae7
0 ETH0.000709922.75824809
Deposit204695652024-08-06 12:35:11162 days ago1722947711IN
0x167c606b...9e8FA2Ae7
0 ETH0.000915643.38363129
Withdraw203939202024-07-26 23:11:11173 days ago1722035471IN
0x167c606b...9e8FA2Ae7
0 ETH0.000474221.46307188
Withdraw200703392024-06-11 18:20:35218 days ago1718130035IN
0x167c606b...9e8FA2Ae7
0 ETH0.0032446912.6053997
Withdraw197063882024-04-21 21:12:35269 days ago1713733955IN
0x167c606b...9e8FA2Ae7
0 ETH0.001966567.16404328
Withdraw196060042024-04-07 19:50:23283 days ago1712519423IN
0x167c606b...9e8FA2Ae7
0 ETH0.0041077415.23996168
Withdraw193007432024-02-24 23:31:47326 days ago1708817507IN
0x167c606b...9e8FA2Ae7
0 ETH0.005148120
Withdraw192479792024-02-17 13:48:59333 days ago1708177739IN
0x167c606b...9e8FA2Ae7
0 ETH0.005420821.05943921
Withdraw192113592024-02-12 10:29:59338 days ago1707733799IN
0x167c606b...9e8FA2Ae7
0 ETH0.0052337820.33286726
Withdraw191671202024-02-06 5:28:23345 days ago1707197303IN
0x167c606b...9e8FA2Ae7
0 ETH0.0042954416.68749231
Withdraw190007422024-01-13 21:46:11368 days ago1705182371IN
0x167c606b...9e8FA2Ae7
0 ETH0.0039619414.69901742
Withdraw189705152024-01-09 16:11:59372 days ago1704816719IN
0x167c606b...9e8FA2Ae7
0 ETH0.0059203123
Withdraw189091362024-01-01 0:49:23381 days ago1704070163IN
0x167c606b...9e8FA2Ae7
0 ETH0.0029990211.1985032
Withdraw189069582023-12-31 17:30:59381 days ago1704043859IN
0x167c606b...9e8FA2Ae7
0 ETH0.0044759218.76124976
Withdraw187694162023-12-12 10:09:11400 days ago1702375751IN
0x167c606b...9e8FA2Ae7
0 ETH0.0147912424.43714694
Withdraw186055552023-11-19 11:27:23423 days ago1700393243IN
0x167c606b...9e8FA2Ae7
0 ETH0.0105181217.37765569
Withdraw183772082023-10-18 12:22:23455 days ago1697631743IN
0x167c606b...9e8FA2Ae7
0 ETH0.010289717
Withdraw183444362023-10-13 22:25:35460 days ago1697235935IN
0x167c606b...9e8FA2Ae7
0 ETH0.004752987.85257252
Withdraw182087232023-09-24 22:46:11479 days ago1695595571IN
0x167c606b...9e8FA2Ae7
0 ETH0.004206437
Approve182085652023-09-24 22:14:35479 days ago1695593675IN
0x167c606b...9e8FA2Ae7
0 ETH0.000371328
Deposit182085612023-09-24 22:13:47479 days ago1695593627IN
0x167c606b...9e8FA2Ae7
0 ETH0.005391588.64444522
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:
DullahanVault

Compiler Version
v0.8.16+commit.07a7930e

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 13 : DullahanVault.sol
//██████╗  █████╗ ██╗      █████╗ ██████╗ ██╗███╗   ██╗
//██╔══██╗██╔══██╗██║     ██╔══██╗██╔══██╗██║████╗  ██║
//██████╔╝███████║██║     ███████║██║  ██║██║██╔██╗ ██║
//██╔═══╝ ██╔══██║██║     ██╔══██║██║  ██║██║██║╚██╗██║
//██║     ██║  ██║███████╗██║  ██║██████╔╝██║██║ ╚████║
//╚═╝     ╚═╝  ╚═╝╚══════╝╚═╝  ╚═╝╚═════╝ ╚═╝╚═╝  ╚═══╝


pragma solidity 0.8.16;
//SPDX-License-Identifier: BUSL-1.1

import "./base/ScalingERC20.sol";
import "./interfaces/IERC4626.sol";
import "./oz/interfaces/IERC20.sol";
import "./oz/libraries/SafeERC20.sol";
import "./oz/utils/ReentrancyGuard.sol";
import "./oz/utils/Pausable.sol";
import "./interfaces/IStakedAave.sol";
import "./interfaces/IGovernancePowerDelegationToken.sol";
import {Errors} from "./utils/Errors.sol";
import {WadRayMath} from  "./utils/WadRayMath.sol";

/** @title DullahanVault contract
 *  @author Paladin
 *  @notice Main Dullahan Vault. IERC4626 compatible & ScalingERC20 token
 */
contract DullahanVault is IERC4626, ScalingERC20, ReentrancyGuard, Pausable {
    using SafeERC20 for IERC20;
    using WadRayMath for uint256;

    // Constants

    /** @notice Max value for BPS - 100% */
    uint256 public constant MAX_BPS = 10000;
    /** @notice Max value possible for an uint256 */
    uint256 public constant MAX_UINT256 = 2**256 - 1;

    /** @notice Amount to deposit to seed the Vault during initialization */
    uint256 private constant SEED_DEPOSIT = 0.001 ether;

    /** @notice Address of the stkAAVE token */
    address public immutable STK_AAVE;
    /** @notice Address of the AAVE token */
    address public immutable AAVE;


    // Struct

    /** @notice PodsManager struct 
    *   rentingAllowed: Is the Manager allowed to rent from the Vault
    *   totalRented: Total amount rented to the Manager (based on the AAVE max total supply, should be safe)
    */
    struct PodsManager {
        bool rentingAllowed;
        uint248 totalRented;
    }


    // Storage

    /** @notice Is the Vault initialized */
    bool public initialized;

    /** @notice Address of the Vault admin */
    address public admin;
    /** @notice Address of the Vault pending admin */
    address public pendingAdmin;

    /** @notice Total amount of stkAAVE rented to Pod Managers */
    uint256 public totalRentedAmount;

    /** @notice Pod Manager states */
    mapping(address => PodsManager) public podManagers;

    /** @notice Address receiving the delegated voting power from the Vault */
    address public votingPowerManager;
    /** @notice Address receiving the delegated proposal power from the Vault */
    address public proposalPowerManager;

    /** @notice Percentage of funds to stay in the contract for withdraws */
    uint256 public bufferRatio = 500;

    /** @notice Amount accrued as Reserve */
    uint256 public reserveAmount;
    /** @notice Ratio of claimed rewards to be set as Reserve */
    uint256 public reserveRatio;
    /** @notice Address of the Reserve Manager */
    address public reserveManager;


    // Events

    /** @notice Event emitted when the Vault is initialized */
    event Initialized();

    /** @notice Event emitted when stkAAVE is rented to a Pod */
    event RentToPod(address indexed manager, address indexed pod, uint256 amount);
    /** @notice Event emitted when stkAAVE claim is notified by a Pod */
    event NotifyRentedAmount(address indexed manager, address indexed pod, uint256 addedAmount);
    /** @notice Event emitted when stkAAVE is pulled back from a Pod */
    event PullFromPod(address indexed manager, address indexed pod, uint256 amount);

    /** @notice Event emitted when the adminship is transfered */
    event AdminTransferred(
        address indexed previousAdmin,
        address indexed newAdmin
    );
    /** @notice Event emitted when a new pending admin is set */
    event NewPendingAdmin(
        address indexed previousPendingAdmin,
        address indexed newPendingAdmin
    );

    /** @notice Event emitted when a new Pod Manager is added */
    event NewPodManager(address indexed newManager);
    /** @notice Event emitted when a Pod Manager is blocked */
    event BlockedPodManager(address indexed manager);

    /** @notice Event emitted when depositing in the Reserve */
    event ReserveDeposit(address indexed from, uint256 amount);
    /** @notice Event emitted when withdrawing from the Reserve */
    event ReserveWithdraw(address indexed to, uint256 amount);

    /** @notice Event emitted when the Voting maanger is updated */
    event UpdatedVotingPowerManager(address indexed oldManager, address indexed newManager);
    /** @notice Event emitted when the Proposal maanger is updated */
    event UpdatedProposalPowerManager(address indexed oldManager, address indexed newManager);
    /** @notice Event emitted when the Reserve manager is updated */
    event UpdatedReserveManager(address indexed oldManager, address indexed newManager);
    /** @notice Event emitted when the Buffer ratio is updated */
    event UpdatedBufferRatio(uint256 oldRatio, uint256 newRatio);
    /** @notice Event emitted when the Reserve ratio is updated */
    event UpdatedReserveRatio(uint256 oldRatio, uint256 newRatio);

    /** @notice Event emitted when an ERC20 token is recovered */
    event TokenRecovered(address indexed token, uint256 amount);


    // Modifers

    /** @notice Check that the caller is the admin */
    modifier onlyAdmin() {
        if (msg.sender != admin) revert Errors.CallerNotAdmin();
        _;
    }

    /** @notice Check that the caller is the admin or the Reserve maanger */
    modifier onlyAllowed() {
        if (msg.sender != admin && msg.sender != reserveManager) revert Errors.CallerNotAdmin();
        _;
    }

    /** @notice Check that the contract is initialized */
    modifier isInitialized() {
        if (!initialized) revert Errors.NotInitialized();
        _;
    }


    // Constructor

    constructor(
        address _admin,
        uint256 _reserveRatio,
        address _reserveManager,
        address _aave,
        address _stkAave,
        string memory _name,
        string memory _symbol
    ) ScalingERC20(_name, _symbol) {
        if(_admin == address(0) || _reserveManager == address(0) || _aave == address(0) || _stkAave == address(0)) revert Errors.AddressZero();
        if(_reserveRatio == 0) revert Errors.NullAmount();

        admin = _admin;

        reserveRatio = _reserveRatio;
        reserveManager = _reserveManager;

        AAVE = _aave;
        STK_AAVE = _stkAave;
    }

    /**
    * @notice Initialize the Vault
    * @dev Initialize the Vault by performing a seed deposit & delegating voting power
    * @param _votingPowerManager Address to receive the voting power delegation
    * @param _proposalPowerManager Address to receive the proposal power delegation
    */
    function init(address _votingPowerManager, address _proposalPowerManager) external onlyAdmin {
        if(initialized) revert Errors.AlreadyInitialized();

        initialized = true;

        votingPowerManager = _votingPowerManager;
        proposalPowerManager = _proposalPowerManager;

        // Seed deposit to prevent 1 wei LP token exploit
        _deposit(
            SEED_DEPOSIT,
            msg.sender,
            msg.sender
        );

        // Set the delegates, so any received token updates the delegates power
        IGovernancePowerDelegationToken(STK_AAVE).delegateByType(
            _votingPowerManager,
            IGovernancePowerDelegationToken.DelegationType.VOTING_POWER
        );
        IGovernancePowerDelegationToken(STK_AAVE).delegateByType(
            _proposalPowerManager,
            IGovernancePowerDelegationToken.DelegationType.PROPOSITION_POWER
        );

        emit Initialized();
    }


    // View functions

    /**
    * @notice Get the vault's asset
    * @return address : Address of the asset
    */
    function asset() external view returns (address) {
        return STK_AAVE;
    }

    /**
    * @notice Get the total amount of assets in the Vault
    * @return uint256 : total amount of assets
    */
    function totalAssets() public view returns (uint256) {
        return
            IERC20(STK_AAVE).balanceOf(address(this)) +
            totalRentedAmount -
            reserveAmount;
    }

    /**
    * @notice Get the total supply of shares
    * @return uint256 : Total supply of shares
    */
    function totalSupply()
        public
        view
        override(ScalingERC20, IERC20)
        returns (uint256)
    {
        return totalAssets();
    }

    /**
    * @notice Get the current total amount of asset available in the Vault
    * @return uint256 : Current total amount available
    */
    function totalAvailable() public view returns (uint256) {
        uint256 availableBalance = IERC20(STK_AAVE).balanceOf(address(this));
        availableBalance = reserveAmount >= availableBalance ? 0 : availableBalance - reserveAmount;
        uint256 bufferAmount = (totalAssets() * bufferRatio) / MAX_BPS;
        return availableBalance > bufferAmount ? availableBalance - bufferAmount : 0;
    }

    /**
    * @notice Convert a given amount of assets to shares
    * @param assets amount of assets
    * @return uint256 : amount of shares
    */
    function convertToShares(uint256 assets) public pure returns (uint256) {
        // Because we use a ScalingERC20, shares of the user will grow over time to match the owed assets
        // (assets & shares are always 1:1)
        return assets;
    }

    /**
    * @notice Convert a given amount of shares to assets
    * @param shares amount of shares
    * @return uint256 : amount of assets
    */
    function convertToAssets(uint256 shares) public pure returns (uint256) {
        // Because we use a ScalingERC20, shares of the user will grow over time to match the owed assets
        // (assets & shares are always 1:1)
        return shares;
    }

    /**
    * @notice Return the amount of shares expected for depositing the given assets
    * @param assets Amount of assets to be deposited
    * @return uint256 : amount of shares
    */
    function previewDeposit(uint256 assets) public pure returns (uint256) {
        // Because we use a ScalingERC20, shares of the user will grow over time to match the owed assets
        // (assets & shares are always 1:1)
        return assets;
    }

    /**
    * @notice Return the amount of assets expected for minting the given shares
    * @param shares Amount of shares to be minted
    * @return uint256 : amount of assets
    */
    function previewMint(uint256 shares) public pure returns (uint256) {
        // Because we use a ScalingERC20, shares of the user will grow over time to match the owed assets
        // (assets & shares are always 1:1)
        return shares;
    }

    /**
    * @notice Return the amount of shares expected for withdrawing the given assets
    * @param assets Amount of assets to be withdrawn
    * @return uint256 : amount of shares
    */
    function previewWithdraw(uint256 assets) public pure returns (uint256) {
        // Because we use a ScalingERC20, shares of the user will grow over time to match the owed assets
        // (assets & shares are always 1:1)
        return assets;
    }

    /**
    * @notice Return the amount of assets expected for burning the given shares
    * @param shares Amount of shares to be burned
    * @return uint256 : amount of assets
    */
    function previewRedeem(uint256 shares) public pure returns (uint256) {
        // Because we use a ScalingERC20, shares of the user will grow over time to match the owed assets
        // (assets & shares are always 1:1)
        return shares;
    }

    /**
    * @notice Get the maximum amount that can be deposited by the user
    * @param user User address
    * @return uint256 : Max amount to deposit
    */
    function maxDeposit(address user) public view returns (uint256) {
        return type(uint256).max;
    }

    /**
    * @notice Get the maximum amount that can be minted by the user
    * @param user User address
    * @return uint256 : Max amount to mint
    */
    function maxMint(address user) public view returns (uint256) {
        return type(uint256).max;
    }

    /**
    * @notice Get the maximum amount that can be withdrawn by the user
    * @param owner Owner address
    * @return uint256 : Max amount to withdraw
    */
    function maxWithdraw(address owner) public view returns (uint256) {
        return balanceOf(owner);
    }

    /**
    * @notice Get the maximum amount that can be burned by the user
    * @param owner Owner address
    * @return uint256 : Max amount to burn
    */
    function maxRedeem(address owner) public view returns (uint256) {
        return balanceOf(owner);
    }

    /**
    * @notice Get the current index to convert between balance and scaled balances
    * @return uint256 : Current index
    */
    function getCurrentIndex() public view returns(uint256) {
        return _getCurrentIndex();
    }

    /**
    * @notice Get the current delegates for the Vault voting power & proposal power
    */
    function getDelegates() external view returns(address votingPower, address proposalPower) {
        return (votingPowerManager, proposalPowerManager);
    }


    // State-changing functions

    /**
    * @notice Deposit assets in the Vault & mint shares
    * @param assets Amount to deposit
    * @param receiver Address to receive the shares
    * @return shares - uint256 : Amount of shares minted
    */
    function deposit(
        uint256 assets,
        address receiver
    ) public isInitialized nonReentrant whenNotPaused returns (uint256 shares) {
        (assets, shares) = _deposit(assets, receiver, msg.sender);

        emit Deposit(msg.sender, receiver, assets, shares);
    }

    /**
    * @notice Mint vault shares by depositing assets
    * @param shares Amount of shares to mint
    * @param receiver Address to receive the shares
    * @return assets - uint256 : Amount of assets deposited
    */
    function mint(
        uint256 shares,
        address receiver
        ) public isInitialized nonReentrant whenNotPaused returns (uint256 assets) {
        (assets, shares) = _deposit(shares, receiver, msg.sender);

        emit Deposit(msg.sender, receiver, assets, shares);
    }

    /**
    * @notice Withdraw from the Vault & burn shares
    * @param assets Amount of assets to withdraw
    * @param receiver Address to receive the assets
    * @param owner Address of the owner of the shares
    * @return shares - uint256 : Amount of shares burned
    */
    function withdraw(
        uint256 assets,
        address receiver,
        address owner
    ) public isInitialized nonReentrant returns (uint256 shares) {
        (uint256 _withdrawn, uint256 _burntShares) = _withdraw(
            assets,
            owner,
            receiver,
            msg.sender
        );

        emit Withdraw(msg.sender, receiver, owner, _withdrawn, _burntShares);
        return _burntShares;
    }

    /**
    * @notice Burn shares to withdraw from the Vault
    * @param shares Amount of shares to burn
    * @param receiver Address to receive the assets
    * @param owner Address of the owner of the shares
    * @return assets - uint256 : Amount of assets withdrawn
    */
    function redeem(
        uint256 shares,
        address receiver,
        address owner
    ) public isInitialized nonReentrant returns (uint256 assets) {
        (uint256 _withdrawn, uint256 _burntShares) = _withdraw(
            shares,
            owner,
            receiver,
            msg.sender
        );

        emit Withdraw(msg.sender, receiver, owner, _withdrawn, _burntShares);
        return _withdrawn;
    }

    /**
    * @notice Claim Safety Module rewards & stake them in stkAAVE
    */
    function updateStkAaveRewards() external nonReentrant {
        _getStkAaveRewards();
    }


    // Pods Manager functions

    /**
    * @notice Rent stkAAVE for a Pod
    * @dev Rent stkAAVE to a Pod, sending the amount & tracking the manager that requested 
    * @param pod Address of the Pod
    * @param amount Amount to rent
    */
    function rentStkAave(address pod, uint256 amount) external nonReentrant {
        address manager = msg.sender;
        if(!podManagers[manager].rentingAllowed) revert Errors.CallerNotAllowedManager();
        if(pod == address(0)) revert Errors.AddressZero();
        if(amount == 0) revert Errors.NullAmount();

        // Fetch Aave Safety Module rewards & stake them into stkAAVE
        _getStkAaveRewards();

        IERC20 _stkAave = IERC20(STK_AAVE);

        // Check that the asked amount is available :
        // - Vault has enough asset for the asked amount
        // - Asked amount does not include the buffer allocated to withdraws
        uint256 availableBalance = _stkAave.balanceOf(address(this));
        availableBalance = reserveAmount >= availableBalance ? 0 : availableBalance - reserveAmount;
        uint256 bufferAmount = (totalAssets() * bufferRatio) / MAX_BPS;
        if(availableBalance < bufferAmount) revert Errors.WithdrawBuffer();
        if(amount > (availableBalance - bufferAmount)) revert Errors.NotEnoughAvailableFunds();

        // Track the amount rented for the manager that requested it
        // & send the token to the Pod
        podManagers[manager].totalRented += safe248(amount);
        totalRentedAmount += amount;
        _stkAave.safeTransfer(pod, amount);
    
        emit RentToPod(manager, pod, amount);
    }

    /**
    * @notice Notify a claim on rented stkAAVE
    * @dev Notify the newly claimed rewards from rented stkAAVE to a Pod & add it as rented to the Pod
    * @param pod Address of the Pod
    * @param addedAmount Amount added
    */
    // To track pods stkAave claims & re-stake into the main balance for ScalingeRC20 logic
    function notifyRentedAmount(address pod, uint256 addedAmount) external nonReentrant {
        address manager = msg.sender;
        if(podManagers[manager].totalRented == 0) revert Errors.NotUndebtedManager();
        if(pod == address(0)) revert Errors.AddressZero();
        if(addedAmount == 0) revert Errors.NullAmount();

        // Update the total amount rented & the amount rented for the specific
        // maanger with the amount claimed from Aave's Safety Module via the Pod
        podManagers[manager].totalRented += safe248(addedAmount);
        totalRentedAmount += addedAmount;

        // Add the part taken as fees to the Reserve
        reserveAmount += (addedAmount * reserveRatio) / MAX_BPS;

        emit NotifyRentedAmount(manager, pod, addedAmount);
    }

    /**
    * @notice Pull rented stkAAVE from a Pod
    * @dev Pull stkAAVE from a Pod & update the tracked rented amount
    * @param pod Address of the Pod
    * @param amount Amount to pull
    */
    function pullRentedStkAave(address pod, uint256 amount) external nonReentrant {
        address manager = msg.sender;
        if(podManagers[manager].totalRented == 0) revert Errors.NotUndebtedManager();
        if(pod == address(0)) revert Errors.AddressZero();
        if(amount == 0) revert Errors.NullAmount();
        if(amount > podManagers[manager].totalRented) revert Errors.AmountExceedsDebt();

        // Fetch Aave Safety Module rewards & stake them into stkAAVE
        _getStkAaveRewards();

        // Pull the tokens from the Pod, and update the tracked rented amount for the
        // corresponding Manager
        podManagers[manager].totalRented -= safe248(amount);
        totalRentedAmount -= amount;
        // We consider that pod give MAX_UINT256 allowance to this contract when created
        IERC20(STK_AAVE).safeTransferFrom(pod, address(this), amount);

        emit PullFromPod(manager, pod, amount);
    }


    // Internal functions

    /**
    * @dev Get the current index to convert between balance and scaled balances
    * @return uint256 : Current index
    */
    function _getCurrentIndex() internal view override returns (uint256) {
        if(_totalSupply == 0) return INITIAL_INDEX;
        return totalAssets().rayDiv(_totalSupply);
    }

    /**
    * @dev Pull assets to deposit in the Vault & mint shares
    * @param amount Amount to deposit
    * @param receiver Address to receive the shares
    * @param depositor Address depositing the assets
    * @return uint256 : Amount of assets deposited
    * @return uint256 : Amount of shares minted
    */
    function _deposit(
        uint256 amount,
        address receiver,
        address depositor
    ) internal returns (uint256, uint256) {
        if (receiver == address(0)) revert Errors.AddressZero();
        if (amount == 0) revert Errors.NullAmount();

        // Fetch Aave Safety Module rewards & stake them into stkAAVE
        _getStkAaveRewards();

        // We need to get the index before pulling the assets
        // so we can have the correct one based on previous stkAave claim
        uint256 _currentIndex = _getCurrentIndex();

        // Pull tokens from the depositor
        IERC20(STK_AAVE).safeTransferFrom(depositor, address(this), amount);

        // Mint the scaled balance of the user to match the deposited amount
        uint256 minted = _mint(receiver, amount, _currentIndex);

        afterDeposit(amount);

        return (amount, minted);
    }

    /**
    * @dev Withdraw assets from the Vault & send to the receiver & burn shares
    * @param amount Amount to withdraw
    * @param owner Address owning the shares
    * @param receiver Address to receive the assets
    * @param sender Address of the caller
    * @return uint256 : Amount of assets withdrawn
    * @return uint256 : Amount of shares burned
    */
    function _withdraw(
        uint256 amount, // if `MAX_UINT256`, just withdraw everything
        address owner,
        address receiver,
        address sender
    ) internal returns (uint256, uint256) {
        if (receiver == address(0) || owner == address(0)) revert Errors.AddressZero();
        if (amount == 0) revert Errors.NullAmount();

        // Fetch Aave Safety Module rewards & stake them into stkAAVE
        _getStkAaveRewards();

        // If the user wants to withdraw their full balance
        bool _maxWithdraw;
        if(amount == MAX_UINT256) {
            amount = balanceOf(owner);
            _maxWithdraw = true;
        }

        // Check that the caller has the allowance to withdraw for the given owner
        if (owner != sender) {
            uint256 allowed = _allowances[owner][sender];
            if (allowed < amount) revert Errors.ERC20_AmountOverAllowance();
            if (allowed != type(uint256).max)
                _allowances[owner][sender] = allowed - amount;
        }

        IERC20 _stkAave = IERC20(STK_AAVE);

        // Check that the Vault has enough stkAave to send
        uint256 availableBalance = _stkAave.balanceOf(address(this));
        availableBalance = reserveAmount >= availableBalance ? 0 : availableBalance - reserveAmount;
        if(amount > availableBalance) revert Errors.NotEnoughAvailableFunds();

        // Burn the scaled balance matching the amount to withdraw
        uint256 burned = _burn(owner, amount, _maxWithdraw);

        beforeWithdraw(amount);

        // Send the tokens to the given receiver
        _stkAave.safeTransfer(receiver, amount);

        return (amount, burned);
    }

    /**
    * @dev Hook exectued before withdrawing
    * @param amount Amount to withdraw
    */
    function beforeWithdraw(uint256 amount) internal {}

    /**
    * @dev Hook exectued after depositing
    * @param amount Amount deposited
    */
    function afterDeposit(uint256 amount) internal {}

    /**
    * @dev Hook executed before each transfer
    * @param from Sender address
    * @param to Receiver address
    * @param amount Amount to transfer
    */
    function _beforeTokenTransfer(
        address from,
        address to,
        uint256 amount
    ) internal isInitialized whenNotPaused override virtual {
        super._beforeTokenTransfer(from, to, amount);
    }

    /**
    * @dev Hook executed after each transfer
    * @param from Sender address
    * @param to Receiver address
    * @param amount Amount to transfer
    */
    function _afterTokenTransfer(
        address from,
        address to,
        uint256 amount
    ) internal override virtual {
        super._afterTokenTransfer(from, to, amount);
    }

    /**
    * @dev Claim AAVE rewards from the Safety Module & stake them to receive stkAAVE
    */
    function _getStkAaveRewards() internal {
        IStakedAave _stkAave = IStakedAave(STK_AAVE);

        // Get pending rewards amount
        uint256 pendingRewards = _stkAave.getTotalRewardsBalance(address(this));

        if (pendingRewards > 0) {
            // Claim the AAVE tokens
            _stkAave.claimRewards(address(this), pendingRewards);

            // Set a part of the claimed amount as the Reserve (protocol fees)
            reserveAmount += (pendingRewards * reserveRatio) / MAX_BPS;
        }

        IERC20 _aave = IERC20(AAVE);
        uint256 currentBalance = _aave.balanceOf(address(this));
        
        if(currentBalance > 0) {
            // Increase allowance for the Safety Module & stake AAVE into stkAAVE
            _aave.safeIncreaseAllowance(STK_AAVE, currentBalance);
            _stkAave.stake(address(this), currentBalance);
        }
    }


    // Admin 
    
    /**
     * @notice Pause the contract
     */
    function pause() external onlyAdmin {
        _pause();
    }

    /**
     * @notice Unpause the contract
     */
    function unpause() external onlyAdmin {
        _unpause();
    }

    /**
    * @notice Set a given address as the new pending admin
    * @param newAdmin Address to be the new admin
    */
    function transferAdmin(address newAdmin) external onlyAdmin {
        if (newAdmin == address(0)) revert Errors.AddressZero();
        if (newAdmin == admin) revert Errors.CannotBeAdmin();
        address oldPendingAdmin = pendingAdmin;

        pendingAdmin = newAdmin;

        emit NewPendingAdmin(oldPendingAdmin, newAdmin);
    }

    /**
    * @notice Accpet adminship of the contract (must be the pending admin)
    */
    function acceptAdmin() external {
        if (msg.sender != pendingAdmin) revert Errors.CallerNotPendingAdmin();
        address newAdmin = pendingAdmin;
        address oldAdmin = admin;
        admin = newAdmin;
        pendingAdmin = address(0);

        emit AdminTransferred(oldAdmin, newAdmin);
        emit NewPendingAdmin(newAdmin, address(0));
    }

    /**
    * @notice Add a new Pod Manager
    * @param newManager Address of the new manager
    */
    function addPodManager(address newManager) external onlyAdmin {
        if(newManager == address(0)) revert Errors.AddressZero();
        if(podManagers[newManager].rentingAllowed) revert Errors.ManagerAlreadyListed();

        podManagers[newManager].rentingAllowed = true;

        emit NewPodManager(newManager);
    }

    /**
    * @notice Block a Pod Manager
    * @param manager Address of the manager
    */
    function blockPodManager(address manager) external onlyAdmin {
        if(manager == address(0)) revert Errors.AddressZero();
        if(!podManagers[manager].rentingAllowed) revert Errors.ManagerNotListed();

        podManagers[manager].rentingAllowed = false;

        emit BlockedPodManager(manager);
    }

    /**
    * @notice Update the Vault's voting power manager & delegate the voting power to it
    * @param newManager Address of the new manager
    */
    function updateVotingPowerManager(address newManager) external onlyAdmin {
        if(newManager == address(0)) revert Errors.AddressZero();
        if(newManager == votingPowerManager) revert Errors.SameAddress();

        address oldManager = votingPowerManager;
        votingPowerManager = newManager;

        IGovernancePowerDelegationToken(STK_AAVE).delegateByType(
            newManager,
            IGovernancePowerDelegationToken.DelegationType.VOTING_POWER
        );

        emit UpdatedVotingPowerManager(oldManager, newManager);
    }

    /**
    * @notice Update the Vault's proposal power manager & delegate the proposal power to it
    * @param newManager Address of the new manager
    */
    function updateProposalPowerManager(address newManager) external onlyAdmin {
        if(newManager == address(0)) revert Errors.AddressZero();
        if(newManager == proposalPowerManager) revert Errors.SameAddress();

        address oldManager = proposalPowerManager;
        proposalPowerManager = newManager;

        IGovernancePowerDelegationToken(STK_AAVE).delegateByType(
            newManager,
            IGovernancePowerDelegationToken.DelegationType.PROPOSITION_POWER
        );

        emit UpdatedProposalPowerManager(oldManager, newManager);
    }

    /**
    * @notice Update the Vault's Reserve manager
    * @param newManager Address of the new manager
    */
    function updateReserveManager(address newManager) external onlyAdmin {
        if(newManager == address(0)) revert Errors.AddressZero();
        if(newManager == reserveManager) revert Errors.SameAddress();

        address oldManager = reserveManager;
        reserveManager = newManager;

        emit UpdatedReserveManager(oldManager, newManager);
    }

    /**
    * @notice Uodate the reserve ratio parameter
    * @param newRatio New ratio value
    */
    function updateReserveRatio(uint256 newRatio) external onlyAdmin {
        if(newRatio > 1500) revert Errors.InvalidParameter();

        uint256 oldRatio = reserveRatio;
        reserveRatio = newRatio;

        emit UpdatedReserveRatio(oldRatio, newRatio);
    }

    /**
    * @notice Uodate the buffer ratio parameter
    * @param newRatio New ratio value
    */
    function updateBufferRatio(uint256 newRatio) external onlyAdmin {
        if(newRatio > 1500) revert Errors.InvalidParameter();

        uint256 oldRatio = bufferRatio;
        bufferRatio = newRatio;

        emit UpdatedBufferRatio(oldRatio, newRatio);
    }

    /**
     * @notice Deposit token in the reserve
     * @param amount Amount of token to deposit
     */
    function depositToReserve(uint256 amount) external nonReentrant onlyAllowed returns(bool) {
        if(amount == 0) revert Errors.NullAmount();

        // Fetch Aave Safety Module rewards & stake them into stkAAVE
        _getStkAaveRewards();

        IERC20(STK_AAVE).safeTransferFrom(msg.sender, address(this), amount);
        reserveAmount += amount;

        emit ReserveDeposit(msg.sender, amount);

        return true;
    }

    /**
     * @notice Withdraw tokens from the reserve to send to the given receiver
     * @param amount Amount of token to withdraw
     * @param receiver Address to receive the tokens
     */
    function withdrawFromReserve(uint256 amount, address receiver) external nonReentrant onlyAllowed returns(bool) {
        if(amount == 0) revert Errors.NullAmount();
        if(receiver == address(0)) revert Errors.AddressZero();
        if(amount > reserveAmount) revert Errors.ReserveTooLow();

        // Fetch Aave Safety Module rewards & stake them into stkAAVE
        _getStkAaveRewards();

        IERC20(STK_AAVE).safeTransfer(receiver, amount);
        reserveAmount -= amount;

        emit ReserveWithdraw(receiver, amount);

        return true;
    }

    /**
    * @notice Recover ERC2O tokens sent by mistake to the contract
    * @dev Recover ERC2O tokens sent by mistake to the contract
    * @param token Address of the ERC2O token
    * @return bool: success
    */
    function recoverERC20(address token) external onlyAdmin returns(bool) {
        if(token == AAVE || token == STK_AAVE) revert Errors.CannotRecoverToken();

        uint256 amount = IERC20(token).balanceOf(address(this));
        if(amount == 0) revert Errors.NullAmount();
        IERC20(token).safeTransfer(admin, amount);

        emit TokenRecovered(token, amount);

        return true;
    }

    // Maths

    function safe248(uint256 n) internal pure returns (uint248) {
        if(n > type(uint248).max) revert Errors.NumberExceed248Bits();
        return uint248(n);
    }

}

File 2 of 13 : ScalingERC20.sol
//██████╗  █████╗ ██╗      █████╗ ██████╗ ██╗███╗   ██╗
//██╔══██╗██╔══██╗██║     ██╔══██╗██╔══██╗██║████╗  ██║
//██████╔╝███████║██║     ███████║██║  ██║██║██╔██╗ ██║
//██╔═══╝ ██╔══██║██║     ██╔══██║██║  ██║██║██║╚██╗██║
//██║     ██║  ██║███████╗██║  ██║██████╔╝██║██║ ╚████║
//╚═╝     ╚═╝  ╚═╝╚══════╝╚═╝  ╚═╝╚═════╝ ╚═╝╚═╝  ╚═══╝


pragma solidity 0.8.16;
//SPDX-License-Identifier: BUSL-1.1

import "../oz/interfaces/IERC20.sol";
import "../oz/utils/Context.sol";
import {Errors} from  "../utils/Errors.sol";
import {WadRayMath} from  "../utils/WadRayMath.sol";

/** @title ScalingERC20 contract
 *  @author Paladin, inspired by Aave & OpenZeppelin implementations
 *  @notice ERC20 implementation of scaled balance token
*/
abstract contract ScalingERC20 is Context, IERC20 {
    using WadRayMath for uint256;

    // Constants

    /** @notice 1e18 scale */
    uint256 public constant UNIT = 1e18;

    /** @notice 1e27 - RAY - Initial Index for balance to scaled balance */
    uint256 internal constant INITIAL_INDEX = 1e27;

    // Structs

    /** @notice UserState struct 
    *   scaledBalance: scaled balance of the user
    *   index: last index for the user
    */
    struct UserState {
        uint128 scaledBalance;
        uint128 index;
    }

    // Storage

    /** @notice Total scaled supply */
    uint256 internal _totalSupply;

    /** @notice Allowances for users */
    mapping(address => mapping(address => uint256)) internal _allowances;

    /** @notice Token name */
    string private _name;
    /** @notice Token symbol */
    string private _symbol;
    /** @notice Token decimals */
    uint8 private _decimals;

    /** @notice User states */
    mapping(address => UserState) internal _userStates;


    // Events

    /** @notice Event emitted when minting */
    event Mint(address indexed user, uint256 scaledAmount, uint256 index);
    /** @notice Event emitted when burning */
    event Burn(address indexed user, uint256 scaledAmount, uint256 index);


    // Constructor

    constructor(
        string memory __name,
        string memory __symbol
    ) {
        _name = __name;
        _symbol = __symbol;
        _decimals = 18;
    }


    // View methods

    /**
    * @notice Get the name of the ERC20
    * @return string : Name
    */
    function name() public view returns (string memory) {
        return _name;
    }

    /**
    * @notice Get the symbol of the ERC20
    * @return string : Symbol
    */
    function symbol() external view returns (string memory) {
        return _symbol;
    }

    /**
    * @notice Get the decimals of the ERC20
    * @return uint256 : Number of decimals
    */
    function decimals() external view returns (uint8) {
        return _decimals;
    }

    /**
    * @notice Get the current total supply
    * @return uint256 : Current total supply
    */
    function totalSupply() public view override virtual returns (uint256) {
        uint256 _scaledSupply = _totalSupply;
        if(_scaledSupply == 0) return 0;
        return _scaledSupply.rayMul(_getCurrentIndex());
    }

    /**
    * @notice Get the current user balance
    * @param account Address of user
    * @return uint256 : User balance
    */
    function balanceOf(address account) public view override virtual returns (uint256) {
        return uint256(_userStates[account].scaledBalance).rayMul(_getCurrentIndex());
    }

    /**
    * @notice Get the current total scaled supply
    * @return uint256 : Current total scaled supply
    */
    function totalScaledSupply() public view virtual returns (uint256) {
        return _totalSupply;
    }

    /**
    * @notice Get the current user scaled balance
    * @param account Address of user
    * @return uint256 : User scaled balance
    */
    function scaledBalanceOf(address account) public view virtual returns (uint256) {
        return _userStates[account].scaledBalance;
    }

    /**
    * @notice Get the allowance of a spender for a given owner
    * @param owner Address of the owner
    * @param spender Address of the spender
    * @return uint256 : allowance amount
    */
    function allowance(address owner, address spender) public view virtual override returns (uint256) {
        return _allowances[owner][spender];
    }




    // Write methods

    /**
    * @notice Approve a spender to spend tokens
    * @param spender Address of the spender
    * @param amount Amount to approve
    * @return bool : success
    */
    function approve(address spender, uint256 amount) public virtual override returns (bool) {
        _approve(msg.sender, spender, amount);
        return true;
    }

    /**
    * @notice Increase the allowance given to a spender
    * @param spender Address of the spender
    * @param addedValue Increase amount
    * @return bool : success
    */
    function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
        address owner = msg.sender;
        _approve(owner, spender, allowance(owner, spender) + addedValue);
        return true;
    }

    /**
    * @notice Decrease the allowance given to a spender
    * @param spender Address of the spender
    * @param subtractedValue Decrease amount
    * @return bool : success
    */
    function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
        address owner = msg.sender;
        uint256 currentAllowance = allowance(owner, spender);
        if(currentAllowance < subtractedValue) revert Errors.ERC20_AllowanceUnderflow();
        unchecked {
            _approve(owner, spender, currentAllowance - subtractedValue);
        }

        return true;
    }

    /**
    * @notice Transfer tokens to the given recipient
    * @param recipient Address to receive the tokens
    * @param amount Amount to transfer
    * @return bool : success
    */
    function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
        _transfer(msg.sender, recipient, amount);
        emit Transfer(msg.sender, recipient, amount);
        return true;
    }

    /**
    * @notice Transfer tokens from the spender to the given recipient
    * @param sender Address sending the tokens
    * @param recipient Address to receive the tokens
    * @param amount Amount to transfer
    * @return bool : success
    */
    function transferFrom(
        address sender,
        address recipient,
        uint256 amount
    ) public virtual override returns (bool) {
        uint256 _allowance = _allowances[sender][msg.sender];
        if(_allowance < amount) revert Errors.ERC20_AmountOverAllowance();
        if(_allowance != type(uint256).max) {
            _approve(
                sender,
                msg.sender,
                _allowances[sender][msg.sender] - amount
            );
        }
        _transfer(sender, recipient, amount);
        emit Transfer(sender, recipient, amount);
        return true;
    }


    // Internal methods

    /**
    * @dev Get the current index to convert between balance and scaled balances
    * @return uint256 : Current index
    */
    // To implement in inheriting contract
    function _getCurrentIndex() internal virtual view returns(uint256) {}

    /**
    * @dev Approve a spender to spend tokens
    * @param owner Address of the woner
    * @param spender Address of the spender
    * @param amount Amount to approve
    */
    function _approve(
        address owner,
        address spender,
        uint256 amount
    ) internal virtual {
        if(owner == address(0) || spender == address(0)) revert Errors.ERC20_ApproveAddressZero();

        _allowances[owner][spender] = amount;
        emit Approval(owner, spender, amount);
    }

    /**
    * @dev Transfer tokens from the spender to the given recipient
    * @param sender Address sending the tokens
    * @param recipient Address to receive the tokens
    * @param amount Amount to transfer
    */
    function _transfer(
        address sender,
        address recipient,
        uint256 amount
    ) internal virtual {
        if(sender == address(0) || recipient == address(0)) revert Errors.ERC20_AddressZero();
        if(sender == recipient) revert Errors.ERC20_SelfTransfer();
        if(amount == 0) revert Errors.ERC20_NullAmount();

        // Get the scaled amount to transfer for the given amount
        uint128 _scaledAmount = safe128(amount.rayDiv(_getCurrentIndex()));
        _transferScaled(sender, recipient, _scaledAmount);
    }

    /**
    * @dev Transfer the scaled amount of tokens
    * @param sender Address sending the tokens
    * @param recipient Address to receive the tokens
    * @param scaledAmount Scaled amount to transfer
    */
    function _transferScaled(
        address sender,
        address recipient,
        uint128 scaledAmount
    ) internal virtual {
        if(scaledAmount > _userStates[sender].scaledBalance) revert Errors.ERC20_AmountExceedBalance();

        _beforeTokenTransfer(sender, recipient, scaledAmount);

        unchecked {
            // Should never fail because of previous check
            // & because the scaledBalance of an user should never exceed the _totalSupply
            _userStates[sender].scaledBalance -= scaledAmount;
            _userStates[recipient].scaledBalance += scaledAmount;
        }

        _afterTokenTransfer(sender, recipient, scaledAmount);
    }

    /**
    * @dev Mint the given amount to the given address (by minting the correct scaled amount)
    * @param account Address to mint to
    * @param amount Amount to mint
    * @param _currentIndex Index to use to calculate the scaled amount
    * @return uint256 : Amount minted
    */
    function _mint(address account, uint256 amount, uint256 _currentIndex) internal virtual returns(uint256) {
        uint256 _scaledAmount = amount.rayDiv(_currentIndex);
        if(_scaledAmount == 0) revert Errors.ERC20_NullAmount();

        _beforeTokenTransfer(address(0), account, _scaledAmount);

        _userStates[account].index = safe128(_currentIndex);

        _totalSupply += _scaledAmount;
        _userStates[account].scaledBalance += safe128(_scaledAmount);

        _afterTokenTransfer(address(0), account, _scaledAmount);

        emit Mint(account, _scaledAmount, _currentIndex);
        emit Transfer(address(0), account, amount);

        return amount;
    }

    /**
    * @dev Burn the given amount from the given address (by burning the correct scaled amount)
    * @param account Address to burn from
    * @param amount Amount to burn
    * @param maxWithdraw True if burning the full balance
    * @return uint256 : Amount burned
    */
    function _burn(address account, uint256 amount, bool maxWithdraw) internal virtual returns(uint256) {
        uint256 _currentIndex = _getCurrentIndex();
        uint256 _scaledBalance = _userStates[account].scaledBalance;

        // if given maxWithdraw as true, we want to burn the whole balance for the user
        uint256 _scaledAmount = maxWithdraw ?  _scaledBalance: amount.rayDiv(_currentIndex);
        if(_scaledAmount == 0) revert Errors.ERC20_NullAmount();
        if(_scaledAmount > _scaledBalance) revert Errors.ERC20_AmountExceedBalance();

        _beforeTokenTransfer(account, address(0), _scaledAmount);
        
        _userStates[account].index = safe128(_currentIndex);

        _totalSupply -= _scaledAmount;
        _userStates[account].scaledBalance -= safe128(_scaledAmount);

        _afterTokenTransfer(account, address(0), _scaledAmount);
        
        emit Burn(account, _scaledAmount, _currentIndex);
        emit Transfer(account, address(0), amount);

        return amount;
    }


    // Virtual hooks

    /**
    * @dev Hook executed before each transfer
    * @param from Sender address
    * @param to Receiver address
    * @param amount Amount to transfer
    */
    // To implement in inheriting contract
    function _beforeTokenTransfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {}

    /**
    * @dev Hook executed after each transfer
    * @param from Sender address
    * @param to Receiver address
    * @param amount Amount to transfer
    */
    // To implement in inheriting contract
    function _afterTokenTransfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {}


    // Maths

    function safe128(uint256 n) internal pure returns (uint128) {
        if(n > type(uint128).max) revert Errors.NumberExceed128Bits();
        return uint128(n);
    }


}

File 3 of 13 : IERC4626.sol
pragma solidity 0.8.16;
//SPDX-License-Identifier: MIT

import "../oz/interfaces/IERC20.sol";

interface IERC4626 is IERC20 {
    /*//////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

    event Deposit(
        address indexed caller,
        address indexed owner,
        uint256 assets,
        uint256 shares
    );

    event Withdraw(
        address indexed caller,
        address indexed receiver,
        address indexed owner,
        uint256 assets,
        uint256 shares
    );

    /*//////////////////////////////////////////////////////////////
                               IMMUTABLES
    //////////////////////////////////////////////////////////////*/

    function asset() external view returns (address);

    /*//////////////////////////////////////////////////////////////
                        DEPOSIT/WITHDRAWAL LOGIC
    //////////////////////////////////////////////////////////////*/

    function deposit(uint256 assets, address receiver)
        external
        returns (uint256 shares);

    function mint(uint256 shares, address receiver)
        external
        returns (uint256 assets);

    function withdraw(
        uint256 assets,
        address receiver,
        address owner
    ) external returns (uint256 shares);

    function redeem(
        uint256 shares,
        address receiver,
        address owner
    ) external returns (uint256 assets);

    /*//////////////////////////////////////////////////////////////
                            ACCOUNTING LOGIC
    //////////////////////////////////////////////////////////////*/

    function totalAssets() external view returns (uint256);

    function convertToShares(uint256 assets) external view returns (uint256);

    function convertToAssets(uint256 shares) external view returns (uint256);

    function previewDeposit(uint256 assets) external view returns (uint256);

    function previewMint(uint256 shares) external view returns (uint256);

    function previewWithdraw(uint256 assets) external view returns (uint256);

    function previewRedeem(uint256 shares) external view returns (uint256);

    /*//////////////////////////////////////////////////////////////
                     DEPOSIT/WITHDRAWAL LIMIT LOGIC
    //////////////////////////////////////////////////////////////*/

    function maxDeposit(address) external view returns (uint256);

    function maxMint(address) external view returns (uint256);

    function maxWithdraw(address owner) external view returns (uint256);

    function maxRedeem(address owner) external view returns (uint256);

    /*//////////////////////////////////////////////////////////////
                          INTERNAL HOOKS LOGIC
    //////////////////////////////////////////////////////////////*/
    /*
    function beforeWithdraw(uint256 assets, uint256 shares) internal {}
    function afterDeposit(uint256 assets, uint256 shares) internal {}
    */
}

File 4 of 13 : IGovernancePowerDelegationToken.sol
//Aave Governance Token Interface

// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.8.16;

interface IGovernancePowerDelegationToken {
    enum DelegationType {
        VOTING_POWER,
        PROPOSITION_POWER
    }

    /**
     * @dev emitted when a user delegates to another
     * @param delegator the delegator
     * @param delegatee the delegatee
     * @param delegationType the type of delegation (VOTING_POWER, PROPOSITION_POWER)
     **/
    event DelegateChanged(
        address indexed delegator,
        address indexed delegatee,
        DelegationType delegationType
    );

    /**
     * @dev emitted when an action changes the delegated power of a user
     * @param user the user which delegated power has changed
     * @param amount the amount of delegated power for the user
     * @param delegationType the type of delegation (VOTING_POWER, PROPOSITION_POWER)
     **/
    event DelegatedPowerChanged(
        address indexed user,
        uint256 amount,
        DelegationType delegationType
    );

    /**
     * @dev delegates the specific power to a delegatee
     * @param delegatee the user which delegated power has changed
     * @param delegationType the type of delegation (VOTING_POWER, PROPOSITION_POWER)
     **/
    function delegateByType(address delegatee, DelegationType delegationType)
        external;

    /**
     * @dev delegates all the powers to a specific user
     * @param delegatee the user to which the power will be delegated
     **/
    function delegate(address delegatee) external;

    /**
     * @dev returns the delegatee of an user
     * @param delegator the address of the delegator
     **/
    function getDelegateeByType(
        address delegator,
        DelegationType delegationType
    ) external view returns (address);

    /**
     * @dev returns the current delegated power of a user. The current power is the
     * power delegated at the time of the last snapshot
     * @param user the user
     **/
    function getPowerCurrent(address user, DelegationType delegationType)
        external
        view
        returns (uint256);

    /**
     * @dev returns the delegated power of a user at a certain block
     * @param user the user
     **/
    function getPowerAtBlock(
        address user,
        uint256 blockNumber,
        DelegationType delegationType
    ) external view returns (uint256);

    /**
     * @dev returns the total supply at a certain block number
     **/
    function totalSupplyAt(uint256 blockNumber) external view returns (uint256);
}

File 5 of 13 : IStakedAave.sol
// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.8.16;

interface IStakedAave {

  event Staked(
    address indexed from,
    address indexed to,
    uint256 assets,
    uint256 shares
  );
  event Redeem(
    address indexed from,
    address indexed to,
    uint256 assets,
    uint256 shares
  );

  event RewardsAccrued(address user, uint256 amount);
  event RewardsClaimed(address indexed from, address indexed to, uint256 amount);

  event Cooldown(address indexed user);

  function stake(address to, uint256 amount) external;

  function redeem(address to, uint256 amount) external;

  function cooldown() external;

  function claimRewards(address to, uint256 amount) external;

  function getTotalRewardsBalance(address staker) external view returns (uint256);
}

File 6 of 13 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) external returns (bool);
}

File 7 of 13 : SafeERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "../interfaces/IERC20.sol";
import "../utils/Address.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    using Address for address;

    function safeTransfer(
        IERC20 token,
        address to,
        uint256 value
    ) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    function safeTransferFrom(
        IERC20 token,
        address from,
        address to,
        uint256 value
    ) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    /**
     * @dev Deprecated. This function has issues similar to the ones found in
     * {IERC20-approve}, and its usage is discouraged.
     *
     * Whenever possible, use {safeIncreaseAllowance} and
     * {safeDecreaseAllowance} instead.
     */
    function safeApprove(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        require(
            (value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

    function safeIncreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        uint256 newAllowance = token.allowance(address(this), spender) + value;
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    function safeDecreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        unchecked {
            uint256 oldAllowance = token.allowance(address(this), spender);
            require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
            uint256 newAllowance = oldAllowance - value;
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
        if (returndata.length > 0) {
            // Return data is optional
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}

File 8 of 13 : Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        require(isContract(target), "Address: call to non-contract");

        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        require(isContract(target), "Address: static call to non-contract");

        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(isContract(target), "Address: delegate call to non-contract");

        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly
                /// @solidity memory-safe-assembly
                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

File 9 of 13 : Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }
}

File 10 of 13 : Pausable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (security/Pausable.sol)

pragma solidity ^0.8.0;

import "./Context.sol";

/**
 * @dev Contract module which allows children to implement an emergency stop
 * mechanism that can be triggered by an authorized account.
 *
 * This module is used through inheritance. It will make available the
 * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
 * the functions of your contract. Note that they will not be pausable by
 * simply including this module, only once the modifiers are put in place.
 */
abstract contract Pausable is Context {
    /**
     * @dev Emitted when the pause is triggered by `account`.
     */
    event Paused(address account);

    /**
     * @dev Emitted when the pause is lifted by `account`.
     */
    event Unpaused(address account);

    bool private _paused;

    /**
     * @dev Initializes the contract in unpaused state.
     */
    constructor() {
        _paused = false;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is not paused.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    modifier whenNotPaused() {
        _requireNotPaused();
        _;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is paused.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    modifier whenPaused() {
        _requirePaused();
        _;
    }

    /**
     * @dev Returns true if the contract is paused, and false otherwise.
     */
    function paused() public view virtual returns (bool) {
        return _paused;
    }

    /**
     * @dev Throws if the contract is paused.
     */
    function _requireNotPaused() internal view virtual {
        require(!paused(), "Pausable: paused");
    }

    /**
     * @dev Throws if the contract is not paused.
     */
    function _requirePaused() internal view virtual {
        require(paused(), "Pausable: not paused");
    }

    /**
     * @dev Triggers stopped state.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    function _pause() internal virtual whenNotPaused {
        _paused = true;
        emit Paused(_msgSender());
    }

    /**
     * @dev Returns to normal state.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    function _unpause() internal virtual whenPaused {
        _paused = false;
        emit Unpaused(_msgSender());
    }
}

File 11 of 13 : ReentrancyGuard.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol)

pragma solidity ^0.8.0;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    constructor() {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        // On the first call to nonReentrant, _notEntered will be true
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        // Any calls to nonReentrant after this point will fail
        _status = _ENTERED;

        _;

        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = _NOT_ENTERED;
    }
}

File 12 of 13 : Errors.sol
pragma solidity 0.8.16;
//SPDX-License-Identifier: MIT

library Errors {

    // Common Errors
    error AddressZero();
    error NullAmount();
    error IncorrectRewardToken();
    error SameAddress();
    error InequalArraySizes();
    error EmptyArray();
    error EmptyParameters();
    error NotInitialized();
    error AlreadyInitialized();
    error CannotInitialize();
    error InvalidParameter();
    error CannotRecoverToken();
    error NullWithdraw();
    error AlreadyListedManager();
    error NotListedManager();

    // Access Control Erros
    error CallerNotAdmin();
    error CannotBeAdmin();
    error CallerNotPendingAdmin();
    error CallerNotAllowed();

    // ERC20 Errors
    error ERC20_ApproveAddressZero();
    error ERC20_AllowanceUnderflow();
    error ERC20_AmountOverAllowance();
    error ERC20_AddressZero();
    error ERC20_SelfTransfer();
    error ERC20_NullAmount();
    error ERC20_AmountExceedBalance();

    // Maths Errors
    error NumberExceed96Bits();
    error NumberExceed128Bits();
    error NumberExceed248Bits();

    // Vault Errors
    error ManagerAlreadyListed();
    error ManagerNotListed();
    error NotEnoughAvailableFunds();
    error WithdrawBuffer();
    error ReserveTooLow();
    error CallerNotAllowedManager();
    error NotUndebtedManager();
    error AmountExceedsDebt();

    // Vaults Rewards Errors
    error NullScaledAmount();
    error AlreadyListedDepositor();
    error NotListedDepositor();
    error ClaimNotAllowed();

    // Pods Errors
    error NotPodOwner();
    error NotPodManager();
    error FailPodStateUpdate();
    error MintAmountUnderMinimum();
    error RepayFailed();

    // Pods Manager Errors
    error CallerNotValidPod();
    error CollateralBlocked();
    error MintingAllowanceFailed();
    error FreeingStkAaveFailed();
    error CollateralAlreadyListed();
    error CollateralNotListed();
    error CollateralNotAllowed();
    error PodInvalid();
    error FailStateUpdate();
    error PodNotLiquidable();

    // Registry Errors
    error VaultAlreadySet();

    // Zap Errors
    error InvalidSourceToken();
    error DepositFailed();

    // Wrapper Errors
    error NullConvertedAmount();

}

File 13 of 13 : WadRayMath.sol
// SPDX-License-Identifier: GNU AGPLv3
pragma solidity ^0.8.0;

/// @title WadRayMath.
/// @author Morpho Labs.
/// @custom:contact [email protected]
/// @notice Optimized version of Aave V3 math library WadRayMath to conduct wad and ray manipulations: https://github.com/aave/aave-v3-core/blob/master/contracts/protocol/libraries/math/WadRayMath.sol
library WadRayMath {
    /// CONSTANTS ///

    uint256 internal constant WAD = 1e18;
    uint256 internal constant HALF_WAD = 0.5e18;
    uint256 internal constant RAY = 1e27;
    uint256 internal constant HALF_RAY = 0.5e27;
    uint256 internal constant WAD_RAY_RATIO = 1e9;
    uint256 internal constant HALF_WAD_RAY_RATIO = 0.5e9;
    uint256 internal constant MAX_UINT256 = 2**256 - 1; // Not possible to use type(uint256).max in yul.
    uint256 internal constant MAX_UINT256_MINUS_HALF_WAD = 2**256 - 1 - 0.5e18;
    uint256 internal constant MAX_UINT256_MINUS_HALF_RAY = 2**256 - 1 - 0.5e27;

    /// INTERNAL ///

    /// @dev Multiplies two wad, rounding half up to the nearest wad.
    /// @param x Wad.
    /// @param y Wad.
    /// @return z The result of x * y, in wad.
    function wadMul(uint256 x, uint256 y) internal pure returns (uint256 z) {
        // Let y > 0
        // Overflow if (x * y + HALF_WAD) > type(uint256).max
        // <=> x * y > type(uint256).max - HALF_WAD
        // <=> x > (type(uint256).max - HALF_WAD) / y
        assembly {
            if mul(y, gt(x, div(MAX_UINT256_MINUS_HALF_WAD, y))) {
                revert(0, 0)
            }

            z := div(add(mul(x, y), HALF_WAD), WAD)
        }
    }

    /// @dev Divides two wad, rounding half up to the nearest wad.
    /// @param x Wad.
    /// @param y Wad.
    /// @return z The result of x / y, in wad.
    function wadDiv(uint256 x, uint256 y) internal pure returns (uint256 z) {
        // Overflow if y == 0
        // Overflow if (x * WAD + y / 2) > type(uint256).max
        // <=> x * WAD > type(uint256).max - y / 2
        // <=> x > (type(uint256).max - y / 2) / WAD
        assembly {
            z := div(y, 2)
            if iszero(mul(y, iszero(gt(x, div(sub(MAX_UINT256, z), WAD))))) {
                revert(0, 0)
            }

            z := div(add(mul(WAD, x), z), y)
        }
    }

    /// @dev Multiplies two ray, rounding half up to the nearest ray.
    /// @param x Ray.
    /// @param y Ray.
    /// @return z The result of x * y, in ray.
    function rayMul(uint256 x, uint256 y) internal pure returns (uint256 z) {
        // Let y > 0
        // Overflow if (x * y + HALF_RAY) > type(uint256).max
        // <=> x * y > type(uint256).max - HALF_RAY
        // <=> x > (type(uint256).max - HALF_RAY) / y
        assembly {
            if mul(y, gt(x, div(MAX_UINT256_MINUS_HALF_RAY, y))) {
                revert(0, 0)
            }

            z := div(add(mul(x, y), HALF_RAY), RAY)
        }
    }

    /// @dev Divides two ray, rounding half up to the nearest ray.
    /// @param x Ray.
    /// @param y Ray.
    /// @return z The result of x / y, in ray.
    function rayDiv(uint256 x, uint256 y) internal pure returns (uint256 z) {
        // Overflow if y == 0
        // Overflow if (x * RAY + y / 2) > type(uint256).max
        // <=> x * RAY > type(uint256).max - y / 2
        // <=> x > (type(uint256).max - y / 2) / RAY
        assembly {
            z := div(y, 2)
            if iszero(mul(y, iszero(gt(x, div(sub(MAX_UINT256, z), RAY))))) {
                revert(0, 0)
            }

            z := div(add(mul(RAY, x), z), y)
        }
    }

    /// @dev Casts ray down to wad.
    /// @param x Ray.
    /// @return y = x converted to wad, rounded half up to the nearest wad.
    function rayToWad(uint256 x) internal pure returns (uint256 y) {
        assembly {
            // If x % WAD_RAY_RATIO >= HALF_WAD_RAY_RATIO, round up.
            y := add(div(x, WAD_RAY_RATIO), iszero(lt(mod(x, WAD_RAY_RATIO), HALF_WAD_RAY_RATIO)))
        }
    }

    /// @dev Converts wad up to ray.
    /// @param x Wad.
    /// @return y = x converted in ray.
    function wadToRay(uint256 x) internal pure returns (uint256 y) {
        assembly {
            y := mul(WAD_RAY_RATIO, x)
            // Revert if y / WAD_RAY_RATIO != x
            if iszero(eq(div(y, WAD_RAY_RATIO), x)) {
                revert(0, 0)
            }
        }
    }
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_admin","type":"address"},{"internalType":"uint256","name":"_reserveRatio","type":"uint256"},{"internalType":"address","name":"_reserveManager","type":"address"},{"internalType":"address","name":"_aave","type":"address"},{"internalType":"address","name":"_stkAave","type":"address"},{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AddressZero","type":"error"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"AmountExceedsDebt","type":"error"},{"inputs":[],"name":"CallerNotAdmin","type":"error"},{"inputs":[],"name":"CallerNotAllowedManager","type":"error"},{"inputs":[],"name":"CallerNotPendingAdmin","type":"error"},{"inputs":[],"name":"CannotBeAdmin","type":"error"},{"inputs":[],"name":"CannotRecoverToken","type":"error"},{"inputs":[],"name":"ERC20_AddressZero","type":"error"},{"inputs":[],"name":"ERC20_AllowanceUnderflow","type":"error"},{"inputs":[],"name":"ERC20_AmountExceedBalance","type":"error"},{"inputs":[],"name":"ERC20_AmountOverAllowance","type":"error"},{"inputs":[],"name":"ERC20_ApproveAddressZero","type":"error"},{"inputs":[],"name":"ERC20_NullAmount","type":"error"},{"inputs":[],"name":"ERC20_SelfTransfer","type":"error"},{"inputs":[],"name":"InvalidParameter","type":"error"},{"inputs":[],"name":"ManagerAlreadyListed","type":"error"},{"inputs":[],"name":"ManagerNotListed","type":"error"},{"inputs":[],"name":"NotEnoughAvailableFunds","type":"error"},{"inputs":[],"name":"NotInitialized","type":"error"},{"inputs":[],"name":"NotUndebtedManager","type":"error"},{"inputs":[],"name":"NullAmount","type":"error"},{"inputs":[],"name":"NumberExceed128Bits","type":"error"},{"inputs":[],"name":"NumberExceed248Bits","type":"error"},{"inputs":[],"name":"ReserveTooLow","type":"error"},{"inputs":[],"name":"SameAddress","type":"error"},{"inputs":[],"name":"WithdrawBuffer","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousAdmin","type":"address"},{"indexed":true,"internalType":"address","name":"newAdmin","type":"address"}],"name":"AdminTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"manager","type":"address"}],"name":"BlockedPodManager","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"scaledAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"index","type":"uint256"}],"name":"Burn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"scaledAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"index","type":"uint256"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousPendingAdmin","type":"address"},{"indexed":true,"internalType":"address","name":"newPendingAdmin","type":"address"}],"name":"NewPendingAdmin","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newManager","type":"address"}],"name":"NewPodManager","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"manager","type":"address"},{"indexed":true,"internalType":"address","name":"pod","type":"address"},{"indexed":false,"internalType":"uint256","name":"addedAmount","type":"uint256"}],"name":"NotifyRentedAmount","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"manager","type":"address"},{"indexed":true,"internalType":"address","name":"pod","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"PullFromPod","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"manager","type":"address"},{"indexed":true,"internalType":"address","name":"pod","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RentToPod","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ReserveDeposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ReserveWithdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TokenRecovered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldRatio","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newRatio","type":"uint256"}],"name":"UpdatedBufferRatio","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldManager","type":"address"},{"indexed":true,"internalType":"address","name":"newManager","type":"address"}],"name":"UpdatedProposalPowerManager","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldManager","type":"address"},{"indexed":true,"internalType":"address","name":"newManager","type":"address"}],"name":"UpdatedReserveManager","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldRatio","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newRatio","type":"uint256"}],"name":"UpdatedReserveRatio","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldManager","type":"address"},{"indexed":true,"internalType":"address","name":"newManager","type":"address"}],"name":"UpdatedVotingPowerManager","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[],"name":"AAVE","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_BPS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_UINT256","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STK_AAVE","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UNIT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newManager","type":"address"}],"name":"addPodManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"asset","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"manager","type":"address"}],"name":"blockPodManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"bufferRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"convertToAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"convertToShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"depositToReserve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getCurrentIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getDelegates","outputs":[{"internalType":"address","name":"votingPower","type":"address"},{"internalType":"address","name":"proposalPower","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_votingPowerManager","type":"address"},{"internalType":"address","name":"_proposalPowerManager","type":"address"}],"name":"init","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"initialized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"maxDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"maxMint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"maxRedeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"maxWithdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"mint","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pod","type":"address"},{"internalType":"uint256","name":"addedAmount","type":"uint256"}],"name":"notifyRentedAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingAdmin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"podManagers","outputs":[{"internalType":"bool","name":"rentingAllowed","type":"bool"},{"internalType":"uint248","name":"totalRented","type":"uint248"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"previewDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"previewMint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"previewRedeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"previewWithdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"proposalPowerManager","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pod","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"pullRentedStkAave","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"recoverERC20","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"redeem","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"pod","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"rentStkAave","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"reserveAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"reserveManager","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"reserveRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"scaledBalanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalAvailable","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalRentedAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalScaledSupply","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":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newAdmin","type":"address"}],"name":"transferAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newRatio","type":"uint256"}],"name":"updateBufferRatio","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newManager","type":"address"}],"name":"updateProposalPowerManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newManager","type":"address"}],"name":"updateReserveManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newRatio","type":"uint256"}],"name":"updateReserveRatio","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"updateStkAaveRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newManager","type":"address"}],"name":"updateVotingPowerManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"votingPowerManager","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"withdrawFromReserve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}]

60c06040526101f4600d553480156200001757600080fd5b5060405162003ef238038062003ef28339810160408190526200003a9162000233565b818160026200004a838262000381565b50600362000059828262000381565b50506004805460ff199081166012179091556001600655600780549091169055506001600160a01b03871615806200009857506001600160a01b038516155b80620000ab57506001600160a01b038416155b80620000be57506001600160a01b038316155b15620000dd57604051639fabe1c160e01b815260040160405180910390fd5b85600003620000ff57604051630e5a744960e41b815260040160405180910390fd5b50506007805462010000600160b01b031916620100006001600160a01b0397881602179055600f93909355601080546001600160a01b03191692851692909217909155821660a052166080526200044d565b80516001600160a01b03811681146200016957600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200019657600080fd5b81516001600160401b0380821115620001b357620001b36200016e565b604051601f8301601f19908116603f01168101908282118183101715620001de57620001de6200016e565b81604052838152602092508683858801011115620001fb57600080fd5b600091505b838210156200021f578582018301518183018401529082019062000200565b600093810190920192909252949350505050565b600080600080600080600060e0888a0312156200024f57600080fd5b6200025a8862000151565b965060208801519550620002716040890162000151565b9450620002816060890162000151565b9350620002916080890162000151565b60a08901519093506001600160401b0380821115620002af57600080fd5b620002bd8b838c0162000184565b935060c08a0151915080821115620002d457600080fd5b50620002e38a828b0162000184565b91505092959891949750929550565b600181811c908216806200030757607f821691505b6020821081036200032857634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200037c57600081815260208120601f850160051c81016020861015620003575750805b601f850160051c820191505b81811015620003785782815560010162000363565b5050505b505050565b81516001600160401b038111156200039d576200039d6200016e565b620003b581620003ae8454620002f2565b846200032e565b602080601f831160018114620003ed5760008415620003d45750858301515b600019600386901b1c1916600185901b17855562000378565b600085815260208120601f198616915b828110156200041e57888601518255948401946001909101908401620003fd565b50858210156200043d5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60805160a051613a01620004f1600039600081816105c4015281816114e80152612871015260008181610550015281816107ba015281816108ec01528181611523015281816117a701528181611a7d01528181611c7901528181611f61015281816120ad0152818161217501528181612336015281816123b5015281816125060152818161274a0152818161290001528181612a8f0152612d4f0152613a016000f3fe608060405234801561001057600080fd5b50600436106103fc5760003560e01c80638456cb5911610215578063bdf2878d11610125578063d85d7f5b116100b8578063f09a401611610087578063f09a401614610869578063f27ef5c91461087c578063f851a4401461088f578063fd967f47146108a8578063fed371ed146108b157600080fd5b8063d85d7f5b1461084e578063d905777e14610815578063dd62ed3e14610856578063ef8b30f71461043157600080fd5b8063c838ccb6116100f4578063c838ccb6146107ef578063ce96cb7714610815578063cfb982c814610828578063d6d5784f1461083b57600080fd5b8063bdf2878d146107b5578063c415565f146107dc578063c63d75b6146105aa578063c6e6f5921461043157600080fd5b8063a9059cbb116101a8578063b553c08511610177578063b553c08514610717578063b6e1a2f11461072a578063ba0876521461077c578063ba0a3a581461078f578063bb004abc146107a257600080fd5b8063a9059cbb146106de578063b17d718e146106f1578063b3d7f6b914610431578063b460af941461070457600080fd5b80639d8e2177116101e45780639d8e2177146106a05780639e8c708e146106af578063a37f6911146106c2578063a457c2d7146106cb57600080fd5b80638456cb591461066a57806394bf804d1461067257806395d1d05b1461068557806395d89b411461069857600080fd5b806338d52e0f116103105780634cdad506116102a35780636f8b4530116102725780636f8b4530146106165780636fb36bcb1461061e57806370a082311461063157806371526ce51461064457806375829def1461065757600080fd5b80634cdad506146104315780635c975abb146105ef578063659db576146105fa5780636e553f651461060357600080fd5b80633f4ba83a116102df5780633f4ba83a146105a2578063402d267d146105aa57806348ccda3c146105bf5780634b09b72a146105e657600080fd5b806338d52e0f1461054e578063395093511461057457806339c00de91461058757806339c423d11461059a57600080fd5b8063158ef93e11610393578063264f6bb311610362578063264f6bb3146104df57806326782247146104f25780632a9950be1461051d578063313ce5671461053057806333a581d21461054557600080fd5b8063158ef93e1461048057806318160ddd146104925780631da24f3e1461049a57806323b872dd146104cc57600080fd5b80630a28a477116103cf5780630a28a477146104315780630c7d5cd8146104655780630d9005ae1461046e5780630e18b6811461047657600080fd5b806301e1d1141461040157806306fdde031461041c57806307a2d13a14610431578063095ea7b314610442575b600080fd5b6104096108c4565b6040519081526020015b60405180910390f35b610424610970565b604051610413919061362e565b61040961043f366004613661565b90565b610455610450366004613691565b610a02565b6040519015158152602001610413565b610409600f5481565b610409610a19565b61047e610a23565b005b60075461045590610100900460ff1681565b610409610af7565b6104096104a83660046136bb565b6001600160a01b03166000908152600560205260409020546001600160801b031690565b6104556104da3660046136d6565b610b01565b61047e6104ed366004613661565b610bdd565b600854610505906001600160a01b031681565b6040516001600160a01b039091168152602001610413565b61047e61052b3660046136bb565b610c77565b60045460405160ff9091168152602001610413565b61040960001981565b7f0000000000000000000000000000000000000000000000000000000000000000610505565b610455610582366004613691565b610d55565b61047e6105953660046136bb565b610d7c565b61047e610e55565b61047e610e94565b6104096105b83660046136bb565b5060001990565b6105057f000000000000000000000000000000000000000000000000000000000000000081565b610409600e5481565b60075460ff16610455565b61040960095481565b610409610611366004613712565b610ecf565b600054610409565b61047e61062c3660046136bb565b610f8c565b61040961063f3660046136bb565b611066565b61047e610652366004613691565b61109b565b61047e6106653660046136bb565b61124b565b61047e61132a565b610409610680366004613712565b611363565b61047e610693366004613661565b611411565b6104246114a3565b610409670de0b6b3a764000081565b6104556106bd3660046136bb565b6114b2565b610409600d5481565b6104556106d9366004613691565b611671565b6104556106ec366004613691565b6116ba565b6104556106ff366004613661565b6116fe565b61040961071236600461373e565b611827565b61047e610725366004613691565b6118fa565b61075d6107383660046136bb565b600a6020526000908152604090205460ff81169061010090046001600160f81b031682565b6040805192151583526001600160f81b03909116602083015201610413565b61040961078a36600461373e565b611aea565b61047e61079d366004613691565b611bbd565b601054610505906001600160a01b031681565b6105057f000000000000000000000000000000000000000000000000000000000000000081565b6104556107ea366004613712565b611e6e565b600b54600c54604080516001600160a01b03938416815292909116602083015201610413565b6104096108233660046136bb565b611fea565b61047e6108363660046136bb565b611ff5565b600b54610505906001600160a01b031681565b610409612153565b61040961086436600461377a565b612248565b61047e61087736600461377a565b612273565b61047e61088a3660046136bb565b61244e565b600754610505906201000090046001600160a01b031681565b61040961271081565b600c54610505906001600160a01b031681565b600e546009546040516370a0823160e01b815230600482015260009291906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa158015610933573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061095791906137a4565b61096191906137d3565b61096b91906137e6565b905090565b60606002805461097f906137f9565b80601f01602080910402602001604051908101604052809291908181526020018280546109ab906137f9565b80156109f85780601f106109cd576101008083540402835291602001916109f8565b820191906000526020600020905b8154815290600101906020018083116109db57829003601f168201915b5050505050905090565b6000610a0f3384846125ac565b5060015b92915050565b600061096b612648565b6008546001600160a01b03163314610a4e57604051630ac6491560e01b815260040160405180910390fd5b6008805460078054620100006001600160a01b0380851682810262010000600160b01b03198516179094556001600160a01b03199094169094556040519193900490911690829082907ff8ccb027dfcd135e000e9d45e6cc2d662578a8825d4c45b5e32e0adf67e79ec690600090a36040516000906001600160a01b038416907fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9908390a35050565b600061096b6108c4565b6001600160a01b038316600090815260016020908152604080832033845290915281205482811015610b46576040516364b3d8c760e01b815260040160405180910390fd5b6000198114610b8a576001600160a01b038516600090815260016020908152604080832033808552925290912054610b8a918791610b859087906137e6565b6125ac565b610b95858585612678565b836001600160a01b0316856001600160a01b03166000805160206139ac83398151915285604051610bc891815260200190565b60405180910390a360019150505b9392505050565b6007546201000090046001600160a01b03163314610c0e5760405163036c8cf960e11b815260040160405180910390fd5b6105dc811115610c3157604051630309cb8760e51b815260040160405180910390fd5b600d80549082905560408051828152602081018490527ff4eb55c9d5784e11db6a6ec12075c6539bbf1f33dd6e5167d622dd409570688d91015b60405180910390a15050565b6007546201000090046001600160a01b03163314610ca85760405163036c8cf960e11b815260040160405180910390fd5b6001600160a01b038116610ccf57604051639fabe1c160e01b815260040160405180910390fd5b6001600160a01b0381166000908152600a602052604090205460ff1615610d09576040516351b6234d60e11b815260040160405180910390fd5b6001600160a01b0381166000818152600a6020526040808220805460ff19166001179055517f24a580edd7d72eaf169d7530d023d8e608352e77e0e132cff8c2a8955b00bb279190a250565b600033610d72818585610d688383612248565b610b8591906137d3565b5060019392505050565b6007546201000090046001600160a01b03163314610dad5760405163036c8cf960e11b815260040160405180910390fd5b6001600160a01b038116610dd457604051639fabe1c160e01b815260040160405180910390fd5b6010546001600160a01b0390811690821603610e035760405163367558c360e01b815260040160405180910390fd5b601080546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f79b97624b2eef26c75b54eb94adf1e51d19018df8d5b05e3fde9dfbef209040590600090a35050565b600260065403610e805760405162461bcd60e51b8152600401610e7790613833565b60405180910390fd5b6002600655610e8d612735565b6001600655565b6007546201000090046001600160a01b03163314610ec55760405163036c8cf960e11b815260040160405180910390fd5b610ecd61298b565b565b600754600090610100900460ff16610efa576040516321c4e35760e21b815260040160405180910390fd5b600260065403610f1c5760405162461bcd60e51b8152600401610e7790613833565b6002600655610f296129dd565b610f34838333612a23565b60408051838152602081018390529295509092506001600160a01b0384169133917fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d791015b60405180910390a3600160065592915050565b6007546201000090046001600160a01b03163314610fbd5760405163036c8cf960e11b815260040160405180910390fd5b6001600160a01b038116610fe457604051639fabe1c160e01b815260040160405180910390fd5b6001600160a01b0381166000908152600a602052604090205460ff1661101d576040516353182fc160e11b815260040160405180910390fd5b6001600160a01b0381166000818152600a6020526040808220805460ff19169055517fee27a3e7a8b63b60512a9b8b1c49bdf64c712021a5d4459beddfb87fb72f55819190a250565b6000610a13611073612648565b6001600160a01b0384166000908152600560205260409020546001600160801b031690612acf565b6002600654036110bd5760405162461bcd60e51b8152600401610e7790613833565b6002600655336000818152600a602052604081205461010090046001600160f81b031690036110ff576040516370bd2a8560e11b815260040160405180910390fd5b6001600160a01b03831661112657604051639fabe1c160e01b815260040160405180910390fd5b8160000361114757604051630e5a744960e41b815260040160405180910390fd5b61115082612b11565b6001600160a01b0382166000908152600a60205260409020805460019061118690849061010090046001600160f81b031661386a565b92506101000a8154816001600160f81b0302191690836001600160f81b0316021790555081600960008282546111bc91906137d3565b9091555050600f54612710906111d29084613891565b6111dc91906138b0565b600e60008282546111ed91906137d3565b92505081905550826001600160a01b0316816001600160a01b03167f8ac0d63df3c915ef42ced3274ab222a7932776d6cc50de74d25cd5a225f420148460405161123991815260200190565b60405180910390a35050600160065550565b6007546201000090046001600160a01b0316331461127c5760405163036c8cf960e11b815260040160405180910390fd5b6001600160a01b0381166112a357604051639fabe1c160e01b815260040160405180910390fd5b6007546001600160a01b03620100009091048116908216036112d8576040516335803f0160e01b815260040160405180910390fd5b600880546001600160a01b038381166001600160a01b0319831681179093556040519116919082907fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a990600090a35050565b6007546201000090046001600160a01b0316331461135b5760405163036c8cf960e11b815260040160405180910390fd5b610ecd612b3f565b600754600090610100900460ff1661138e576040516321c4e35760e21b815260040160405180910390fd5b6002600654036113b05760405162461bcd60e51b8152600401610e7790613833565b60026006556113bd6129dd565b6113c8838333612a23565b60408051838152602081018390529195509192506001600160a01b0384169133917fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d79101610f79565b6007546201000090046001600160a01b031633146114425760405163036c8cf960e11b815260040160405180910390fd5b6105dc81111561146557604051630309cb8760e51b815260040160405180910390fd5b600f80549082905560408051828152602081018490527fd56cfcea46fe9dc52c77ef7c03b5481be192c845dcad56ac266e399cd29b1dab9101610c6b565b60606003805461097f906137f9565b6007546000906201000090046001600160a01b031633146114e65760405163036c8cf960e11b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316148061155757507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316145b15611575576040516380eb2a0160e01b815260040160405180910390fd5b6040516370a0823160e01b81523060048201526000906001600160a01b038416906370a0823190602401602060405180830381865afa1580156115bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115e091906137a4565b90508060000361160357604051630e5a744960e41b815260040160405180910390fd5b600754611623906001600160a01b03858116916201000090041683612b7c565b826001600160a01b03167f4590b594be6fdef6bd5e18792a2494ddf2156b618c7bbe48d13a92831208af058260405161165e91815260200190565b60405180910390a260019150505b919050565b6000338161167f8286612248565b9050838110156116a2576040516389532b7d60e01b815260040160405180910390fd5b6116af82868684036125ac565b506001949350505050565b60006116c7338484612678565b6040518281526001600160a01b0384169033906000805160206139ac8339815191529060200160405180910390a350600192915050565b60006002600654036117225760405162461bcd60e51b8152600401610e7790613833565b60026006556007546201000090046001600160a01b0316331480159061175357506010546001600160a01b03163314155b156117715760405163036c8cf960e11b815260040160405180910390fd5b8160000361179257604051630e5a744960e41b815260040160405180910390fd5b61179a612735565b6117cf6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016333085612be4565b81600e60008282546117e191906137d3565b909155505060405182815233907f418979cce08cdd6e1bb0e09c0b1df658cf18921d5979efb980f189b35907bb2f9060200160405180910390a250600180600655919050565b600754600090610100900460ff16611852576040516321c4e35760e21b815260040160405180910390fd5b6002600654036118745760405162461bcd60e51b8152600401610e7790613833565b600260065560008061188886858733612c1c565b91509150836001600160a01b0316856001600160a01b0316336001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db85856040516118e4929190918252602082015260400190565b60405180910390a4600160065595945050505050565b60026006540361191c5760405162461bcd60e51b8152600401610e7790613833565b6002600655336000818152600a602052604081205461010090046001600160f81b0316900361195e576040516370bd2a8560e11b815260040160405180910390fd5b6001600160a01b03831661198557604051639fabe1c160e01b815260040160405180910390fd5b816000036119a657604051630e5a744960e41b815260040160405180910390fd5b6001600160a01b0381166000908152600a602052604090205461010090046001600160f81b03168211156119ed576040516364ddcf3760e01b815260040160405180910390fd5b6119f5612735565b6119fe82612b11565b6001600160a01b0382166000908152600a602052604090208054600190611a3490849061010090046001600160f81b03166138d2565b92506101000a8154816001600160f81b0302191690836001600160f81b031602179055508160096000828254611a6a91906137e6565b90915550611aa590506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016843085612be4565b826001600160a01b0316816001600160a01b03167f8f3c36759a69d5bda5c0381c2c1137caea3a3e9547d86ec860d019f3591dd2468460405161123991815260200190565b600754600090610100900460ff16611b15576040516321c4e35760e21b815260040160405180910390fd5b600260065403611b375760405162461bcd60e51b8152600401610e7790613833565b6002600655600080611b4b86858733612c1c565b91509150836001600160a01b0316856001600160a01b0316336001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db8585604051611ba7929190918252602082015260400190565b60405180910390a4506001600655949350505050565b600260065403611bdf5760405162461bcd60e51b8152600401610e7790613833565b6002600655336000818152600a602052604090205460ff16611c1457604051630bf6175d60e11b815260040160405180910390fd5b6001600160a01b038316611c3b57604051639fabe1c160e01b815260040160405180910390fd5b81600003611c5c57604051630e5a744960e41b815260040160405180910390fd5b611c64612735565b6040516370a0823160e01b81523060048201527f0000000000000000000000000000000000000000000000000000000000000000906000906001600160a01b038316906370a0823190602401602060405180830381865afa158015611ccd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cf191906137a4565b905080600e541015611d0f57600e54611d0a90826137e6565b611d12565b60005b90506000612710600d54611d246108c4565b611d2e9190613891565b611d3891906138b0565b905080821015611d5b576040516309262c7f60e41b815260040160405180910390fd5b611d6581836137e6565b851115611d85576040516326f1bf9360e01b815260040160405180910390fd5b611d8e85612b11565b6001600160a01b0385166000908152600a602052604090208054600190611dc490849061010090046001600160f81b031661386a565b92506101000a8154816001600160f81b0302191690836001600160f81b031602179055508460096000828254611dfa91906137d3565b90915550611e1490506001600160a01b0384168787612b7c565b856001600160a01b0316846001600160a01b03167f99602732910020e2e51a839f33ced64c6b36b6b64a2c225e52cdd8ef6c07d9f987604051611e5991815260200190565b60405180910390a35050600160065550505050565b6000600260065403611e925760405162461bcd60e51b8152600401610e7790613833565b60026006556007546201000090046001600160a01b03163314801590611ec357506010546001600160a01b03163314155b15611ee15760405163036c8cf960e11b815260040160405180910390fd5b82600003611f0257604051630e5a744960e41b815260040160405180910390fd5b6001600160a01b038216611f2957604051639fabe1c160e01b815260040160405180910390fd5b600e54831115611f4c57604051634cc7b59d60e01b815260040160405180910390fd5b611f54612735565b611f886001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168385612b7c565b82600e6000828254611f9a91906137e6565b90915550506040518381526001600160a01b038316907f0529afc4538720fe0b3eadc40486369ab962002d72fead1387b300c66073e7bf9060200160405180910390a25060018060065592915050565b6000610a1382611066565b6007546201000090046001600160a01b031633146120265760405163036c8cf960e11b815260040160405180910390fd5b6001600160a01b03811661204d57604051639fabe1c160e01b815260040160405180910390fd5b600b546001600160a01b039081169082160361207c5760405163367558c360e01b815260040160405180910390fd5b600b80546001600160a01b038381166001600160a01b0319831617909255604051633724df8760e21b8152908216917f0000000000000000000000000000000000000000000000000000000000000000169063dc937e1c906120e59085906000906004016138f2565b600060405180830381600087803b1580156120ff57600080fd5b505af1158015612113573d6000803e3d6000fd5b50506040516001600160a01b038086169350841691507f1703370ea1b3aaecb46974b10cd9534323f8b62d4b5c858e78c34ac64d4e329490600090a35050565b6040516370a0823160e01b815230600482015260009081906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa1580156121bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121e091906137a4565b905080600e5410156121fe57600e546121f990826137e6565b612201565b60005b90506000612710600d546122136108c4565b61221d9190613891565b61222791906138b0565b9050808211612237576000612241565b61224181836137e6565b9250505090565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b6007546201000090046001600160a01b031633146122a45760405163036c8cf960e11b815260040160405180910390fd5b600754610100900460ff16156122cc5760405162dc149f60e41b815260040160405180910390fd5b6007805461ff001916610100179055600b80546001600160a01b038085166001600160a01b031992831617909255600c80549284169290911691909117905561231d66038d7ea4c680003380612a23565b5050604051633724df8760e21b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063dc937e1c9061236e9085906000906004016138f2565b600060405180830381600087803b15801561238857600080fd5b505af115801561239c573d6000803e3d6000fd5b5050604051633724df8760e21b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016925063dc937e1c91506123ef9084906001906004016138f2565b600060405180830381600087803b15801561240957600080fd5b505af115801561241d573d6000803e3d6000fd5b50506040517f5daa87a0e9463431830481fd4b6e3403442dfb9a12b9c07597e9f61d50b633c8925060009150a15050565b6007546201000090046001600160a01b0316331461247f5760405163036c8cf960e11b815260040160405180910390fd5b6001600160a01b0381166124a657604051639fabe1c160e01b815260040160405180910390fd5b600c546001600160a01b03908116908216036124d55760405163367558c360e01b815260040160405180910390fd5b600c80546001600160a01b038381166001600160a01b0319831617909255604051633724df8760e21b8152908216917f0000000000000000000000000000000000000000000000000000000000000000169063dc937e1c9061253e9085906001906004016138f2565b600060405180830381600087803b15801561255857600080fd5b505af115801561256c573d6000803e3d6000fd5b50506040516001600160a01b038086169350841691507f97fb01cd0e4b307e0835da37ae485767ec7107d154a4abfb2b58f3730e6f4cef90600090a35050565b6001600160a01b03831615806125c957506001600160a01b038216155b156125e757604051632b65113b60e01b815260040160405180910390fd5b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b6000805460000361266457506b033b2e3c9fd0803ce800000090565b61096b6000546126726108c4565b90612e3b565b6001600160a01b038316158061269557506001600160a01b038216155b156126b35760405163b53aab2360e01b815260040160405180910390fd5b816001600160a01b0316836001600160a01b0316036126e55760405163b3e918cb60e01b815260040160405180910390fd5b806000036127065760405163b3fcf27960e01b815260040160405180910390fd5b600061272261271d612716612648565b8490612e3b565b612e74565b905061272f848483612e9e565b50505050565b6040516346df7f7160e11b81523060048201527f0000000000000000000000000000000000000000000000000000000000000000906000906001600160a01b03831690638dbefee290602401602060405180830381865afa15801561279e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127c291906137a4565b9050801561285c576040516309a99b4f60e41b8152306004820152602481018290526001600160a01b03831690639a99b4f090604401600060405180830381600087803b15801561281257600080fd5b505af1158015612826573d6000803e3d6000fd5b50505050612710600f548261283b9190613891565b61284591906138b0565b600e600082825461285691906137d3565b90915550505b6040516370a0823160e01b81523060048201527f0000000000000000000000000000000000000000000000000000000000000000906000906001600160a01b038316906370a0823190602401602060405180830381865afa1580156128c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128e991906137a4565b9050801561272f576129256001600160a01b0383167f000000000000000000000000000000000000000000000000000000000000000083612f57565b6040516356e4bb9760e11b8152306004820152602481018290526001600160a01b0385169063adc9772e90604401600060405180830381600087803b15801561296d57600080fd5b505af1158015612981573d6000803e3d6000fd5b5050505050505050565b612993613009565b6007805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b60075460ff1615610ecd5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610e77565b6000806001600160a01b038416612a4d57604051639fabe1c160e01b815260040160405180910390fd5b84600003612a6e57604051630e5a744960e41b815260040160405180910390fd5b612a76612735565b6000612a80612648565b9050612ab76001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016853089612be4565b6000612ac4868884613052565b969795505050505050565b6000816b019d971e4fe8401e7400000019048311820215612aef57600080fd5b506b033b2e3c9fd0803ce800000091026b019d971e4fe8401e74000000010490565b60006001600160f81b03821115612b3b57604051635a7eea2760e11b815260040160405180910390fd5b5090565b612b476129dd565b6007805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586129c03390565b6040516001600160a01b038316602482015260448101829052612bdf90849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526131bd565b505050565b6040516001600160a01b038085166024830152831660448201526064810182905261272f9085906323b872dd60e01b90608401612ba8565b6000806001600160a01b0384161580612c3c57506001600160a01b038516155b15612c5a57604051639fabe1c160e01b815260040160405180910390fd5b85600003612c7b57604051630e5a744960e41b815260040160405180910390fd5b612c83612735565b60006000198703612c9e57612c9786611066565b9650600190505b836001600160a01b0316866001600160a01b031614612d3a576001600160a01b0380871660009081526001602090815260408083209388168352929052205487811015612cfe576040516364b3d8c760e01b815260040160405180910390fd5b6000198114612d3857612d1188826137e6565b6001600160a01b038089166000908152600160209081526040808320938a16835292905220555b505b6040516370a0823160e01b81523060048201527f0000000000000000000000000000000000000000000000000000000000000000906000906001600160a01b038316906370a0823190602401602060405180830381865afa158015612da3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dc791906137a4565b905080600e541015612de557600e54612de090826137e6565b612de8565b60005b905080891115612e0b576040516326f1bf9360e01b815260040160405180910390fd5b6000612e18898b8661328f565b9050612e2e6001600160a01b038416898c612b7c565b9899975050505050505050565b600281046b033b2e3c9fd0803ce80000008119048311158202612e5d57600080fd5b6b033b2e3c9fd0803ce80000009092029091010490565b60006001600160801b03821115612b3b57604051638ac92bf960e01b815260040160405180910390fd5b6001600160a01b0383166000908152600560205260409020546001600160801b039081169082161115612ee45760405163a50f989960e01b815260040160405180910390fd5b612ef88383836001600160801b0316613459565b6001600160a01b0392831660009081526005602052604080822080546001600160801b0380821686900381166fffffffffffffffffffffffffffffffff1992831617909255949095168252902080548085169092019093169116179055565b604051636eb1769f60e11b81523060048201526001600160a01b038381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa158015612fa8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fcc91906137a4565b612fd691906137d3565b6040516001600160a01b03851660248201526044810182905290915061272f90859063095ea7b360e01b90606401612ba8565b60075460ff16610ecd5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610e77565b60008061305f8484612e3b565b9050806000036130825760405163b3fcf27960e01b815260040160405180910390fd5b61308e60008683613459565b61309783612e74565b6001600160a01b038616600090815260056020526040812080546001600160801b03938416600160801b02931692909217909155805482919081906130dd9084906137d3565b909155506130ec905081612e74565b6001600160a01b0386166000908152600560205260408120805490919061311d9084906001600160801b031661392d565b92506101000a8154816001600160801b0302191690836001600160801b0316021790555060408051828152602081018590526001600160a01b038716917f4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f910160405180910390a26040518481526001600160a01b038616906000906000805160206139ac8339815191529060200160405180910390a350919392505050565b6000613212826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166134899092919063ffffffff16565b805190915015612bdf5780806020019051810190613230919061394d565b612bdf5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610e77565b60008061329a612648565b6001600160a01b0386166000908152600560205260408120549192506001600160801b0390911690846132d6576132d18684612e3b565b6132d8565b815b9050806000036132fb5760405163b3fcf27960e01b815260040160405180910390fd5b8181111561331c5760405163a50f989960e01b815260040160405180910390fd5b61332887600083613459565b61333183612e74565b6001600160a01b038816600090815260056020526040812080546001600160801b03938416600160801b02931692909217909155805482919081906133779084906137e6565b90915550613386905081612e74565b6001600160a01b038816600090815260056020526040812080549091906133b79084906001600160801b031661396f565b92506101000a8154816001600160801b0302191690836001600160801b0316021790555060408051828152602081018590526001600160a01b038916917f49995e5dd6158cf69ad3e9777c46755a1a826a446c6416992167462dad033b2a910160405180910390a26040518681526000906001600160a01b038916906000805160206139ac8339815191529060200160405180910390a3509395945050505050565b600754610100900460ff16613481576040516321c4e35760e21b815260040160405180910390fd5b612bdf6129dd565b606061349884846000856134a0565b949350505050565b6060824710156135015760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610e77565b6001600160a01b0385163b6135585760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610e77565b600080866001600160a01b03168587604051613574919061398f565b60006040518083038185875af1925050503d80600081146135b1576040519150601f19603f3d011682016040523d82523d6000602084013e6135b6565b606091505b50915091506135c68282866135d1565b979650505050505050565b606083156135e0575081610bd6565b8251156135f05782518084602001fd5b8160405162461bcd60e51b8152600401610e77919061362e565b60005b8381101561362557818101518382015260200161360d565b50506000910152565b602081526000825180602084015261364d81604085016020870161360a565b601f01601f19169190910160400192915050565b60006020828403121561367357600080fd5b5035919050565b80356001600160a01b038116811461166c57600080fd5b600080604083850312156136a457600080fd5b6136ad8361367a565b946020939093013593505050565b6000602082840312156136cd57600080fd5b610bd68261367a565b6000806000606084860312156136eb57600080fd5b6136f48461367a565b92506137026020850161367a565b9150604084013590509250925092565b6000806040838503121561372557600080fd5b823591506137356020840161367a565b90509250929050565b60008060006060848603121561375357600080fd5b833592506137636020850161367a565b91506137716040850161367a565b90509250925092565b6000806040838503121561378d57600080fd5b6137968361367a565b91506137356020840161367a565b6000602082840312156137b657600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b80820180821115610a1357610a136137bd565b81810381811115610a1357610a136137bd565b600181811c9082168061380d57607f821691505b60208210810361382d57634e487b7160e01b600052602260045260246000fd5b50919050565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b6001600160f81b0381811683821601908082111561388a5761388a6137bd565b5092915050565b60008160001904831182151516156138ab576138ab6137bd565b500290565b6000826138cd57634e487b7160e01b600052601260045260246000fd5b500490565b6001600160f81b0382811682821603908082111561388a5761388a6137bd565b6001600160a01b0383168152604081016002831061392057634e487b7160e01b600052602160045260246000fd5b8260208301529392505050565b6001600160801b0381811683821601908082111561388a5761388a6137bd565b60006020828403121561395f57600080fd5b81518015158114610bd657600080fd5b6001600160801b0382811682821603908082111561388a5761388a6137bd565b600082516139a181846020870161360a565b919091019291505056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa264697066735822122044f2632f32f061f871ee940d3dc81e0a314dab2e1f93c36e5c234813b9d9f70a64736f6c63430008100033000000000000000000000000bfd7a3dafed7c2d48b3374f6c4df946ba37395e500000000000000000000000000000000000000000000000000000000000001f4000000000000000000000000bfd7a3dafed7c2d48b3374f6c4df946ba37395e50000000000000000000000007fc66500c84a76ad7e9c93437bfc5ac33e2ddae90000000000000000000000004da27a545c0c5b758a6ba100e3a049001de870f500000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000001044756c6c6168616e2073746b416176650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000086473746b41415645000000000000000000000000000000000000000000000000

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106103fc5760003560e01c80638456cb5911610215578063bdf2878d11610125578063d85d7f5b116100b8578063f09a401611610087578063f09a401614610869578063f27ef5c91461087c578063f851a4401461088f578063fd967f47146108a8578063fed371ed146108b157600080fd5b8063d85d7f5b1461084e578063d905777e14610815578063dd62ed3e14610856578063ef8b30f71461043157600080fd5b8063c838ccb6116100f4578063c838ccb6146107ef578063ce96cb7714610815578063cfb982c814610828578063d6d5784f1461083b57600080fd5b8063bdf2878d146107b5578063c415565f146107dc578063c63d75b6146105aa578063c6e6f5921461043157600080fd5b8063a9059cbb116101a8578063b553c08511610177578063b553c08514610717578063b6e1a2f11461072a578063ba0876521461077c578063ba0a3a581461078f578063bb004abc146107a257600080fd5b8063a9059cbb146106de578063b17d718e146106f1578063b3d7f6b914610431578063b460af941461070457600080fd5b80639d8e2177116101e45780639d8e2177146106a05780639e8c708e146106af578063a37f6911146106c2578063a457c2d7146106cb57600080fd5b80638456cb591461066a57806394bf804d1461067257806395d1d05b1461068557806395d89b411461069857600080fd5b806338d52e0f116103105780634cdad506116102a35780636f8b4530116102725780636f8b4530146106165780636fb36bcb1461061e57806370a082311461063157806371526ce51461064457806375829def1461065757600080fd5b80634cdad506146104315780635c975abb146105ef578063659db576146105fa5780636e553f651461060357600080fd5b80633f4ba83a116102df5780633f4ba83a146105a2578063402d267d146105aa57806348ccda3c146105bf5780634b09b72a146105e657600080fd5b806338d52e0f1461054e578063395093511461057457806339c00de91461058757806339c423d11461059a57600080fd5b8063158ef93e11610393578063264f6bb311610362578063264f6bb3146104df57806326782247146104f25780632a9950be1461051d578063313ce5671461053057806333a581d21461054557600080fd5b8063158ef93e1461048057806318160ddd146104925780631da24f3e1461049a57806323b872dd146104cc57600080fd5b80630a28a477116103cf5780630a28a477146104315780630c7d5cd8146104655780630d9005ae1461046e5780630e18b6811461047657600080fd5b806301e1d1141461040157806306fdde031461041c57806307a2d13a14610431578063095ea7b314610442575b600080fd5b6104096108c4565b6040519081526020015b60405180910390f35b610424610970565b604051610413919061362e565b61040961043f366004613661565b90565b610455610450366004613691565b610a02565b6040519015158152602001610413565b610409600f5481565b610409610a19565b61047e610a23565b005b60075461045590610100900460ff1681565b610409610af7565b6104096104a83660046136bb565b6001600160a01b03166000908152600560205260409020546001600160801b031690565b6104556104da3660046136d6565b610b01565b61047e6104ed366004613661565b610bdd565b600854610505906001600160a01b031681565b6040516001600160a01b039091168152602001610413565b61047e61052b3660046136bb565b610c77565b60045460405160ff9091168152602001610413565b61040960001981565b7f0000000000000000000000004da27a545c0c5b758a6ba100e3a049001de870f5610505565b610455610582366004613691565b610d55565b61047e6105953660046136bb565b610d7c565b61047e610e55565b61047e610e94565b6104096105b83660046136bb565b5060001990565b6105057f0000000000000000000000007fc66500c84a76ad7e9c93437bfc5ac33e2ddae981565b610409600e5481565b60075460ff16610455565b61040960095481565b610409610611366004613712565b610ecf565b600054610409565b61047e61062c3660046136bb565b610f8c565b61040961063f3660046136bb565b611066565b61047e610652366004613691565b61109b565b61047e6106653660046136bb565b61124b565b61047e61132a565b610409610680366004613712565b611363565b61047e610693366004613661565b611411565b6104246114a3565b610409670de0b6b3a764000081565b6104556106bd3660046136bb565b6114b2565b610409600d5481565b6104556106d9366004613691565b611671565b6104556106ec366004613691565b6116ba565b6104556106ff366004613661565b6116fe565b61040961071236600461373e565b611827565b61047e610725366004613691565b6118fa565b61075d6107383660046136bb565b600a6020526000908152604090205460ff81169061010090046001600160f81b031682565b6040805192151583526001600160f81b03909116602083015201610413565b61040961078a36600461373e565b611aea565b61047e61079d366004613691565b611bbd565b601054610505906001600160a01b031681565b6105057f0000000000000000000000004da27a545c0c5b758a6ba100e3a049001de870f581565b6104556107ea366004613712565b611e6e565b600b54600c54604080516001600160a01b03938416815292909116602083015201610413565b6104096108233660046136bb565b611fea565b61047e6108363660046136bb565b611ff5565b600b54610505906001600160a01b031681565b610409612153565b61040961086436600461377a565b612248565b61047e61087736600461377a565b612273565b61047e61088a3660046136bb565b61244e565b600754610505906201000090046001600160a01b031681565b61040961271081565b600c54610505906001600160a01b031681565b600e546009546040516370a0823160e01b815230600482015260009291906001600160a01b037f0000000000000000000000004da27a545c0c5b758a6ba100e3a049001de870f516906370a0823190602401602060405180830381865afa158015610933573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061095791906137a4565b61096191906137d3565b61096b91906137e6565b905090565b60606002805461097f906137f9565b80601f01602080910402602001604051908101604052809291908181526020018280546109ab906137f9565b80156109f85780601f106109cd576101008083540402835291602001916109f8565b820191906000526020600020905b8154815290600101906020018083116109db57829003601f168201915b5050505050905090565b6000610a0f3384846125ac565b5060015b92915050565b600061096b612648565b6008546001600160a01b03163314610a4e57604051630ac6491560e01b815260040160405180910390fd5b6008805460078054620100006001600160a01b0380851682810262010000600160b01b03198516179094556001600160a01b03199094169094556040519193900490911690829082907ff8ccb027dfcd135e000e9d45e6cc2d662578a8825d4c45b5e32e0adf67e79ec690600090a36040516000906001600160a01b038416907fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9908390a35050565b600061096b6108c4565b6001600160a01b038316600090815260016020908152604080832033845290915281205482811015610b46576040516364b3d8c760e01b815260040160405180910390fd5b6000198114610b8a576001600160a01b038516600090815260016020908152604080832033808552925290912054610b8a918791610b859087906137e6565b6125ac565b610b95858585612678565b836001600160a01b0316856001600160a01b03166000805160206139ac83398151915285604051610bc891815260200190565b60405180910390a360019150505b9392505050565b6007546201000090046001600160a01b03163314610c0e5760405163036c8cf960e11b815260040160405180910390fd5b6105dc811115610c3157604051630309cb8760e51b815260040160405180910390fd5b600d80549082905560408051828152602081018490527ff4eb55c9d5784e11db6a6ec12075c6539bbf1f33dd6e5167d622dd409570688d91015b60405180910390a15050565b6007546201000090046001600160a01b03163314610ca85760405163036c8cf960e11b815260040160405180910390fd5b6001600160a01b038116610ccf57604051639fabe1c160e01b815260040160405180910390fd5b6001600160a01b0381166000908152600a602052604090205460ff1615610d09576040516351b6234d60e11b815260040160405180910390fd5b6001600160a01b0381166000818152600a6020526040808220805460ff19166001179055517f24a580edd7d72eaf169d7530d023d8e608352e77e0e132cff8c2a8955b00bb279190a250565b600033610d72818585610d688383612248565b610b8591906137d3565b5060019392505050565b6007546201000090046001600160a01b03163314610dad5760405163036c8cf960e11b815260040160405180910390fd5b6001600160a01b038116610dd457604051639fabe1c160e01b815260040160405180910390fd5b6010546001600160a01b0390811690821603610e035760405163367558c360e01b815260040160405180910390fd5b601080546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f79b97624b2eef26c75b54eb94adf1e51d19018df8d5b05e3fde9dfbef209040590600090a35050565b600260065403610e805760405162461bcd60e51b8152600401610e7790613833565b60405180910390fd5b6002600655610e8d612735565b6001600655565b6007546201000090046001600160a01b03163314610ec55760405163036c8cf960e11b815260040160405180910390fd5b610ecd61298b565b565b600754600090610100900460ff16610efa576040516321c4e35760e21b815260040160405180910390fd5b600260065403610f1c5760405162461bcd60e51b8152600401610e7790613833565b6002600655610f296129dd565b610f34838333612a23565b60408051838152602081018390529295509092506001600160a01b0384169133917fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d791015b60405180910390a3600160065592915050565b6007546201000090046001600160a01b03163314610fbd5760405163036c8cf960e11b815260040160405180910390fd5b6001600160a01b038116610fe457604051639fabe1c160e01b815260040160405180910390fd5b6001600160a01b0381166000908152600a602052604090205460ff1661101d576040516353182fc160e11b815260040160405180910390fd5b6001600160a01b0381166000818152600a6020526040808220805460ff19169055517fee27a3e7a8b63b60512a9b8b1c49bdf64c712021a5d4459beddfb87fb72f55819190a250565b6000610a13611073612648565b6001600160a01b0384166000908152600560205260409020546001600160801b031690612acf565b6002600654036110bd5760405162461bcd60e51b8152600401610e7790613833565b6002600655336000818152600a602052604081205461010090046001600160f81b031690036110ff576040516370bd2a8560e11b815260040160405180910390fd5b6001600160a01b03831661112657604051639fabe1c160e01b815260040160405180910390fd5b8160000361114757604051630e5a744960e41b815260040160405180910390fd5b61115082612b11565b6001600160a01b0382166000908152600a60205260409020805460019061118690849061010090046001600160f81b031661386a565b92506101000a8154816001600160f81b0302191690836001600160f81b0316021790555081600960008282546111bc91906137d3565b9091555050600f54612710906111d29084613891565b6111dc91906138b0565b600e60008282546111ed91906137d3565b92505081905550826001600160a01b0316816001600160a01b03167f8ac0d63df3c915ef42ced3274ab222a7932776d6cc50de74d25cd5a225f420148460405161123991815260200190565b60405180910390a35050600160065550565b6007546201000090046001600160a01b0316331461127c5760405163036c8cf960e11b815260040160405180910390fd5b6001600160a01b0381166112a357604051639fabe1c160e01b815260040160405180910390fd5b6007546001600160a01b03620100009091048116908216036112d8576040516335803f0160e01b815260040160405180910390fd5b600880546001600160a01b038381166001600160a01b0319831681179093556040519116919082907fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a990600090a35050565b6007546201000090046001600160a01b0316331461135b5760405163036c8cf960e11b815260040160405180910390fd5b610ecd612b3f565b600754600090610100900460ff1661138e576040516321c4e35760e21b815260040160405180910390fd5b6002600654036113b05760405162461bcd60e51b8152600401610e7790613833565b60026006556113bd6129dd565b6113c8838333612a23565b60408051838152602081018390529195509192506001600160a01b0384169133917fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d79101610f79565b6007546201000090046001600160a01b031633146114425760405163036c8cf960e11b815260040160405180910390fd5b6105dc81111561146557604051630309cb8760e51b815260040160405180910390fd5b600f80549082905560408051828152602081018490527fd56cfcea46fe9dc52c77ef7c03b5481be192c845dcad56ac266e399cd29b1dab9101610c6b565b60606003805461097f906137f9565b6007546000906201000090046001600160a01b031633146114e65760405163036c8cf960e11b815260040160405180910390fd5b7f0000000000000000000000007fc66500c84a76ad7e9c93437bfc5ac33e2ddae96001600160a01b0316826001600160a01b0316148061155757507f0000000000000000000000004da27a545c0c5b758a6ba100e3a049001de870f56001600160a01b0316826001600160a01b0316145b15611575576040516380eb2a0160e01b815260040160405180910390fd5b6040516370a0823160e01b81523060048201526000906001600160a01b038416906370a0823190602401602060405180830381865afa1580156115bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115e091906137a4565b90508060000361160357604051630e5a744960e41b815260040160405180910390fd5b600754611623906001600160a01b03858116916201000090041683612b7c565b826001600160a01b03167f4590b594be6fdef6bd5e18792a2494ddf2156b618c7bbe48d13a92831208af058260405161165e91815260200190565b60405180910390a260019150505b919050565b6000338161167f8286612248565b9050838110156116a2576040516389532b7d60e01b815260040160405180910390fd5b6116af82868684036125ac565b506001949350505050565b60006116c7338484612678565b6040518281526001600160a01b0384169033906000805160206139ac8339815191529060200160405180910390a350600192915050565b60006002600654036117225760405162461bcd60e51b8152600401610e7790613833565b60026006556007546201000090046001600160a01b0316331480159061175357506010546001600160a01b03163314155b156117715760405163036c8cf960e11b815260040160405180910390fd5b8160000361179257604051630e5a744960e41b815260040160405180910390fd5b61179a612735565b6117cf6001600160a01b037f0000000000000000000000004da27a545c0c5b758a6ba100e3a049001de870f516333085612be4565b81600e60008282546117e191906137d3565b909155505060405182815233907f418979cce08cdd6e1bb0e09c0b1df658cf18921d5979efb980f189b35907bb2f9060200160405180910390a250600180600655919050565b600754600090610100900460ff16611852576040516321c4e35760e21b815260040160405180910390fd5b6002600654036118745760405162461bcd60e51b8152600401610e7790613833565b600260065560008061188886858733612c1c565b91509150836001600160a01b0316856001600160a01b0316336001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db85856040516118e4929190918252602082015260400190565b60405180910390a4600160065595945050505050565b60026006540361191c5760405162461bcd60e51b8152600401610e7790613833565b6002600655336000818152600a602052604081205461010090046001600160f81b0316900361195e576040516370bd2a8560e11b815260040160405180910390fd5b6001600160a01b03831661198557604051639fabe1c160e01b815260040160405180910390fd5b816000036119a657604051630e5a744960e41b815260040160405180910390fd5b6001600160a01b0381166000908152600a602052604090205461010090046001600160f81b03168211156119ed576040516364ddcf3760e01b815260040160405180910390fd5b6119f5612735565b6119fe82612b11565b6001600160a01b0382166000908152600a602052604090208054600190611a3490849061010090046001600160f81b03166138d2565b92506101000a8154816001600160f81b0302191690836001600160f81b031602179055508160096000828254611a6a91906137e6565b90915550611aa590506001600160a01b037f0000000000000000000000004da27a545c0c5b758a6ba100e3a049001de870f516843085612be4565b826001600160a01b0316816001600160a01b03167f8f3c36759a69d5bda5c0381c2c1137caea3a3e9547d86ec860d019f3591dd2468460405161123991815260200190565b600754600090610100900460ff16611b15576040516321c4e35760e21b815260040160405180910390fd5b600260065403611b375760405162461bcd60e51b8152600401610e7790613833565b6002600655600080611b4b86858733612c1c565b91509150836001600160a01b0316856001600160a01b0316336001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db8585604051611ba7929190918252602082015260400190565b60405180910390a4506001600655949350505050565b600260065403611bdf5760405162461bcd60e51b8152600401610e7790613833565b6002600655336000818152600a602052604090205460ff16611c1457604051630bf6175d60e11b815260040160405180910390fd5b6001600160a01b038316611c3b57604051639fabe1c160e01b815260040160405180910390fd5b81600003611c5c57604051630e5a744960e41b815260040160405180910390fd5b611c64612735565b6040516370a0823160e01b81523060048201527f0000000000000000000000004da27a545c0c5b758a6ba100e3a049001de870f5906000906001600160a01b038316906370a0823190602401602060405180830381865afa158015611ccd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cf191906137a4565b905080600e541015611d0f57600e54611d0a90826137e6565b611d12565b60005b90506000612710600d54611d246108c4565b611d2e9190613891565b611d3891906138b0565b905080821015611d5b576040516309262c7f60e41b815260040160405180910390fd5b611d6581836137e6565b851115611d85576040516326f1bf9360e01b815260040160405180910390fd5b611d8e85612b11565b6001600160a01b0385166000908152600a602052604090208054600190611dc490849061010090046001600160f81b031661386a565b92506101000a8154816001600160f81b0302191690836001600160f81b031602179055508460096000828254611dfa91906137d3565b90915550611e1490506001600160a01b0384168787612b7c565b856001600160a01b0316846001600160a01b03167f99602732910020e2e51a839f33ced64c6b36b6b64a2c225e52cdd8ef6c07d9f987604051611e5991815260200190565b60405180910390a35050600160065550505050565b6000600260065403611e925760405162461bcd60e51b8152600401610e7790613833565b60026006556007546201000090046001600160a01b03163314801590611ec357506010546001600160a01b03163314155b15611ee15760405163036c8cf960e11b815260040160405180910390fd5b82600003611f0257604051630e5a744960e41b815260040160405180910390fd5b6001600160a01b038216611f2957604051639fabe1c160e01b815260040160405180910390fd5b600e54831115611f4c57604051634cc7b59d60e01b815260040160405180910390fd5b611f54612735565b611f886001600160a01b037f0000000000000000000000004da27a545c0c5b758a6ba100e3a049001de870f5168385612b7c565b82600e6000828254611f9a91906137e6565b90915550506040518381526001600160a01b038316907f0529afc4538720fe0b3eadc40486369ab962002d72fead1387b300c66073e7bf9060200160405180910390a25060018060065592915050565b6000610a1382611066565b6007546201000090046001600160a01b031633146120265760405163036c8cf960e11b815260040160405180910390fd5b6001600160a01b03811661204d57604051639fabe1c160e01b815260040160405180910390fd5b600b546001600160a01b039081169082160361207c5760405163367558c360e01b815260040160405180910390fd5b600b80546001600160a01b038381166001600160a01b0319831617909255604051633724df8760e21b8152908216917f0000000000000000000000004da27a545c0c5b758a6ba100e3a049001de870f5169063dc937e1c906120e59085906000906004016138f2565b600060405180830381600087803b1580156120ff57600080fd5b505af1158015612113573d6000803e3d6000fd5b50506040516001600160a01b038086169350841691507f1703370ea1b3aaecb46974b10cd9534323f8b62d4b5c858e78c34ac64d4e329490600090a35050565b6040516370a0823160e01b815230600482015260009081906001600160a01b037f0000000000000000000000004da27a545c0c5b758a6ba100e3a049001de870f516906370a0823190602401602060405180830381865afa1580156121bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121e091906137a4565b905080600e5410156121fe57600e546121f990826137e6565b612201565b60005b90506000612710600d546122136108c4565b61221d9190613891565b61222791906138b0565b9050808211612237576000612241565b61224181836137e6565b9250505090565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b6007546201000090046001600160a01b031633146122a45760405163036c8cf960e11b815260040160405180910390fd5b600754610100900460ff16156122cc5760405162dc149f60e41b815260040160405180910390fd5b6007805461ff001916610100179055600b80546001600160a01b038085166001600160a01b031992831617909255600c80549284169290911691909117905561231d66038d7ea4c680003380612a23565b5050604051633724df8760e21b81526001600160a01b037f0000000000000000000000004da27a545c0c5b758a6ba100e3a049001de870f5169063dc937e1c9061236e9085906000906004016138f2565b600060405180830381600087803b15801561238857600080fd5b505af115801561239c573d6000803e3d6000fd5b5050604051633724df8760e21b81526001600160a01b037f0000000000000000000000004da27a545c0c5b758a6ba100e3a049001de870f516925063dc937e1c91506123ef9084906001906004016138f2565b600060405180830381600087803b15801561240957600080fd5b505af115801561241d573d6000803e3d6000fd5b50506040517f5daa87a0e9463431830481fd4b6e3403442dfb9a12b9c07597e9f61d50b633c8925060009150a15050565b6007546201000090046001600160a01b0316331461247f5760405163036c8cf960e11b815260040160405180910390fd5b6001600160a01b0381166124a657604051639fabe1c160e01b815260040160405180910390fd5b600c546001600160a01b03908116908216036124d55760405163367558c360e01b815260040160405180910390fd5b600c80546001600160a01b038381166001600160a01b0319831617909255604051633724df8760e21b8152908216917f0000000000000000000000004da27a545c0c5b758a6ba100e3a049001de870f5169063dc937e1c9061253e9085906001906004016138f2565b600060405180830381600087803b15801561255857600080fd5b505af115801561256c573d6000803e3d6000fd5b50506040516001600160a01b038086169350841691507f97fb01cd0e4b307e0835da37ae485767ec7107d154a4abfb2b58f3730e6f4cef90600090a35050565b6001600160a01b03831615806125c957506001600160a01b038216155b156125e757604051632b65113b60e01b815260040160405180910390fd5b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b6000805460000361266457506b033b2e3c9fd0803ce800000090565b61096b6000546126726108c4565b90612e3b565b6001600160a01b038316158061269557506001600160a01b038216155b156126b35760405163b53aab2360e01b815260040160405180910390fd5b816001600160a01b0316836001600160a01b0316036126e55760405163b3e918cb60e01b815260040160405180910390fd5b806000036127065760405163b3fcf27960e01b815260040160405180910390fd5b600061272261271d612716612648565b8490612e3b565b612e74565b905061272f848483612e9e565b50505050565b6040516346df7f7160e11b81523060048201527f0000000000000000000000004da27a545c0c5b758a6ba100e3a049001de870f5906000906001600160a01b03831690638dbefee290602401602060405180830381865afa15801561279e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127c291906137a4565b9050801561285c576040516309a99b4f60e41b8152306004820152602481018290526001600160a01b03831690639a99b4f090604401600060405180830381600087803b15801561281257600080fd5b505af1158015612826573d6000803e3d6000fd5b50505050612710600f548261283b9190613891565b61284591906138b0565b600e600082825461285691906137d3565b90915550505b6040516370a0823160e01b81523060048201527f0000000000000000000000007fc66500c84a76ad7e9c93437bfc5ac33e2ddae9906000906001600160a01b038316906370a0823190602401602060405180830381865afa1580156128c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128e991906137a4565b9050801561272f576129256001600160a01b0383167f0000000000000000000000004da27a545c0c5b758a6ba100e3a049001de870f583612f57565b6040516356e4bb9760e11b8152306004820152602481018290526001600160a01b0385169063adc9772e90604401600060405180830381600087803b15801561296d57600080fd5b505af1158015612981573d6000803e3d6000fd5b5050505050505050565b612993613009565b6007805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b60075460ff1615610ecd5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610e77565b6000806001600160a01b038416612a4d57604051639fabe1c160e01b815260040160405180910390fd5b84600003612a6e57604051630e5a744960e41b815260040160405180910390fd5b612a76612735565b6000612a80612648565b9050612ab76001600160a01b037f0000000000000000000000004da27a545c0c5b758a6ba100e3a049001de870f516853089612be4565b6000612ac4868884613052565b969795505050505050565b6000816b019d971e4fe8401e7400000019048311820215612aef57600080fd5b506b033b2e3c9fd0803ce800000091026b019d971e4fe8401e74000000010490565b60006001600160f81b03821115612b3b57604051635a7eea2760e11b815260040160405180910390fd5b5090565b612b476129dd565b6007805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586129c03390565b6040516001600160a01b038316602482015260448101829052612bdf90849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526131bd565b505050565b6040516001600160a01b038085166024830152831660448201526064810182905261272f9085906323b872dd60e01b90608401612ba8565b6000806001600160a01b0384161580612c3c57506001600160a01b038516155b15612c5a57604051639fabe1c160e01b815260040160405180910390fd5b85600003612c7b57604051630e5a744960e41b815260040160405180910390fd5b612c83612735565b60006000198703612c9e57612c9786611066565b9650600190505b836001600160a01b0316866001600160a01b031614612d3a576001600160a01b0380871660009081526001602090815260408083209388168352929052205487811015612cfe576040516364b3d8c760e01b815260040160405180910390fd5b6000198114612d3857612d1188826137e6565b6001600160a01b038089166000908152600160209081526040808320938a16835292905220555b505b6040516370a0823160e01b81523060048201527f0000000000000000000000004da27a545c0c5b758a6ba100e3a049001de870f5906000906001600160a01b038316906370a0823190602401602060405180830381865afa158015612da3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dc791906137a4565b905080600e541015612de557600e54612de090826137e6565b612de8565b60005b905080891115612e0b576040516326f1bf9360e01b815260040160405180910390fd5b6000612e18898b8661328f565b9050612e2e6001600160a01b038416898c612b7c565b9899975050505050505050565b600281046b033b2e3c9fd0803ce80000008119048311158202612e5d57600080fd5b6b033b2e3c9fd0803ce80000009092029091010490565b60006001600160801b03821115612b3b57604051638ac92bf960e01b815260040160405180910390fd5b6001600160a01b0383166000908152600560205260409020546001600160801b039081169082161115612ee45760405163a50f989960e01b815260040160405180910390fd5b612ef88383836001600160801b0316613459565b6001600160a01b0392831660009081526005602052604080822080546001600160801b0380821686900381166fffffffffffffffffffffffffffffffff1992831617909255949095168252902080548085169092019093169116179055565b604051636eb1769f60e11b81523060048201526001600160a01b038381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa158015612fa8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fcc91906137a4565b612fd691906137d3565b6040516001600160a01b03851660248201526044810182905290915061272f90859063095ea7b360e01b90606401612ba8565b60075460ff16610ecd5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610e77565b60008061305f8484612e3b565b9050806000036130825760405163b3fcf27960e01b815260040160405180910390fd5b61308e60008683613459565b61309783612e74565b6001600160a01b038616600090815260056020526040812080546001600160801b03938416600160801b02931692909217909155805482919081906130dd9084906137d3565b909155506130ec905081612e74565b6001600160a01b0386166000908152600560205260408120805490919061311d9084906001600160801b031661392d565b92506101000a8154816001600160801b0302191690836001600160801b0316021790555060408051828152602081018590526001600160a01b038716917f4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f910160405180910390a26040518481526001600160a01b038616906000906000805160206139ac8339815191529060200160405180910390a350919392505050565b6000613212826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166134899092919063ffffffff16565b805190915015612bdf5780806020019051810190613230919061394d565b612bdf5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610e77565b60008061329a612648565b6001600160a01b0386166000908152600560205260408120549192506001600160801b0390911690846132d6576132d18684612e3b565b6132d8565b815b9050806000036132fb5760405163b3fcf27960e01b815260040160405180910390fd5b8181111561331c5760405163a50f989960e01b815260040160405180910390fd5b61332887600083613459565b61333183612e74565b6001600160a01b038816600090815260056020526040812080546001600160801b03938416600160801b02931692909217909155805482919081906133779084906137e6565b90915550613386905081612e74565b6001600160a01b038816600090815260056020526040812080549091906133b79084906001600160801b031661396f565b92506101000a8154816001600160801b0302191690836001600160801b0316021790555060408051828152602081018590526001600160a01b038916917f49995e5dd6158cf69ad3e9777c46755a1a826a446c6416992167462dad033b2a910160405180910390a26040518681526000906001600160a01b038916906000805160206139ac8339815191529060200160405180910390a3509395945050505050565b600754610100900460ff16613481576040516321c4e35760e21b815260040160405180910390fd5b612bdf6129dd565b606061349884846000856134a0565b949350505050565b6060824710156135015760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610e77565b6001600160a01b0385163b6135585760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610e77565b600080866001600160a01b03168587604051613574919061398f565b60006040518083038185875af1925050503d80600081146135b1576040519150601f19603f3d011682016040523d82523d6000602084013e6135b6565b606091505b50915091506135c68282866135d1565b979650505050505050565b606083156135e0575081610bd6565b8251156135f05782518084602001fd5b8160405162461bcd60e51b8152600401610e77919061362e565b60005b8381101561362557818101518382015260200161360d565b50506000910152565b602081526000825180602084015261364d81604085016020870161360a565b601f01601f19169190910160400192915050565b60006020828403121561367357600080fd5b5035919050565b80356001600160a01b038116811461166c57600080fd5b600080604083850312156136a457600080fd5b6136ad8361367a565b946020939093013593505050565b6000602082840312156136cd57600080fd5b610bd68261367a565b6000806000606084860312156136eb57600080fd5b6136f48461367a565b92506137026020850161367a565b9150604084013590509250925092565b6000806040838503121561372557600080fd5b823591506137356020840161367a565b90509250929050565b60008060006060848603121561375357600080fd5b833592506137636020850161367a565b91506137716040850161367a565b90509250925092565b6000806040838503121561378d57600080fd5b6137968361367a565b91506137356020840161367a565b6000602082840312156137b657600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b80820180821115610a1357610a136137bd565b81810381811115610a1357610a136137bd565b600181811c9082168061380d57607f821691505b60208210810361382d57634e487b7160e01b600052602260045260246000fd5b50919050565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b6001600160f81b0381811683821601908082111561388a5761388a6137bd565b5092915050565b60008160001904831182151516156138ab576138ab6137bd565b500290565b6000826138cd57634e487b7160e01b600052601260045260246000fd5b500490565b6001600160f81b0382811682821603908082111561388a5761388a6137bd565b6001600160a01b0383168152604081016002831061392057634e487b7160e01b600052602160045260246000fd5b8260208301529392505050565b6001600160801b0381811683821601908082111561388a5761388a6137bd565b60006020828403121561395f57600080fd5b81518015158114610bd657600080fd5b6001600160801b0382811682821603908082111561388a5761388a6137bd565b600082516139a181846020870161360a565b919091019291505056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa264697066735822122044f2632f32f061f871ee940d3dc81e0a314dab2e1f93c36e5c234813b9d9f70a64736f6c63430008100033

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

000000000000000000000000bfd7a3dafed7c2d48b3374f6c4df946ba37395e500000000000000000000000000000000000000000000000000000000000001f4000000000000000000000000bfd7a3dafed7c2d48b3374f6c4df946ba37395e50000000000000000000000007fc66500c84a76ad7e9c93437bfc5ac33e2ddae90000000000000000000000004da27a545c0c5b758a6ba100e3a049001de870f500000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000001044756c6c6168616e2073746b416176650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000086473746b41415645000000000000000000000000000000000000000000000000

-----Decoded View---------------
Arg [0] : _admin (address): 0xbFd7a3DafeD7C2d48b3374F6C4DF946bA37395e5
Arg [1] : _reserveRatio (uint256): 500
Arg [2] : _reserveManager (address): 0xbFd7a3DafeD7C2d48b3374F6C4DF946bA37395e5
Arg [3] : _aave (address): 0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9
Arg [4] : _stkAave (address): 0x4da27a545c0c5B758a6BA100e3a049001de870f5
Arg [5] : _name (string): Dullahan stkAave
Arg [6] : _symbol (string): dstkAAVE

-----Encoded View---------------
11 Constructor Arguments found :
Arg [0] : 000000000000000000000000bfd7a3dafed7c2d48b3374f6c4df946ba37395e5
Arg [1] : 00000000000000000000000000000000000000000000000000000000000001f4
Arg [2] : 000000000000000000000000bfd7a3dafed7c2d48b3374f6c4df946ba37395e5
Arg [3] : 0000000000000000000000007fc66500c84a76ad7e9c93437bfc5ac33e2ddae9
Arg [4] : 0000000000000000000000004da27a545c0c5b758a6ba100e3a049001de870f5
Arg [5] : 00000000000000000000000000000000000000000000000000000000000000e0
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000120
Arg [7] : 0000000000000000000000000000000000000000000000000000000000000010
Arg [8] : 44756c6c6168616e2073746b4161766500000000000000000000000000000000
Arg [9] : 0000000000000000000000000000000000000000000000000000000000000008
Arg [10] : 6473746b41415645000000000000000000000000000000000000000000000000


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.