ETH Price: $3,260.42 (+4.80%)
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

Please try again later

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
USDI

Compiler Version
v0.8.9+commit.e5eed63a

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 19 : USDI.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;

import "./IUSDI.sol";

import "./token/UFragments.sol";
import "./lending/Vault.sol";

import "./_external/IERC20.sol";
import "./_external/compound/ExponentialNoError.sol";
import "./_external/openzeppelin/PausableUpgradeable.sol";

/// @title USDI token contract
/// @notice handles all minting/burning of usdi
/// @dev extends UFragments
contract USDI is Initializable, PausableUpgradeable, UFragments, IUSDI, ExponentialNoError {
  IERC20 public _reserve;
  IVaultController public _VaultController;

  address public _pauser;

  /// @notice checks if _msgSender() is VaultController
  modifier onlyVaultController() {
    require(_msgSender() == address(_VaultController), "only VaultController");
    _;
  }

  /// @notice checks if _msgSender() is pauser
  modifier onlyPauser() {
    require(_msgSender() == address(_pauser), "only pauser");
    _;
  }

  /// @notice any function with this modifier will call the pay_interest() function before any function logic is called
  modifier paysInterest() {
    _VaultController.calculateInterest();
    _;
  }

  /// @notice initializer for contract
  /// @param reserveAddr the address of USDC
  /// @dev consider adding decimals?
  function initialize(address reserveAddr) public override initializer {
    __UFragments_init("USDI Token", "USDI");
    __Pausable_init();
    _reserve = IERC20(reserveAddr);
  }

  ///@notice sets the pauser for both USDI and VaultController
  ///@notice the pauser is a separate role from the owner
  function setPauser(address pauser_) external override onlyOwner {
    _pauser = pauser_;
  }

  /// @notice pause contract, pauser only
  function pause() external override onlyPauser {
    _pause();
  }

  /// @notice unpause contract, pauser only
  function unpause() external override onlyPauser {
    _unpause();
  }

  ///@notice gets the pauser for both USDI and VaultController
  function pauser() public view returns (address) {
    return _pauser;
  }

  ///@notice gets the owner of the USDI contract
  function owner() public view override(IUSDI, OwnableUpgradeable) returns (address) {
    return super.owner();
  }

  /// @notice getter for name
  /// @return name of token
  function name() public view override(IERC20Metadata, ERC20Detailed) returns (string memory) {
    return super.name();
  }

  /// @notice getter for symbol
  /// @return symbol for token
  function symbol() public view override(IERC20Metadata, ERC20Detailed) returns (string memory) {
    return super.symbol();
  }

  /// @notice getter for decimals
  /// @return decimals for token
  function decimals() public view override(IERC20Metadata, ERC20Detailed) returns (uint8) {
    return super.decimals();
  }

  /// @notice getter for address of the reserve currency, or usdc
  /// @return decimals for of reserve currency
  function reserveAddress() public view override returns (address) {
    return address(_reserve);
  }

  /// @notice get the VaultController addr
  /// @return vaultcontroller addr
  function getVaultController() public view override returns (address) {
    return address(_VaultController);
  }

  /// @notice set the VaultController addr so that vault_master may mint/burn USDi without restriction
  /// @param vault_master_address address of vault master
  function setVaultController(address vault_master_address) external override onlyOwner {
    _VaultController = IVaultController(vault_master_address);
  }

  /// @notice deposit USDC to mint USDi
  /// @dev caller should obtain 1e12 USDi for each USDC
  /// the calculations for deposit mimic the calculations done by mint in the ampleforth contract, simply with the usdc transfer
  /// "fragments" are the units that we see, so 1000 fragments == 1000 USDi
  /// "gons" are the internal accounting unit, used to keep scale.
  /// we use the variable _gonsPerFragment in order to convert between the two
  /// try dimensional analysis when doing the math in order to verify units are correct
  /// @param usdc_amount amount of USDC to deposit
  function deposit(uint256 usdc_amount) external override paysInterest whenNotPaused {
    // scale the usdc_amount to the usdi decimal amount, aka 1e18. since usdc is 6 decimals, we multiply by 1e12
    uint256 amount = usdc_amount * 1e12;
    require(amount > 0, "Cannot deposit 0");
    // check allowance and ensure transfer success
    uint256 allowance = _reserve.allowance(_msgSender(), address(this));
    require(allowance >= usdc_amount, "Insufficient Allowance");
    require(_reserve.transferFrom(_msgSender(), address(this), usdc_amount), "transfer failed");
    // the gonbalances of the sender is in gons, therefore we must multiply the deposit amount, which is in fragments, by gonsperfragment
    _gonBalances[_msgSender()] = _gonBalances[_msgSender()] + amount * _gonsPerFragment;
    // total supply is in fragments, and so we add amount
    _totalSupply = _totalSupply + amount;
    // and totalgons of course is in gons, and so we multiply amount by gonsperfragment to get the amount of gons we must add to totalGons
    _totalGons = _totalGons + amount * _gonsPerFragment;

    emit Transfer(address(0), _msgSender(), amount);
    emit Deposit(_msgSender(), amount);
  }

  /// @notice withdraw USDC by burning USDi
  /// caller should obtain 1 USDC for every 1e12 USDi
  /// @param usdc_amount amount of USDC to withdraw
  function withdraw(uint256 usdc_amount) external override paysInterest whenNotPaused {
    // scale the usdc_amount to the USDi decimal amount, aka 1e18
    uint256 amount = usdc_amount * 1e12;
    // check balances all around
    require(amount <= this.balanceOf(_msgSender()), "insufficient funds");
    require(amount > 0, "Cannot withdraw 0");
    uint256 balance = _reserve.balanceOf(address(this));
    require(balance >= usdc_amount, "Insufficient Reserve in Bank");
    // ensure transfer success
    require(_reserve.transfer(_msgSender(), usdc_amount), "transfer failed");
    // modify the gonbalances of the sender, subtracting the amount of gons, therefore amount*gonsperfragment
    _gonBalances[_msgSender()] = _gonBalances[_msgSender()] - amount * _gonsPerFragment;
    // modify totalSupply and totalGons
    _totalSupply = _totalSupply - amount;
    _totalGons = _totalGons - amount * _gonsPerFragment;
    // emit both a Withdraw and transfer event
    emit Transfer(_msgSender(), address(0), amount);
    emit Withdraw(_msgSender(), amount);
  }

  /// @notice withdraw USDC by burning USDi
  /// caller should obtain 1 USDC for every 1e12 USDi
  /// this function is effectively just withdraw, but we calculate the amount for the sender
  function withdrawAll() external override paysInterest whenNotPaused {
    uint256 reserve = _reserve.balanceOf(address(this));
    require(reserve != 0, "Reserve is empty");
    uint256 usdc_amount = (this.balanceOf(_msgSender())) / 1e12;
    //user's USDI value is more than reserve
    if (usdc_amount > reserve) {
      usdc_amount = reserve;
    }
    uint256 amount = usdc_amount * 1e12;
    require(_reserve.transfer(_msgSender(), usdc_amount), "transfer failed");
    // see comments in the withdraw function for an explaination of this math
    _gonBalances[_msgSender()] = _gonBalances[_msgSender()] - (amount * _gonsPerFragment);
    _totalSupply = _totalSupply - amount;
    _totalGons = _totalGons - (amount * _gonsPerFragment);
    // emit both a Withdraw and transfer event
    emit Transfer(_msgSender(), address(0), amount);
    emit Withdraw(_msgSender(), amount);
  }

  /// @notice admin function to mint USDi
  /// @param usdc_amount the amount of USDi to mint, denominated in USDC
  function mint(uint256 usdc_amount) external override paysInterest onlyOwner {
    require(usdc_amount != 0, "Cannot mint 0");
    uint256 amount = usdc_amount * 1e12;
    // see comments in the deposit function for an explaination of this math
    _gonBalances[_msgSender()] = _gonBalances[_msgSender()] + amount * _gonsPerFragment;
    _totalSupply = _totalSupply + amount;
    _totalGons = _totalGons + amount * _gonsPerFragment;
    // emit both a mint and transfer event
    emit Transfer(address(0), _msgSender(), amount);
    emit Mint(_msgSender(), amount);
  }

  /// @notice admin function to burn USDi
  /// @param usdc_amount the amount of USDi to burn, denominated in USDC
  function burn(uint256 usdc_amount) external override paysInterest onlyOwner {
    require(usdc_amount != 0, "Cannot burn 0");
    uint256 amount = usdc_amount * 1e12;
    // see comments in the deposit function for an explaination of this math
    _gonBalances[_msgSender()] = _gonBalances[_msgSender()] - amount * _gonsPerFragment;
    _totalSupply = _totalSupply - amount;
    _totalGons = _totalGons - amount * _gonsPerFragment;
    // emit both a mint and transfer event
    emit Transfer(_msgSender(), address(0), amount);
    emit Burn(_msgSender(), amount);
  }

  /// @notice donates usdc to the protocol reserve
  /// @param usdc_amount the amount of USDC to donate
  function donate(uint256 usdc_amount) external override paysInterest whenNotPaused {
    uint256 amount = usdc_amount * 1e12;
    require(amount > 0, "Cannot deposit 0");
    uint256 allowance = _reserve.allowance(_msgSender(), address(this));
    require(allowance >= usdc_amount, "Insufficient Allowance");
    require(_reserve.transferFrom(_msgSender(), address(this), usdc_amount), "transfer failed");
    _donation(amount);
  }

  /// @notice donates any USDC held by this contract to the USDi holders
  /// @notice accounts for any USDC that may have been sent here accidently
  /// @notice without this, any USDC sent to the contract could mess up the reserve ratio
  function donateReserve() external override onlyOwner whenNotPaused {
    uint256 totalUSDC = (_reserve.balanceOf(address(this))) * 1e12;
    uint256 totalLiability = truncate(_VaultController.totalBaseLiability() * _VaultController.interestFactor());
    require((totalUSDC + totalLiability) > _totalSupply, "No extra reserve");

    _donation((totalUSDC + totalLiability) - _totalSupply);
  }

  /// @notice function for the vaultController to mint
  /// @param target whom to mint the USDi to
  /// @param amount the amount of USDi to mint
  function vaultControllerMint(address target, uint256 amount) external override onlyVaultController {
    // see comments in the deposit function for an explaination of this math
    _gonBalances[target] = _gonBalances[target] + amount * _gonsPerFragment;
    _totalSupply = _totalSupply + amount;
    _totalGons = _totalGons + amount * _gonsPerFragment;
    emit Transfer(address(0), target, amount);
    emit Mint(target, amount);
  }

  /// @notice function for the vaultController to burn
  /// @param target whom to burn the USDi from
  /// @param amount the amount of USDi to burn
  function vaultControllerBurn(address target, uint256 amount) external override onlyVaultController {
    require(_gonBalances[target] > (amount * _gonsPerFragment), "USDI: not enough balance");
    // see comments in the withdraw function for an explaination of this math
    _gonBalances[target] = _gonBalances[target] - amount * _gonsPerFragment;
    _totalSupply = _totalSupply - amount;
    _totalGons = _totalGons - amount * _gonsPerFragment;
    emit Transfer(target, address(0), amount);
    emit Burn(target, amount);
  }

  /// @notice function for the vaultController to scale all USDi balances
  /// @param amount amount of USDi (e18) to donate
  function vaultControllerDonate(uint256 amount) external override onlyVaultController {
    _donation(amount);
  }

  /// @notice function for distributing the donation to all USDi holders
  /// @param amount amount of USDi to donate
  function _donation(uint256 amount) internal {
    _totalSupply = _totalSupply + amount;
    if (_totalSupply > MAX_SUPPLY) {
      _totalSupply = MAX_SUPPLY;
    }
    _gonsPerFragment = _totalGons / _totalSupply;
    emit Donation(_msgSender(), amount, _totalSupply);
  }

  /// @notice get reserve ratio
  /// @return e18_reserve_ratio USDi reserve ratio
  function reserveRatio() external view override returns (uint192 e18_reserve_ratio) {
    e18_reserve_ratio = safeu192(((_reserve.balanceOf(address(this)) * expScale) / _totalSupply) * 1e12);
  }
}

File 2 of 19 : IUSDI.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;

import "./_external/IERC20Metadata.sol";

/// @title USDI Events
/// @notice interface which contains any events which the USDI contract emits
interface USDIEvents {
  event Deposit(address indexed _from, uint256 _value);
  event Withdraw(address indexed _from, uint256 _value);
  event Mint(address to, uint256 _value);
  event Burn(address from, uint256 _value);
  event Donation(address indexed _from, uint256 _value, uint256 _totalSupply);
}

/// @title USDI Interface
/// @notice extends USDIEvents and IERC20Metadata
interface IUSDI is IERC20Metadata, USDIEvents {
  /// @notice initializer specifies the reserveAddress
  function initialize(address reserveAddress) external;

  // getters
  function reserveRatio() external view returns (uint192);

  function reserveAddress() external view returns (address);

  // owner
  function owner() external view returns (address);

  // business
  function deposit(uint256 usdc_amount) external;

  function withdraw(uint256 usdc_amount) external;

  function withdrawAll() external;

  function donate(uint256 usdc_amount) external;

  function donateReserve() external;

  // admin functions

  function setPauser(address pauser_) external;

  function pauser() external view returns (address);

  function pause() external;

  function unpause() external;

  function mint(uint256 usdc_amount) external;

  function burn(uint256 usdc_amount) external;

  function setVaultController(address vault_master_address) external;

  function getVaultController() external view returns (address);

  // functions for the vault controller to call
  function vaultControllerBurn(address target, uint256 amount) external;

  function vaultControllerMint(address target, uint256 amount) external;

  function vaultControllerDonate(uint256 amount) external;
}

File 3 of 19 : UFragments.sol
// SPDX-License-Identifier: MIT
/* solhint-disable */
pragma solidity 0.8.9;

import "../_external/ERC20Detailed.sol";

import "../_external/openzeppelin/OwnableUpgradeable.sol";
import "../_external/openzeppelin/Initializable.sol";

/**
 * @title uFragments ERC20 token
 * @dev USDI uses the uFragments concept from the Ideal Money project to play interest
 *      Implementation is shamelessly borrowed from Ampleforth project
 *      uFragments is a normal ERC20 token, but its supply can be adjusted by splitting and
 *      combining tokens proportionally across all wallets.
 *
 *
 *      uFragment balances are internally represented with a hidden denomination, 'gons'.
 *      We support splitting the currency in expansion and combining the currency on contraction by
 *      changing the exchange rate between the hidden 'gons' and the public 'fragments'.
 */
contract UFragments is Initializable, OwnableUpgradeable, ERC20Detailed {
  // PLEASE READ BEFORE CHANGING ANY ACCOUNTING OR MATH
  // Anytime there is division, there is a risk of numerical instability from rounding errors. In
  // order to minimize this risk, we adhere to the following guidelines:
  // 1) The conversion rate adopted is the number of gons that equals 1 fragment.
  //    The inverse rate must not be used--_totalGons is always the numerator and _totalSupply is
  //    always the denominator. (i.e. If you want to convert gons to fragments instead of
  //    multiplying by the inverse rate, you should divide by the normal rate)
  // 2) Gon balances converted into Fragments are always rounded down (truncated).
  //
  // We make the following guarantees:
  // - If address 'A' transfers x Fragments to address 'B'. A's resulting external balance will
  //   be decreased by precisely x Fragments, and B's external balance will be precisely
  //   increased by x Fragments.
  //
  // We do not guarantee that the sum of all balances equals the result of calling totalSupply().
  // This is because, for any conversion function 'f()' that has non-zero rounding error,
  // f(x0) + f(x1) + ... + f(xn) is not always equal to f(x0 + x1 + ... xn).

  event LogRebase(uint256 indexed epoch, uint256 totalSupply);
  event LogMonetaryPolicyUpdated(address monetaryPolicy);

  // Used for authentication
  address public monetaryPolicy;

  modifier onlyMonetaryPolicy() {
    require(msg.sender == monetaryPolicy);
    _;
  }

  modifier validRecipient(address to) {
    require(to != address(0x0));
    require(to != address(this));
    _;
  }

  uint256 private constant DECIMALS = 18;
  uint256 private constant MAX_UINT256 = 2**256 - 1;
  uint256 private constant INITIAL_FRAGMENTS_SUPPLY = 1 * 10**DECIMALS;

  // _totalGons is a multiple of INITIAL_FRAGMENTS_SUPPLY so that _gonsPerFragment is an integer.
  // Use the highest value that fits in a uint256 for max granularity.
  uint256 public _totalGons; // = INITIAL_FRAGMENTS_SUPPLY * 10**48;

  // MAX_SUPPLY = maximum integer < (sqrt(4*_totalGons + 1) - 1) / 2
  uint256 public MAX_SUPPLY; // = type(uint128).max; // (2^128) - 1

  uint256 public _totalSupply;
  uint256 public _gonsPerFragment;
  mapping(address => uint256) public _gonBalances;

  // This is denominated in Fragments, because the gons-fragments conversion might change before
  // it's fully paid.
  mapping(address => mapping(address => uint256)) private _allowedFragments;

  // EIP-2612: permit – 712-signed approvals
  // https://eips.ethereum.org/EIPS/eip-2612
  string public constant EIP712_REVISION = "1";
  bytes32 public constant EIP712_DOMAIN =
    keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");
  bytes32 public constant PERMIT_TYPEHASH =
    keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");

  // EIP-2612: keeps track of number of permits per address
  mapping(address => uint256) private _nonces;

  function __UFragments_init(string memory name, string memory symbol) public initializer {
    __Ownable_init();
    __ERC20Detailed_init(name, symbol, uint8(DECIMALS));

    //set og initial values
    _totalGons = INITIAL_FRAGMENTS_SUPPLY * 10**48;
    MAX_SUPPLY = 2**128 - 1;

    _totalSupply = INITIAL_FRAGMENTS_SUPPLY;
    _gonBalances[address(0x0)] = _totalGons; //send starting supply to a burner address so _totalSupply is never 0
    _gonsPerFragment = _totalGons / _totalSupply;

    emit Transfer(address(this), address(0x0), _totalSupply);
  }

  /**
   * @param monetaryPolicy_ The address of the monetary policy contract to use for authentication.
   */
  function setMonetaryPolicy(address monetaryPolicy_) external onlyOwner {
    monetaryPolicy = monetaryPolicy_;
    emit LogMonetaryPolicyUpdated(monetaryPolicy_);
  }

  /**
   * @dev Notifies Fragments contract about a new rebase cycle.
   * @param supplyAdd The number of new fragment tokens to add into circulation via expansion.
   * @param supplyRemove The number of new fragment tokens to remove into circulation via expansion.
   * @return The total number of fragments after the supply adjustment.
   */
  function rebase(
    uint256 epoch,
    uint256 supplyAdd,
    uint256 supplyRemove
  ) external onlyMonetaryPolicy returns (uint256) {
    if (supplyAdd == 0 && supplyRemove == 0) {
      emit LogRebase(epoch, _totalSupply);
      return _totalSupply;
    }

    if (supplyAdd > 0) {
      _totalSupply = _totalSupply + supplyAdd;
    } else {
      _totalSupply = _totalSupply - supplyRemove;
    }

    if (_totalSupply > MAX_SUPPLY) {
      _totalSupply = MAX_SUPPLY;
    }

    _gonsPerFragment = _totalGons / _totalSupply;

    // From this point forward, _gonsPerFragment is taken as the source of truth.
    // We recalculate a new _totalSupply to be in agreement with the _gonsPerFragment
    // conversion rate.
    // This means our applied Deltas can deviate from the requested Deltas,
    // but this deviation is guaranteed to be < (_totalSupply^2)/(_totalGons - _totalSupply).
    //
    // In the case of _totalSupply <= MAX_UINT128 (our current supply cap), this
    // deviation is guaranteed to be < 1, so we can omit this step. If the supply cap is
    // ever increased, it must be re-included.
    // _totalSupply = _totalGons - _gonsPerFragment

    emit LogRebase(epoch, _totalSupply);
    return _totalSupply;
  }

  /**
   * @return The total number of fragments.
   */
  function totalSupply() external view override returns (uint256) {
    return _totalSupply;
  }

  /**
   * @param who The address to query.
   * @return The balance of the specified address.
   */
  function balanceOf(address who) external view override returns (uint256) {
    return _gonBalances[who] / _gonsPerFragment;
  }

  /**
   * @param who The address to query.
   * @return The gon balance of the specified address.
   */
  function scaledBalanceOf(address who) external view returns (uint256) {
    return _gonBalances[who];
  }

  /**
   * @return the total number of gons.
   */
  function scaledTotalSupply() external view returns (uint256) {
    return _totalGons;
  }

  /**
   * @return The number of successful permits by the specified address.
   */
  function nonces(address who) public view returns (uint256) {
    return _nonces[who];
  }

  /**
   * @return The computed DOMAIN_SEPARATOR to be used off-chain services
   *         which implement EIP-712.
   *         https://eips.ethereum.org/EIPS/eip-2612
   */
  function DOMAIN_SEPARATOR() public view returns (bytes32) {
    uint256 chainId;
    assembly {
      chainId := chainid()
    }
    return
      keccak256(
        abi.encode(EIP712_DOMAIN, keccak256(bytes(name())), keccak256(bytes(EIP712_REVISION)), chainId, address(this))
      );
  }

  /**
   * @dev Transfer tokens to a specified address.
   * @param to The address to transfer to.
   * @param value The amount to be transferred.
   * @return True on success, false otherwise.
   */
  function transfer(address to, uint256 value) external override validRecipient(to) returns (bool) {
    uint256 gonValue = value * _gonsPerFragment;

    _gonBalances[msg.sender] = _gonBalances[msg.sender] - gonValue;
    _gonBalances[to] = _gonBalances[to] + gonValue;

    emit Transfer(msg.sender, to, value);
    return true;
  }

  /**
   * @dev Transfer all of the sender's wallet balance to a specified address.
   * @param to The address to transfer to.
   * @return True on success, false otherwise.
   */
  function transferAll(address to) external validRecipient(to) returns (bool) {
    uint256 gonValue = _gonBalances[msg.sender];
    uint256 value = gonValue / _gonsPerFragment;

    delete _gonBalances[msg.sender];
    _gonBalances[to] = _gonBalances[to] + gonValue;

    emit Transfer(msg.sender, to, value);
    return true;
  }

  /**
   * @dev Function to check the amount of tokens that an owner has allowed to a spender.
   * @param owner_ The address which owns the funds.
   * @param spender The address which will spend the funds.
   * @return The number of tokens still available for the spender.
   */
  function allowance(address owner_, address spender) external view override returns (uint256) {
    return _allowedFragments[owner_][spender];
  }

  /**
   * @dev Transfer tokens from one address to another.
   * @param from The address you want to send tokens from.
   * @param to The address you want to transfer to.
   * @param value The amount of tokens to be transferred.
   */
  function transferFrom(
    address from,
    address to,
    uint256 value
  ) external override validRecipient(to) returns (bool) {
    _allowedFragments[from][msg.sender] = _allowedFragments[from][msg.sender] - value;

    uint256 gonValue = value * _gonsPerFragment;
    _gonBalances[from] = _gonBalances[from] - gonValue;
    _gonBalances[to] = _gonBalances[to] + gonValue;

    emit Transfer(from, to, value);
    return true;
  }

  /**
   * @dev Transfer all balance tokens from one address to another.
   * @param from The address you want to send tokens from.
   * @param to The address you want to transfer to.
   */
  function transferAllFrom(address from, address to) external validRecipient(to) returns (bool) {
    uint256 gonValue = _gonBalances[from];
    uint256 value = gonValue / _gonsPerFragment;

    _allowedFragments[from][msg.sender] = _allowedFragments[from][msg.sender] - value;

    delete _gonBalances[from];
    _gonBalances[to] = _gonBalances[to] + gonValue;

    emit Transfer(from, to, value);
    return true;
  }

  /**
   * @dev Approve the passed address to spend the specified amount of tokens on behalf of
   * msg.sender. This method is included for ERC20 compatibility.
   * increaseAllowance and decreaseAllowance should be used instead.
   * Changing an allowance with this method brings the risk that someone may transfer both
   * the old and the new allowance - if they are both greater than zero - if a transfer
   * transaction is mined before the later approve() call is mined.
   *
   * @param spender The address which will spend the funds.
   * @param value The amount of tokens to be spent.
   */
  function approve(address spender, uint256 value) external override returns (bool) {
    _allowedFragments[msg.sender][spender] = value;

    emit Approval(msg.sender, spender, value);
    return true;
  }

  /**
   * @dev Increase the amount of tokens that an owner has allowed to a spender.
   * This method should be used instead of approve() to avoid the double approval vulnerability
   * described above.
   * @param spender The address which will spend the funds.
   * @param addedValue The amount of tokens to increase the allowance by.
   */
  function increaseAllowance(address spender, uint256 addedValue) public returns (bool) {
    _allowedFragments[msg.sender][spender] = _allowedFragments[msg.sender][spender] + addedValue;

    emit Approval(msg.sender, spender, _allowedFragments[msg.sender][spender]);
    return true;
  }

  /**
   * @dev Decrease the amount of tokens that an owner has allowed to a spender.
   *
   * @param spender The address which will spend the funds.
   * @param subtractedValue The amount of tokens to decrease the allowance by.
   */
  function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool) {
    uint256 oldValue = _allowedFragments[msg.sender][spender];
    _allowedFragments[msg.sender][spender] = (subtractedValue >= oldValue) ? 0 : oldValue - subtractedValue;

    emit Approval(msg.sender, spender, _allowedFragments[msg.sender][spender]);
    return true;
  }

  /**
   * @dev Allows for approvals to be made via secp256k1 signatures.
   * @param owner The owner of the funds
   * @param spender The spender
   * @param value The amount
   * @param deadline The deadline timestamp, type(uint256).max for max deadline
   * @param v Signature param
   * @param s Signature param
   * @param r Signature param
   */
  function permit(
    address owner,
    address spender,
    uint256 value,
    uint256 deadline,
    uint8 v,
    bytes32 r,
    bytes32 s
  ) public {
    require(block.timestamp <= deadline);

    uint256 ownerNonce = _nonces[owner];
    bytes32 permitDataDigest = keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, ownerNonce, deadline));
    bytes32 digest = keccak256(abi.encodePacked("\x19\x01", DOMAIN_SEPARATOR(), permitDataDigest));

    require(owner == ecrecover(digest, v, r, s));
    require(owner != address(0x0));

    _nonces[owner] = ownerNonce + 1;

    _allowedFragments[owner][spender] = value;
    emit Approval(owner, spender, value);
  }
}
/* solhint-enable */

File 4 of 19 : Vault.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;

//import "../_external/IWETH.sol";

import "../IUSDI.sol";
import "./IVault.sol";
import "./IVaultController.sol";

import "../_external/CompLike.sol";
import "../_external/IERC20.sol";
import "../_external/Context.sol";
import "../_external/openzeppelin/SafeERC20Upgradeable.sol";

/// @title Vault
/// @notice our implentation of maker-vault like vault
/// major differences:
/// 1. multi-collateral
/// 2. generate interest in USDi
/// 3. can delegate voting power of contained tokens
contract Vault is IVault, Context {
  using SafeERC20Upgradeable for IERC20;

  /// @title VaultInfo struct
  /// @notice this struct is used to store the vault metadata
  /// this should reduce the cost of minting by ~15,000
  /// by limiting us to max 2**96-1 vaults
  struct VaultInfo {
    uint96 id;
    address minter;
  }
  /// @notice Metadata of vault, aka the id & the minter's address
  VaultInfo public _vaultInfo;
  IVaultController public immutable _controller;

  /// @notice this is the unscaled liability of the vault.
  /// the number is meaningless on its own, and must be combined with the factor taken from
  /// the vaultController in order to find the true liabilitiy
  uint256 public _baseLiability;

  /// @notice checks if _msgSender is the controller of the vault
  modifier onlyVaultController() {
    require(_msgSender() == address(_controller), "sender not VaultController");
    _;
  }

  /// @notice checks if _msgSender is the minter of the vault
  modifier onlyMinter() {
    require(_msgSender() == _vaultInfo.minter, "sender not minter");
    _;
  }

  /// @notice must be called by VaultController, else it will not be registered as a vault in system
  /// @param id_ unique id of the vault, ever increasing and tracked by VaultController
  /// @param minter_ address of the person who created this vault
  /// @param controller_address address of the VaultController
  constructor(
    uint96 id_,
    address minter_,
    address controller_address
  ) {
    _vaultInfo = VaultInfo(id_, minter_);
    _controller = IVaultController(controller_address);
  }

  /// @notice minter of the vault
  /// @return address of minter
  function minter() external view override returns (address) {
    return _vaultInfo.minter;
  }

  /// @notice id of the vault
  /// @return address of minter
  function id() external view override returns (uint96) {
    return _vaultInfo.id;
  }

  /// @notice current vault base liability
  /// @return base liability of vault
  function baseLiability() external view override returns (uint256) {
    return _baseLiability;
  }

  /// @notice get vaults balance of an erc20 token
  /// @param addr address of the erc20 token
  /// @dev scales wBTC up to normal erc20 size
  function tokenBalance(address addr) external view override returns (uint256) {
    return IERC20(addr).balanceOf(address(this));
  }

  /// @notice withdraw an erc20 token from the vault
  /// this can only be called by the minter
  /// the withdraw will be denied if ones vault would become insolvent
  /// @param token_address address of erc20 token
  /// @param amount amount of erc20 token to withdraw
  function withdrawErc20(address token_address, uint256 amount) external override onlyMinter {
    // transfer the token to the owner
    SafeERC20Upgradeable.safeTransfer(IERC20Upgradeable(token_address), _msgSender(), amount);
    //  check if the account is solvent
    require(_controller.checkVault(_vaultInfo.id), "over-withdrawal");
    emit Withdraw(token_address, amount);
  }

  /// @notice delegate the voting power of a comp-like erc20 token to another address
  /// @param delegatee address that will receive the votes
  /// @param token_address address of comp-like erc20 token
  function delegateCompLikeTo(address delegatee, address token_address) external override onlyMinter {
    CompLike(token_address).delegate(delegatee);
  }

  /// @notice function used by the VaultController to transfer tokens
  /// callable by the VaultController only
  /// @param _token token to transfer
  /// @param _to person to send the coins to
  /// @param _amount amount of coins to move
  function controllerTransfer(
    address _token,
    address _to,
    uint256 _amount
  ) external override onlyVaultController {
    SafeERC20Upgradeable.safeTransfer(IERC20Upgradeable(_token), _to, _amount);
  }

  /// @notice function used by the VaultController to reduce a vaults liability
  /// callable by the VaultController only
  /// @param increase true to increase, false to decerase
  /// @param base_amount amount to reduce base liability by
  function modifyLiability(bool increase, uint256 base_amount) external override onlyVaultController returns (uint256) {
    if (increase) {
      _baseLiability = _baseLiability + base_amount;
    } else {
      // require statement only valid for repayment
      require(_baseLiability >= base_amount, "repay too much");
      _baseLiability = _baseLiability - base_amount;
    }
    return _baseLiability;
  }
}

File 5 of 19 : IERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.9;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
  /**
   * @dev Returns the amount of tokens in existence.
   */
  function totalSupply() external view returns (uint256);

  /**
   * @dev Returns the token decimals.
   */
  function decimals() external view returns (uint8);

  /**
   * @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 `recipient`.
   *
   * Returns a boolean value indicating whether the operation succeeded.
   *
   * Emits a {Transfer} event.
   */
  function transfer(address recipient, 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 `sender` to `recipient` 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 sender,
    address recipient,
    uint256 amount
  ) external returns (bool);

  /**
   * @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);
}

File 6 of 19 : ExponentialNoError.sol
//SPDX-License-Identifier: MIT
pragma solidity 0.8.9;

/**
 * @title Exponential module for storing fixed-precision decimals
 * @author Compound
 * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places.
 *         Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is:
 *         `Exp({mantissa: 5100000000000000000})`.
 */
contract ExponentialNoError {
  uint256 constant expScale = 1e18;
  uint256 constant doubleScale = 1e36;
  uint256 constant halfExpScale = expScale / 2;
  uint256 constant mantissaOne = expScale;
  uint256 constant uint192Max = 2**192 - 1;
  uint256 constant uint128Max = 2**128 - 1;

  struct Exp {
    uint256 mantissa;
  }

  struct Double {
    uint256 mantissa;
  }

  /**
   * @dev Truncates the given exp to a whole number value.
   *      For example, truncate(Exp{mantissa: 15 * expScale}) = 15
   */
  function truncate(Exp memory exp) internal pure returns (uint256) {
    return exp.mantissa / expScale;
  }

  function truncate(uint256 u) internal pure returns (uint256) {
    return u / expScale;
  }

  function safeu192(uint256 u) internal pure returns (uint192) {
    require(u < uint192Max, "overflow");
    return uint192(u);
  }

  function safeu128(uint256 u) internal pure returns (uint128) {
    require(u < uint128Max, "overflow");
    return uint128(u);
  }

  /**
   * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer.
   */
  function mul_ScalarTruncate(Exp memory a, uint256 scalar) internal pure returns (uint256) {
    Exp memory product = mul_(a, scalar);
    return truncate(product);
  }

  /**
   * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer.
   */
  function mul_ScalarTruncateAddUInt(
    Exp memory a,
    uint256 scalar,
    uint256 addend
  ) internal pure returns (uint256) {
    Exp memory product = mul_(a, scalar);
    return add_(truncate(product), addend);
  }

  /**
   * @dev Checks if first Exp is less than second Exp.
   */
  function lessThanExp(Exp memory left, Exp memory right) internal pure returns (bool) {
    return left.mantissa < right.mantissa;
  }

  /**
   * @dev Checks if left Exp <= right Exp.
   */
  function lessThanOrEqualExp(Exp memory left, Exp memory right) internal pure returns (bool) {
    return left.mantissa <= right.mantissa;
  }

  /**
   * @dev Checks if left Exp > right Exp.
   */
  function greaterThanExp(Exp memory left, Exp memory right) internal pure returns (bool) {
    return left.mantissa > right.mantissa;
  }

  /**
   * @dev returns true if Exp is exactly zero
   */
  function isZeroExp(Exp memory value) internal pure returns (bool) {
    return value.mantissa == 0;
  }

  function safe224(uint256 n, string memory errorMessage) internal pure returns (uint224) {
    require(n < 2**224, errorMessage);
    return uint224(n);
  }

  function safe32(uint256 n, string memory errorMessage) internal pure returns (uint32) {
    require(n < 2**32, errorMessage);
    return uint32(n);
  }

  function add_(Exp memory a, Exp memory b) internal pure returns (Exp memory) {
    return Exp({mantissa: add_(a.mantissa, b.mantissa)});
  }

  function add_(Double memory a, Double memory b) internal pure returns (Double memory) {
    return Double({mantissa: add_(a.mantissa, b.mantissa)});
  }

  function add_(uint256 a, uint256 b) internal pure returns (uint256) {
    return add_(a, b, "addition overflow");
  }

  function add_(
    uint256 a,
    uint256 b,
    string memory errorMessage
  ) internal pure returns (uint256) {
    uint256 c = a + b;
    require(c >= a, errorMessage);
    return c;
  }

  function sub_(Exp memory a, Exp memory b) internal pure returns (Exp memory) {
    return Exp({mantissa: sub_(a.mantissa, b.mantissa)});
  }

  function sub_(Double memory a, Double memory b) internal pure returns (Double memory) {
    return Double({mantissa: sub_(a.mantissa, b.mantissa)});
  }

  function sub_(uint256 a, uint256 b) internal pure returns (uint256) {
    return sub_(a, b, "subtraction underflow");
  }

  function sub_(
    uint256 a,
    uint256 b,
    string memory errorMessage
  ) internal pure returns (uint256) {
    require(b <= a, errorMessage);
    return a - b;
  }

  function mul_(Exp memory a, Exp memory b) internal pure returns (Exp memory) {
    return Exp({mantissa: mul_(a.mantissa, b.mantissa) / expScale});
  }

  function mul_(Exp memory a, uint256 b) internal pure returns (Exp memory) {
    return Exp({mantissa: mul_(a.mantissa, b)});
  }

  function mul_(uint256 a, Exp memory b) internal pure returns (uint256) {
    return mul_(a, b.mantissa) / expScale;
  }

  function mul_(Double memory a, Double memory b) internal pure returns (Double memory) {
    return Double({mantissa: mul_(a.mantissa, b.mantissa) / doubleScale});
  }

  function mul_(Double memory a, uint256 b) internal pure returns (Double memory) {
    return Double({mantissa: mul_(a.mantissa, b)});
  }

  function mul_(uint256 a, Double memory b) internal pure returns (uint256) {
    return mul_(a, b.mantissa) / doubleScale;
  }

  function mul_(uint256 a, uint256 b) internal pure returns (uint256) {
    return mul_(a, b, "multiplication overflow");
  }

  function mul_(
    uint256 a,
    uint256 b,
    string memory errorMessage
  ) internal pure returns (uint256) {
    if (a == 0 || b == 0) {
      return 0;
    }
    uint256 c = a * b;
    require(c / a == b, errorMessage);
    return c;
  }

  function div_(Exp memory a, Exp memory b) internal pure returns (Exp memory) {
    return Exp({mantissa: div_(mul_(a.mantissa, expScale), b.mantissa)});
  }

  function div_(Exp memory a, uint256 b) internal pure returns (Exp memory) {
    return Exp({mantissa: div_(a.mantissa, b)});
  }

  function div_(uint256 a, Exp memory b) internal pure returns (uint256) {
    return div_(mul_(a, expScale), b.mantissa);
  }

  function div_(Double memory a, Double memory b) internal pure returns (Double memory) {
    return Double({mantissa: div_(mul_(a.mantissa, doubleScale), b.mantissa)});
  }

  function div_(Double memory a, uint256 b) internal pure returns (Double memory) {
    return Double({mantissa: div_(a.mantissa, b)});
  }

  function div_(uint256 a, Double memory b) internal pure returns (uint256) {
    return div_(mul_(a, doubleScale), b.mantissa);
  }

  function div_(uint256 a, uint256 b) internal pure returns (uint256) {
    return div_(a, b, "divide by zero");
  }

  function div_(
    uint256 a,
    uint256 b,
    string memory errorMessage
  ) internal pure returns (uint256) {
    require(b > 0, errorMessage);
    return a / b;
  }

  function fraction(uint256 a, uint256 b) internal pure returns (Double memory) {
    return Double({mantissa: div_(mul_(a, doubleScale), b)});
  }
}

File 7 of 19 : PausableUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (security/Pausable.sol)

pragma solidity 0.8.9;

import "./ContextUpgradeable.sol";
import "./Initializable.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 PausableUpgradeable is Initializable, ContextUpgradeable {
  /**
   * @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.
   */
  function __Pausable_init() internal onlyInitializing {
    __Pausable_init_unchained();
  }

  function __Pausable_init_unchained() internal onlyInitializing {
    _paused = false;
  }

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

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

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

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

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

  /**
   * @dev This empty reserved space is put in place to allow future versions to add new
   * variables without shifting down storage in the inheritance chain.
   * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
   */
  uint256[49] private __gap;
}

File 8 of 19 : IERC20Metadata.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.9;

import "./IERC20.sol";

/**
 * @dev Interface for the optional metadata functions from the ERC20 standard.
 *
 * _Available since v4.1._
 */
interface IERC20Metadata is IERC20 {
  /**
   * @dev Returns the name of the token.
   */
  function name() external view returns (string memory);

  /**
   * @dev Returns the symbol of the token.
   */
  function symbol() external view returns (string memory);

  /**
   * @dev Returns the decimals places of the token.
   */
  function decimals() external view returns (uint8);
}

File 9 of 19 : ERC20Detailed.sol
//SPDX-License-Identifier: MIT
pragma solidity 0.8.9;
import "./IERC20.sol";
import "./openzeppelin/Initializable.sol";

/**
 * @title ERC20Detailed token
 * @dev The decimals are only for visualization purposes.
 * All the operations are done using the smallest and indivisible token unit,
 * just as on Ethereum all the operations are done in wei.
 */
abstract contract ERC20Detailed is Initializable, IERC20 {
  string private _name;
  string private _symbol;
  uint8 private _decimals;

  /**
    constructor(string memory name_, string memory symbol_, uint8 decimals_){
        _name = name_;
        _symbol = symbol_;
        _decimals = decimals_;
    }
     */

  function __ERC20Detailed_init(
    string memory name_,
    string memory symbol_,
    uint8 decimals_
  ) public initializer {
    _name = name_;
    _symbol = symbol_;
    _decimals = decimals_;
  }

  /**
   * @return the name of the token.
   */
  function name() public view virtual returns (string memory) {
    return _name;
  }

  /**
   * @return the symbol of the token.
   */
  function symbol() public view virtual returns (string memory) {
    return _symbol;
  }

  /**
   * @return the number of decimals of the token.
   */
  function decimals() public view virtual returns (uint8) {
    return _decimals;
  }

  uint256[50] private ______gap;
}

File 10 of 19 : OwnableUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (access/Ownable.sol)

pragma solidity 0.8.9;

import "./ContextUpgradeable.sol";
import "./Initializable.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
  address private _owner;

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

  /**
   * @dev Initializes the contract setting the deployer as the initial owner.
   */
  function __Ownable_init() internal initializer {
    __Context_init_unchained();
    __Ownable_init_unchained();
  }

  function __Ownable_init_unchained() internal initializer {
    _transferOwnership(_msgSender());
  }

  /**
   * @dev Returns the address of the current owner.
   */
  function owner() public view virtual returns (address) {
    return _owner;
  }

  /**
   * @dev Throws if called by any account other than the owner.
   */
  modifier onlyOwner() {
    require(owner() == _msgSender(), "Ownable: caller is not the owner");
    _;
  }

  /**
   * @dev Leaves the contract without owner. It will not be possible to call
   * `onlyOwner` functions anymore. Can only be called by the current owner.
   *
   * NOTE: Renouncing ownership will leave the contract without an owner,
   * thereby removing any functionality that is only available to the owner.
   */
  function renounceOwnership() public virtual onlyOwner {
    _transferOwnership(address(0));
  }

  /**
   * @dev Transfers ownership of the contract to a new account (`newOwner`).
   * Can only be called by the current owner.
   */
  function transferOwnership(address newOwner) public virtual onlyOwner {
    require(newOwner != address(0), "Ownable: new owner is the zero address");
    _transferOwnership(newOwner);
  }

  /**
   * @dev Transfers ownership of the contract to a new account (`newOwner`).
   * Internal function without access restriction.
   */
  function _transferOwnership(address newOwner) internal virtual {
    address oldOwner = _owner;
    _owner = newOwner;
    emit OwnershipTransferred(oldOwner, newOwner);
  }

  uint256[49] private __gap;
}

File 11 of 19 : Initializable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (proxy/utils/Initializable.sol)

pragma solidity 0.8.9;

/**
 * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
 * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
 * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
 * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
 *
 * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
 * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
 *
 * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
 * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
 *
 * [CAUTION]
 * ====
 * Avoid leaving a contract uninitialized.
 *
 * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
 * contract, which may impact the proxy. To initialize the implementation contract, you can either invoke the
 * initializer manually, or you can include a constructor to automatically mark it as initialized when it is deployed:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * /// @custom:oz-upgrades-unsafe-allow constructor
 * constructor() initializer {}
 * ```
 * ====
 */
abstract contract Initializable {
  /**
   * @dev Indicates that the contract has been initialized.
   */
  bool private _initialized;

  /**
   * @dev Indicates that the contract is in the process of being initialized.
   */
  bool private _initializing;

  /**
   * @dev Modifier to protect an initializer function from being invoked twice.
   */
  modifier initializer() {
    require(_initializing || !_initialized, "Initializable: contract is already initialized");

    bool isTopLevelCall = !_initializing;
    if (isTopLevelCall) {
      _initializing = true;
      _initialized = true;
    }

    _;

    if (isTopLevelCall) {
      _initializing = false;
    }
  }
  /**
   * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
   * {initializer} modifier, directly or indirectly.
   */
  modifier onlyInitializing() {
    require(_initializing, "Initializable: contract is not initializing");
    _;
  }
}

File 12 of 19 : ContextUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (utils/Context.sol)

pragma solidity 0.8.9;
import "./Initializable.sol";

/**
 * @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 ContextUpgradeable is Initializable {
  function __Context_init() internal initializer {
    __Context_init_unchained();
  }

  function __Context_init_unchained() internal initializer {}

  function _msgSender() internal view virtual returns (address) {
    return msg.sender;
  }

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

  uint256[50] private __gap;
}

File 13 of 19 : IVault.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;

// @title Vault Events
/// @notice interface which contains any events which the Vault contract emits
interface VaultEvents {
  event Deposit(address token_address, uint256 amount);
  event Withdraw(address token_address, uint256 amount);
}

/// @title Vault Interface
/// @notice extends VaultEvents
interface IVault is VaultEvents {
  /// @notice value of _baseLiability
  function baseLiability() external view returns (uint256);
  /// @notice value of _vaultInfo.minter
  function minter() external view returns (address);
  /// @notice value of _vaultInfo.id
  function id() external view returns (uint96);
  /// @notice value of _tokenBalance
  function tokenBalance(address) external view returns (uint256);

  // business logic

  function withdrawErc20(address token_address, uint256 amount) external;
  function delegateCompLikeTo(address compLikeDelegatee, address compLikeToken) external;

  // administrative functions
  function controllerTransfer(
    address _token,
    address _to,
    uint256 _amount
  ) external;

  function modifyLiability(bool increase, uint256 base_amount) external returns (uint256);
}

File 14 of 19 : IVaultController.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;

// @title VaultController Events
/// @notice interface which contains any events which the VaultController contract emits
interface VaultControllerEvents {
  event InterestEvent(uint64 epoch, uint192 amount, uint256 curve_val);
  event NewProtocolFee(uint256 protocol_fee);
  event RegisteredErc20(address token_address, uint256 LTVe4, address oracle_address, uint256 liquidationIncentivee4);
  event UpdateRegisteredErc20(
    address token_address,
    uint256 LTVe4,
    address oracle_address,
    uint256 liquidationIncentivee4
  );
  event NewVault(address vault_address, uint256 vaultId, address vaultOwner);
  event RegisterOracleMaster(address oracleMasterAddress);
  event RegisterCurveMaster(address curveMasterAddress);
  event BorrowUSDi(uint256 vaultId, address vaultAddress, uint256 borrowAmount);
  event RepayUSDi(uint256 vaultId, address vaultAddress, uint256 repayAmount);
  event Liquidate(uint256 vaultId, address asset_address, uint256 usdi_to_repurchase, uint256 tokens_to_liquidate);
}

/// @title VaultController Interface
/// @notice extends VaultControllerEvents
interface IVaultController is VaultControllerEvents {
  // initializer
  function initialize() external;

  // view functions

  function tokensRegistered() external view returns (uint256);

  function vaultsMinted() external view returns (uint96);

  function lastInterestTime() external view returns (uint64);

  function totalBaseLiability() external view returns (uint192);

  function interestFactor() external view returns (uint192);

  function protocolFee() external view returns (uint192);

  function vaultAddress(uint96 id) external view returns (address);

  function vaultIDs(address wallet) external view returns (uint96[] memory);

  function amountToSolvency(uint96 id) external view returns (uint256);

  function vaultLiability(uint96 id) external view returns (uint192);

  function vaultBorrowingPower(uint96 id) external view returns (uint192);

  function tokensToLiquidate(uint96 id, address token) external view returns (uint256);

  function checkVault(uint96 id) external view returns (bool);

  struct VaultSummary {
    uint96 id;
    uint192 borrowingPower;
    uint192 vaultLiability;
    address[] tokenAddresses;
    uint256[] tokenBalances;
  }
  function vaultSummaries(uint96 start, uint96 stop) external view returns (VaultSummary[] memory);

  // interest calculations
  function calculateInterest() external returns (uint256);

  // vault management business
  function mintVault() external returns (address);

  function liquidateVault(
    uint96 id,
    address asset_address,
    uint256 tokenAmount
  ) external returns (uint256);

  function borrowUsdi(uint96 id, uint192 amount) external;

  function repayUSDi(uint96 id, uint192 amount) external;

  function repayAllUSDi(uint96 id) external;

  // admin
  function pause() external;

  function unpause() external;

  function getOracleMaster() external view returns (address);

  function registerOracleMaster(address master_oracle_address) external;

  function getCurveMaster() external view returns (address);

  function registerCurveMaster(address master_curve_address) external;

  function changeProtocolFee(uint192 new_protocol_fee) external;

  function registerErc20(
    address token_address,
    uint256 LTV,
    address oracle_address,
    uint256 liquidationIncentive
  ) external;

  function registerUSDi(address usdi_address) external;

  function updateRegisteredErc20(
    address token_address,
    uint256 LTV,
    address oracle_address,
    uint256 liquidationIncentive
  ) external;
}

File 15 of 19 : CompLike.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;

interface CompLike {
  function delegate(address delegatee) external;
}

File 16 of 19 : Context.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;

/*
 * @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) {
    this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
    return msg.data;
  }
}

File 17 of 19 : SafeERC20Upgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.0;

import "./IERC20Upgradeable.sol";
import "./AddressUpgradeable.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 SafeERC20Upgradeable {
    using AddressUpgradeable for address;

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

    function safeTransferFrom(
        IERC20Upgradeable 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(
        IERC20Upgradeable 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(
        IERC20Upgradeable 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(
        IERC20Upgradeable 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(IERC20Upgradeable 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 18 of 19 : IERC20Upgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (token/ERC20/IERC20.sol)

pragma solidity 0.8.9;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20Upgradeable {
  /**
   * @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 `recipient`.
   *
   * Returns a boolean value indicating whether the operation succeeded.
   *
   * Emits a {Transfer} event.
   */
  function transfer(address recipient, 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 `sender` to `recipient` 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 sender,
    address recipient,
    uint256 amount
  ) external returns (bool);

  /**
   * @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);
}

File 19 of 19 : AddressUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.0 (utils/Address.sol)

pragma solidity 0.8.9;

/**
 * @dev Collection of functions related to the address type
 */
library AddressUpgradeable {
  /**
   * @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
   * ====
   */
  function isContract(address account) internal view returns (bool) {
    // This method relies on extcodesize, which returns 0 for contracts in
    // construction, since the code is only stored at the end of the
    // constructor execution.

    uint256 size;
    assembly {
      size := extcodesize(account)
    }
    return size > 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 functionCall(target, data, "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 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

        assembly {
          let returndata_size := mload(returndata)
          revert(add(32, returndata), returndata_size)
        }
      } else {
        revert(errorMessage);
      }
    }
  }
}

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

Contract Security Audit

Contract ABI

[{"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":false,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint256","name":"_value","type":"uint256"}],"name":"Burn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_from","type":"address"},{"indexed":false,"internalType":"uint256","name":"_value","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_from","type":"address"},{"indexed":false,"internalType":"uint256","name":"_value","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_totalSupply","type":"uint256"}],"name":"Donation","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"monetaryPolicy","type":"address"}],"name":"LogMonetaryPolicyUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"epoch","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalSupply","type":"uint256"}],"name":"LogRebase","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"_value","type":"uint256"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","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":"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":true,"internalType":"address","name":"_from","type":"address"},{"indexed":false,"internalType":"uint256","name":"_value","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EIP712_DOMAIN","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EIP712_REVISION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_SUPPLY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PERMIT_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_VaultController","outputs":[{"internalType":"contract IVaultController","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"name_","type":"string"},{"internalType":"string","name":"symbol_","type":"string"},{"internalType":"uint8","name":"decimals_","type":"uint8"}],"name":"__ERC20Detailed_init","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"}],"name":"__UFragments_init","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"_gonBalances","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_gonsPerFragment","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_pauser","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_reserve","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_totalGons","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":"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":"value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"who","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"usdc_amount","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","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":"usdc_amount","type":"uint256"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"usdc_amount","type":"uint256"}],"name":"donate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"donateReserve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getVaultController","outputs":[{"internalType":"address","name":"","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":"reserveAddr","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"usdc_amount","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"monetaryPolicy","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"who","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","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":"pauser","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"epoch","type":"uint256"},{"internalType":"uint256","name":"supplyAdd","type":"uint256"},{"internalType":"uint256","name":"supplyRemove","type":"uint256"}],"name":"rebase","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"reserveAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"reserveRatio","outputs":[{"internalType":"uint192","name":"e18_reserve_ratio","type":"uint192"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"who","type":"address"}],"name":"scaledBalanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"scaledTotalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"monetaryPolicy_","type":"address"}],"name":"setMonetaryPolicy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"pauser_","type":"address"}],"name":"setPauser","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"vault_master_address","type":"address"}],"name":"setVaultController","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"transferAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"}],"name":"transferAllFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"target","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"vaultControllerBurn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"vaultControllerDonate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"target","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"vaultControllerMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"usdc_amount","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawAll","outputs":[],"stateMutability":"nonpayable","type":"function"}]

608060405234801561001057600080fd5b50613a30806100206000396000f3fe608060405234801561001057600080fd5b50600436106103835760003560e01c806378160376116101de578063a457c2d71161010f578063c99d6f01116100ad578063f14faf6f1161007c578063f14faf6f146107c6578063f2fde38b146107d9578063f79ed94b146107ec578063fd5eb09d146107fd57600080fd5b8063c99d6f0114610740578063d505accf14610753578063dd62ed3e14610766578063e1b11da41461079f57600080fd5b8063b1bf962d116100e9578063b1bf962d14610709578063b6b55f2514610711578063c4996f5114610724578063c4d66de81461072d57600080fd5b8063a457c2d7146106d0578063a48daa4f146106e3578063a9059cbb146106f657600080fd5b80638e27d7d71161017c5780639fd0506d116101565780639fd0506d14610686578063a0712d6814610697578063a10daee3146106aa578063a3a7e7f3146106bd57600080fd5b80638e27d7d71461065857806395d89b411461066b57806399747f151461067357600080fd5b806384d4b410116101b857806384d4b41014610622578063853828b6146106355780638b5a6a081461063d5780638da5cb5b1461065057600080fd5b806378160376146105d15780637ecebe00146105f15780638456cb591461061a57600080fd5b80633644e515116102b857806342966c68116102565780636a91d1e8116102305780636a91d1e81461059257806370a08231146105a5578063715018a6146105b857806377520b02146105c057600080fd5b806342966c681461056c57806348fbfea11461057f5780635c975abb1461058757600080fd5b8063395093511161029257806339509351146105355780633eaaf86b146105485780633f4ba83a14610551578063413ab4a81461055957600080fd5b80633644e515146104fa57806336fed975146105025780633769175f1461052257600080fd5b80631da24f3e116103255780632e1a7d4d116102ff5780632e1a7d4d1461049d57806330adf81f146104b0578063313ce567146104d757806332cb6b0c146104f157600080fd5b80631da24f3e1461044e57806323b872dd146104775780632d88af4a1461048a57600080fd5b80630c7d5cd8116103615780630c7d5cd8146103de578063178a6670146103fe57806318160ddd146104115780631bf5fc4d1461042357600080fd5b80630522658d1461038857806306fdde031461039d578063095ea7b3146103bb575b600080fd5b61039b6103963660046132e9565b610806565b005b6103a561092f565b6040516103b29190613313565b60405180910390f35b6103ce6103c93660046132e9565b61093e565b60405190151581526020016103b2565b6103e6610999565b6040516001600160c01b0390911681526020016103b2565b61039b61040c3660046132e9565b610a50565b60cf545b6040519081526020016103b2565b60d654610436906001600160a01b031681565b6040516001600160a01b0390911681526020016103b2565b61041561045c366004613368565b6001600160a01b0316600090815260d1602052604090205490565b6103ce610485366004613383565b610bdb565b61039b610498366004613368565b610d17565b61039b6104ab3660046133bf565b610d68565b6104157f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c981565b6104df61116f565b60405160ff90911681526020016103b2565b61041560ce5481565b61041561117d565b610415610510366004613368565b60d16020526000908152604090205481565b61039b61053036600461347b565b611229565b6103ce6105433660046132e9565b611378565b61041560cf5481565b61039b6113ec565b60d454610436906001600160a01b031681565b61039b61057a3660046133bf565b611447565b61039b61161c565b60335460ff166103ce565b60d554610436906001600160a01b031681565b6104156105b3366004613368565b611898565b61039b6118bf565b60d5546001600160a01b0316610436565b6103a5604051806040016040528060018152602001603160f81b81525081565b6104156105ff366004613368565b6001600160a01b0316600090815260d3602052604090205490565b61039b6118f8565b6103ce6106303660046134df565b611951565b61039b611a62565b61039b61064b366004613368565b611de8565b610436611e6b565b60cc54610436906001600160a01b031681565b6103a5611e7f565b61039b610681366004613368565b611e89565b60d6546001600160a01b0316610436565b61039b6106a53660046133bf565b611eda565b61039b6106b8366004613523565b612095565b6103ce6106cb366004613368565b61213b565b6103ce6106de3660046132e9565b61220b565b6104156106f1366004613597565b61229b565b6103ce6107043660046132e9565b6123a3565b60cd54610415565b61039b61071f3660046133bf565b61247c565b61041560d05481565b61039b61073b366004613368565b6127cc565b61039b61074e3660046133bf565b6128a3565b61039b6107613660046135c3565b6128e2565b6104156107743660046134df565b6001600160a01b03918216600090815260d26020908152604080832093909416825291909152205490565b6104157f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f81565b61039b6107d43660046133bf565b612aac565b61039b6107e7366004613368565b612d48565b60d4546001600160a01b0316610436565b61041560cd5481565b60d5546001600160a01b0316336001600160a01b0316146108425760405162461bcd60e51b81526004016108399061362d565b60405180910390fd5b60d05461084f9082613671565b6001600160a01b038316600090815260d160205260409020546108729190613690565b6001600160a01b038316600090815260d1602052604090205560cf54610899908290613690565b60cf5560d0546108a99082613671565b60cd546108b69190613690565b60cd556040518181526001600160a01b038316906000906000805160206139bb8339815191529060200160405180910390a3604080516001600160a01b0384168152602081018390527f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d412139688591015b60405180910390a15050565b6060610939612de5565b905090565b33600081815260d2602090815260408083206001600160a01b038716808552925280832085905551919290916000805160206139db833981519152906109879086815260200190565b60405180910390a35060015b92915050565b60cf5460d4546040516370a0823160e01b8152306004820152600092610939929091670de0b6b3a7640000916001600160a01b0316906370a082319060240160206040518083038186803b1580156109f057600080fd5b505afa158015610a04573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a2891906136a8565b610a329190613671565b610a3c91906136c1565b610a4b9064e8d4a51000613671565b612e77565b60d5546001600160a01b0316336001600160a01b031614610a835760405162461bcd60e51b81526004016108399061362d565b60d054610a909082613671565b6001600160a01b038316600090815260d1602052604090205411610af65760405162461bcd60e51b815260206004820152601860248201527f555344493a206e6f7420656e6f7567682062616c616e636500000000000000006044820152606401610839565b60d054610b039082613671565b6001600160a01b038316600090815260d16020526040902054610b2691906136e3565b6001600160a01b038316600090815260d1602052604090205560cf54610b4d9082906136e3565b60cf5560d054610b5d9082613671565b60cd54610b6a91906136e3565b60cd556040518181526000906001600160a01b038416906000805160206139bb8339815191529060200160405180910390a3604080516001600160a01b0384168152602081018390527fcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca59101610923565b6000826001600160a01b038116610bf157600080fd5b6001600160a01b038116301415610c0757600080fd5b6001600160a01b038516600090815260d260209081526040808320338452909152902054610c369084906136e3565b6001600160a01b038616600090815260d26020908152604080832033845290915281209190915560d054610c6a9085613671565b6001600160a01b038716600090815260d16020526040902054909150610c919082906136e3565b6001600160a01b03808816600090815260d160205260408082209390935590871681522054610cc1908290613690565b6001600160a01b03808716600081815260d1602052604090819020939093559151908816906000805160206139bb83398151915290610d039088815260200190565b60405180910390a350600195945050505050565b33610d20611e6b565b6001600160a01b031614610d465760405162461bcd60e51b8152600401610839906136fa565b60d680546001600160a01b0319166001600160a01b0392909216919091179055565b60d560009054906101000a90046001600160a01b03166001600160a01b031663eb0c49556040518163ffffffff1660e01b8152600401602060405180830381600087803b158015610db857600080fd5b505af1158015610dcc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610df091906136a8565b5060335460ff1615610e145760405162461bcd60e51b81526004016108399061372f565b6000610e258264e8d4a51000613671565b9050306370a08231336040516001600160e01b031960e084901b1681526001600160a01b03909116600482015260240160206040518083038186803b158015610e6d57600080fd5b505afa158015610e81573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ea591906136a8565b811115610ee95760405162461bcd60e51b8152602060048201526012602482015271696e73756666696369656e742066756e647360701b6044820152606401610839565b60008111610f2d5760405162461bcd60e51b8152602060048201526011602482015270043616e6e6f74207769746864726177203607c1b6044820152606401610839565b60d4546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a082319060240160206040518083038186803b158015610f7157600080fd5b505afa158015610f85573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fa991906136a8565b905082811015610ffb5760405162461bcd60e51b815260206004820152601c60248201527f496e73756666696369656e74205265736572766520696e2042616e6b000000006044820152606401610839565b60d4546001600160a01b031663a9059cbb336040516001600160e01b031960e084901b1681526001600160a01b03909116600482015260248101869052604401602060405180830381600087803b15801561105557600080fd5b505af1158015611069573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061108d9190613759565b6110a95760405162461bcd60e51b81526004016108399061377b565b60d0546110b69083613671565b33600090815260d160205260409020546110d091906136e3565b33600090815260d1602052604090205560cf546110ee9083906136e3565b60cf5560d0546110fe9083613671565b60cd5461110b91906136e3565b60cd5560405182815260009033906000805160206139bb8339815191529060200160405180910390a360405182815233907f884edad9ce6fa2440d8a54cc123490eb96d2768479d49ff9c7366125a9424364906020015b60405180910390a2505050565b600061093960995460ff1690565b6000467f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6111a961092f565b805160209182012060408051808201825260018152603160f81b90840152805192830193909352918101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc66060820152608081018290523060a082015260c0016040516020818303038152906040528051906020012091505090565b600054610100900460ff1680611242575060005460ff16155b61125e5760405162461bcd60e51b8152600401610839906137a4565b600054610100900460ff16158015611280576000805461ffff19166101011790555b611288612ebe565b61129483836012612095565b6112a06012600a6138d6565b6112ab906001613671565b6112c99073af298d050e4395d69670b12b7f41000000000000613671565b60cd556fffffffffffffffffffffffffffffffff60ce556112ec6012600a6138d6565b6112f7906001613671565b60cf81905560cd546000805260d16020527efa5413e7b01fc543d01f0911de573ace463b956369df4472f39030e8d98b7781905561133591906136c1565b60d05560cf5460405190815260009030906000805160206139bb8339815191529060200160405180910390a38015611373576000805461ff00191690555b505050565b33600090815260d2602090815260408083206001600160a01b03861684529091528120546113a7908390613690565b33600081815260d2602090815260408083206001600160a01b038916808552908352928190208590555193845290926000805160206139db8339815191529101610987565b60d6546001600160a01b0316336001600160a01b03161461143d5760405162461bcd60e51b815260206004820152600b60248201526a37b7363c903830bab9b2b960a91b6044820152606401610839565b611445612f39565b565b60d560009054906101000a90046001600160a01b03166001600160a01b031663eb0c49556040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561149757600080fd5b505af11580156114ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114cf91906136a8565b50336114d9611e6b565b6001600160a01b0316146114ff5760405162461bcd60e51b8152600401610839906136fa565b8061153c5760405162461bcd60e51b815260206004820152600d60248201526c043616e6e6f74206275726e203609c1b6044820152606401610839565b600061154d8264e8d4a51000613671565b905060d0548161155d9190613671565b33600090815260d1602052604090205461157791906136e3565b33600090815260d1602052604090205560cf546115959082906136e3565b60cf5560d0546115a59082613671565b60cd546115b291906136e3565b60cd5560405181815260009033906000805160206139bb8339815191529060200160405180910390a37fcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca5335b604080516001600160a01b0390921682526020820184905201610923565b33611625611e6b565b6001600160a01b03161461164b5760405162461bcd60e51b8152600401610839906136fa565b60335460ff161561166e5760405162461bcd60e51b81526004016108399061372f565b60d4546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a082319060240160206040518083038186803b1580156116b257600080fd5b505afa1580156116c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116ea91906136a8565b6116f99064e8d4a51000613671565b9050600061182460d560009054906101000a90046001600160a01b03166001600160a01b03166356dc3ac96040518163ffffffff1660e01b815260040160206040518083038186803b15801561174e57600080fd5b505afa158015611762573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061178691906138e2565b60d560009054906101000a90046001600160a01b03166001600160a01b031663adddb3f26040518163ffffffff1660e01b815260040160206040518083038186803b1580156117d457600080fd5b505afa1580156117e8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061180c91906138e2565b611816919061390b565b6001600160c01b0316612fcc565b60cf549091506118348284613690565b116118745760405162461bcd60e51b815260206004820152601060248201526f4e6f206578747261207265736572766560801b6044820152606401610839565b60cf54611894906118858385613690565b61188f91906136e3565b612fe0565b5050565b60d0546001600160a01b038216600090815260d160205260408120549091610993916136c1565b336118c8611e6b565b6001600160a01b0316146118ee5760405162461bcd60e51b8152600401610839906136fa565b6114456000613058565b60d6546001600160a01b0316336001600160a01b0316146119495760405162461bcd60e51b815260206004820152600b60248201526a37b7363c903830bab9b2b960a91b6044820152606401610839565b6114456130aa565b6000816001600160a01b03811661196757600080fd5b6001600160a01b03811630141561197d57600080fd5b6001600160a01b038416600090815260d1602052604081205460d0549091906119a690836136c1565b6001600160a01b038716600090815260d2602090815260408083203384529091529020549091506119d89082906136e3565b6001600160a01b03808816600081815260d26020908152604080832033845282528083209590955591815260d190915282812081905590871681522054611a20908390613690565b6001600160a01b03808716600081815260d1602052604090819020939093559151908816906000805160206139bb83398151915290610d039085815260200190565b60d560009054906101000a90046001600160a01b03166001600160a01b031663eb0c49556040518163ffffffff1660e01b8152600401602060405180830381600087803b158015611ab257600080fd5b505af1158015611ac6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611aea91906136a8565b5060335460ff1615611b0e5760405162461bcd60e51b81526004016108399061372f565b60d4546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a082319060240160206040518083038186803b158015611b5257600080fd5b505afa158015611b66573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b8a91906136a8565b905080611bcc5760405162461bcd60e51b815260206004820152601060248201526f5265736572766520697320656d70747960801b6044820152606401610839565b600064e8d4a51000306370a08231336040516001600160e01b031960e084901b1681526001600160a01b03909116600482015260240160206040518083038186803b158015611c1a57600080fd5b505afa158015611c2e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c5291906136a8565b611c5c91906136c1565b905081811115611c695750805b6000611c7a8264e8d4a51000613671565b60d4549091506001600160a01b031663a9059cbb336040516001600160e01b031960e084901b1681526001600160a01b03909116600482015260248101859052604401602060405180830381600087803b158015611cd757600080fd5b505af1158015611ceb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d0f9190613759565b611d2b5760405162461bcd60e51b81526004016108399061377b565b60d054611d389082613671565b33600090815260d16020526040902054611d5291906136e3565b33600090815260d1602052604090205560cf54611d709082906136e3565b60cf5560d054611d809082613671565b60cd54611d8d91906136e3565b60cd5560405181815260009033906000805160206139bb8339815191529060200160405180910390a360405181815233907f884edad9ce6fa2440d8a54cc123490eb96d2768479d49ff9c7366125a942436490602001611162565b33611df1611e6b565b6001600160a01b031614611e175760405162461bcd60e51b8152600401610839906136fa565b60cc80546001600160a01b0319166001600160a01b0383169081179091556040519081527f0e6961f1a1afb87eaf51fd64f22ddc10062e23aa7838eac5d0bdf140bfd389729060200160405180910390a150565b60006109396065546001600160a01b031690565b6060610939613102565b33611e92611e6b565b6001600160a01b031614611eb85760405162461bcd60e51b8152600401610839906136fa565b60d580546001600160a01b0319166001600160a01b0392909216919091179055565b60d560009054906101000a90046001600160a01b03166001600160a01b031663eb0c49556040518163ffffffff1660e01b8152600401602060405180830381600087803b158015611f2a57600080fd5b505af1158015611f3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f6291906136a8565b5033611f6c611e6b565b6001600160a01b031614611f925760405162461bcd60e51b8152600401610839906136fa565b80611fcf5760405162461bcd60e51b815260206004820152600d60248201526c043616e6e6f74206d696e74203609c1b6044820152606401610839565b6000611fe08264e8d4a51000613671565b905060d05481611ff09190613671565b33600090815260d1602052604090205461200a9190613690565b33600090815260d1602052604090205560cf54612028908290613690565b60cf5560d0546120389082613671565b60cd546120459190613690565b60cd5560405181815233906000906000805160206139bb8339815191529060200160405180910390a37f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d4121396885336115fe565b600054610100900460ff16806120ae575060005460ff16155b6120ca5760405162461bcd60e51b8152600401610839906137a4565b600054610100900460ff161580156120ec576000805461ffff19166101011790555b83516120ff90609790602087019061323d565b50825161211390609890602086019061323d565b506099805460ff191660ff84161790558015612135576000805461ff00191690555b50505050565b6000816001600160a01b03811661215157600080fd5b6001600160a01b03811630141561216757600080fd5b33600090815260d1602052604081205460d05490919061218790836136c1565b33600090815260d160205260408082208290556001600160a01b03881682529020549091506121b7908390613690565b6001600160a01b038616600081815260d160205260409081902092909255905133906000805160206139bb833981519152906121f69085815260200190565b60405180910390a36001935050505b50919050565b33600090815260d2602090815260408083206001600160a01b0386168452909152812054808310156122465761224183826136e3565b612249565b60005b33600081815260d2602090815260408083206001600160a01b038a16808552908352928190208590555193845290926000805160206139db833981519152910160405180910390a35060019392505050565b60cc546000906001600160a01b031633146122b557600080fd5b821580156122c1575081155b1561230b57837f72725a3b1e5bd622d6bcd1339bb31279c351abe8f541ac7fd320f24e1b1641f260cf546040516122fa91815260200190565b60405180910390a25060cf5461239c565b8215612327578260cf5461231f9190613690565b60cf55612339565b8160cf5461233591906136e3565b60cf555b60ce5460cf54111561234c5760ce5460cf555b60cf5460cd5461235c91906136c1565b60d05560cf5460405190815284907f72725a3b1e5bd622d6bcd1339bb31279c351abe8f541ac7fd320f24e1b1641f29060200160405180910390a25060cf545b9392505050565b6000826001600160a01b0381166123b957600080fd5b6001600160a01b0381163014156123cf57600080fd5b600060d054846123df9190613671565b33600090815260d160205260409020549091506123fd9082906136e3565b33600090815260d16020526040808220929092556001600160a01b0387168152205461242a908290613690565b6001600160a01b038616600081815260d160205260409081902092909255905133906000805160206139bb833981519152906124699088815260200190565b60405180910390a3506001949350505050565b60d560009054906101000a90046001600160a01b03166001600160a01b031663eb0c49556040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156124cc57600080fd5b505af11580156124e0573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061250491906136a8565b5060335460ff16156125285760405162461bcd60e51b81526004016108399061372f565b60006125398264e8d4a51000613671565b90506000811161257e5760405162461bcd60e51b815260206004820152601060248201526f043616e6e6f74206465706f73697420360841b6044820152606401610839565b60d4546000906001600160a01b031663dd62ed3e336040516001600160e01b031960e084901b1681526001600160a01b03909116600482015230602482015260440160206040518083038186803b1580156125d857600080fd5b505afa1580156125ec573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061261091906136a8565b90508281101561265b5760405162461bcd60e51b8152602060048201526016602482015275496e73756666696369656e7420416c6c6f77616e636560501b6044820152606401610839565b60d4546001600160a01b03166323b872dd336040516001600160e01b031960e084901b1681526001600160a01b03909116600482015230602482015260448101869052606401602060405180830381600087803b1580156126bb57600080fd5b505af11580156126cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126f39190613759565b61270f5760405162461bcd60e51b81526004016108399061377b565b60d05461271c9083613671565b33600090815260d160205260409020546127369190613690565b33600090815260d1602052604090205560cf54612754908390613690565b60cf5560d0546127649083613671565b60cd546127719190613690565b60cd5560405182815233906000906000805160206139bb8339815191529060200160405180910390a360405182815233907fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c90602001611162565b600054610100900460ff16806127e5575060005460ff16155b6128015760405162461bcd60e51b8152600401610839906137a4565b600054610100900460ff16158015612823576000805461ffff19166101011790555b61286b6040518060400160405280600a8152602001692aa9a224902a37b5b2b760b11b815250604051806040016040528060048152602001635553444960e01b815250611229565b612873613111565b60d480546001600160a01b0319166001600160a01b0384161790558015611894576000805461ff00191690555050565b60d5546001600160a01b0316336001600160a01b0316146128d65760405162461bcd60e51b81526004016108399061362d565b6128df81612fe0565b50565b834211156128ef57600080fd5b6001600160a01b03878116600081815260d3602090815260408083205481517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98185015280830195909552948b166060850152608084018a905260a0840185905260c08085018a90528151808603909101815260e0909401905282519201919091209061297a61117d565b60405161190160f01b602082015260228101919091526042810183905260620160408051601f1981840301815282825280516020918201206000845290830180835281905260ff8916918301919091526060820187905260808201869052915060019060a0016020604051602081039080840390855afa158015612a02573d6000803e3d6000fd5b505050602060405103516001600160a01b03168a6001600160a01b031614612a2957600080fd5b6001600160a01b038a16612a3c57600080fd5b612a47836001613690565b6001600160a01b038b8116600081815260d3602090815260408083209590955560d28152848220938e16808352938152908490208c905592518b8152919290916000805160206139db833981519152910160405180910390a350505050505050505050565b60d560009054906101000a90046001600160a01b03166001600160a01b031663eb0c49556040518163ffffffff1660e01b8152600401602060405180830381600087803b158015612afc57600080fd5b505af1158015612b10573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b3491906136a8565b5060335460ff1615612b585760405162461bcd60e51b81526004016108399061372f565b6000612b698264e8d4a51000613671565b905060008111612bae5760405162461bcd60e51b815260206004820152601060248201526f043616e6e6f74206465706f73697420360841b6044820152606401610839565b60d4546000906001600160a01b031663dd62ed3e336040516001600160e01b031960e084901b1681526001600160a01b03909116600482015230602482015260440160206040518083038186803b158015612c0857600080fd5b505afa158015612c1c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c4091906136a8565b905082811015612c8b5760405162461bcd60e51b8152602060048201526016602482015275496e73756666696369656e7420416c6c6f77616e636560501b6044820152606401610839565b60d4546001600160a01b03166323b872dd336040516001600160e01b031960e084901b1681526001600160a01b03909116600482015230602482015260448101869052606401602060405180830381600087803b158015612ceb57600080fd5b505af1158015612cff573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d239190613759565b612d3f5760405162461bcd60e51b81526004016108399061377b565b61137382612fe0565b33612d51611e6b565b6001600160a01b031614612d775760405162461bcd60e51b8152600401610839906136fa565b6001600160a01b038116612ddc5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610839565b6128df81613058565b606060978054612df49061393a565b80601f0160208091040260200160405190810160405280929190818152602001828054612e209061393a565b8015612e6d5780601f10612e4257610100808354040283529160200191612e6d565b820191906000526020600020905b815481529060010190602001808311612e5057829003601f168201915b5050505050905090565b60006001600160c01b038210612eba5760405162461bcd60e51b81526020600482015260086024820152676f766572666c6f7760c01b6044820152606401610839565b5090565b600054610100900460ff1680612ed7575060005460ff16155b612ef35760405162461bcd60e51b8152600401610839906137a4565b600054610100900460ff16158015612f15576000805461ffff19166101011790555b612f1d613140565b612f256131aa565b80156128df576000805461ff001916905550565b60335460ff16612f825760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610839565b6033805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6000610993670de0b6b3a7640000836136c1565b8060cf54612fee9190613690565b60cf81905560ce5410156130035760ce5460cf555b60cf5460cd5461301391906136c1565b60d05560cf5460408051838152602081019290925233917f106aac375bbcf013d1e52338bbf9e740009a1a3a6869f8daa1b72aa1620f5fec910160405180910390a250565b606580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60335460ff16156130cd5760405162461bcd60e51b81526004016108399061372f565b6033805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258612faf3390565b606060988054612df49061393a565b600054610100900460ff166131385760405162461bcd60e51b81526004016108399061396f565b61144561320a565b600054610100900460ff1680613159575060005460ff16155b6131755760405162461bcd60e51b8152600401610839906137a4565b600054610100900460ff16158015612f25576000805461ffff191661010117905580156128df576000805461ff001916905550565b600054610100900460ff16806131c3575060005460ff16155b6131df5760405162461bcd60e51b8152600401610839906137a4565b600054610100900460ff16158015613201576000805461ffff19166101011790555b612f2533613058565b600054610100900460ff166132315760405162461bcd60e51b81526004016108399061396f565b6033805460ff19169055565b8280546132499061393a565b90600052602060002090601f01602090048101928261326b57600085556132b1565b82601f1061328457805160ff19168380011785556132b1565b828001600101855582156132b1579182015b828111156132b1578251825591602001919060010190613296565b50612eba9291505b80821115612eba57600081556001016132b9565b80356001600160a01b03811681146132e457600080fd5b919050565b600080604083850312156132fc57600080fd5b613305836132cd565b946020939093013593505050565b600060208083528351808285015260005b8181101561334057858101830151858201604001528201613324565b81811115613352576000604083870101525b50601f01601f1916929092016040019392505050565b60006020828403121561337a57600080fd5b61239c826132cd565b60008060006060848603121561339857600080fd5b6133a1846132cd565b92506133af602085016132cd565b9150604084013590509250925092565b6000602082840312156133d157600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126133ff57600080fd5b813567ffffffffffffffff8082111561341a5761341a6133d8565b604051601f8301601f19908116603f01168101908282118183101715613442576134426133d8565b8160405283815286602085880101111561345b57600080fd5b836020870160208301376000602085830101528094505050505092915050565b6000806040838503121561348e57600080fd5b823567ffffffffffffffff808211156134a657600080fd5b6134b2868387016133ee565b935060208501359150808211156134c857600080fd5b506134d5858286016133ee565b9150509250929050565b600080604083850312156134f257600080fd5b6134fb836132cd565b9150613509602084016132cd565b90509250929050565b803560ff811681146132e457600080fd5b60008060006060848603121561353857600080fd5b833567ffffffffffffffff8082111561355057600080fd5b61355c878388016133ee565b9450602086013591508082111561357257600080fd5b5061357f868287016133ee565b92505061358e60408501613512565b90509250925092565b6000806000606084860312156135ac57600080fd5b505081359360208301359350604090920135919050565b600080600080600080600060e0888a0312156135de57600080fd5b6135e7886132cd565b96506135f5602089016132cd565b9550604088013594506060880135935061361160808901613512565b925060a0880135915060c0880135905092959891949750929550565b60208082526014908201527337b7363c902b30bab63a21b7b73a3937b63632b960611b604082015260600190565b634e487b7160e01b600052601160045260246000fd5b600081600019048311821515161561368b5761368b61365b565b500290565b600082198211156136a3576136a361365b565b500190565b6000602082840312156136ba57600080fd5b5051919050565b6000826136de57634e487b7160e01b600052601260045260246000fd5b500490565b6000828210156136f5576136f561365b565b500390565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b60208082526010908201526f14185d5cd8589b194e881c185d5cd95960821b604082015260600190565b60006020828403121561376b57600080fd5b8151801515811461239c57600080fd5b6020808252600f908201526e1d1c985b9cd9995c8819985a5b1959608a1b604082015260600190565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b600181815b8085111561382d5781600019048211156138135761381361365b565b8085161561382057918102915b93841c93908002906137f7565b509250929050565b60008261384457506001610993565b8161385157506000610993565b816001811461386757600281146138715761388d565b6001915050610993565b60ff8411156138825761388261365b565b50506001821b610993565b5060208310610133831016604e8410600b84101617156138b0575081810a610993565b6138ba83836137f2565b80600019048211156138ce576138ce61365b565b029392505050565b600061239c8383613835565b6000602082840312156138f457600080fd5b81516001600160c01b038116811461239c57600080fd5b60006001600160c01b03828116848216811515828404821116156139315761393161365b565b02949350505050565b600181811c9082168061394e57607f821691505b6020821081141561220557634e487b7160e01b600052602260045260246000fd5b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b60608201526080019056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925a2646970667358221220af54bd5125b96b6aa07228065133a1ddaef3bbd3b8d5772a52594080eee77d4c64736f6c63430008090033

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106103835760003560e01c806378160376116101de578063a457c2d71161010f578063c99d6f01116100ad578063f14faf6f1161007c578063f14faf6f146107c6578063f2fde38b146107d9578063f79ed94b146107ec578063fd5eb09d146107fd57600080fd5b8063c99d6f0114610740578063d505accf14610753578063dd62ed3e14610766578063e1b11da41461079f57600080fd5b8063b1bf962d116100e9578063b1bf962d14610709578063b6b55f2514610711578063c4996f5114610724578063c4d66de81461072d57600080fd5b8063a457c2d7146106d0578063a48daa4f146106e3578063a9059cbb146106f657600080fd5b80638e27d7d71161017c5780639fd0506d116101565780639fd0506d14610686578063a0712d6814610697578063a10daee3146106aa578063a3a7e7f3146106bd57600080fd5b80638e27d7d71461065857806395d89b411461066b57806399747f151461067357600080fd5b806384d4b410116101b857806384d4b41014610622578063853828b6146106355780638b5a6a081461063d5780638da5cb5b1461065057600080fd5b806378160376146105d15780637ecebe00146105f15780638456cb591461061a57600080fd5b80633644e515116102b857806342966c68116102565780636a91d1e8116102305780636a91d1e81461059257806370a08231146105a5578063715018a6146105b857806377520b02146105c057600080fd5b806342966c681461056c57806348fbfea11461057f5780635c975abb1461058757600080fd5b8063395093511161029257806339509351146105355780633eaaf86b146105485780633f4ba83a14610551578063413ab4a81461055957600080fd5b80633644e515146104fa57806336fed975146105025780633769175f1461052257600080fd5b80631da24f3e116103255780632e1a7d4d116102ff5780632e1a7d4d1461049d57806330adf81f146104b0578063313ce567146104d757806332cb6b0c146104f157600080fd5b80631da24f3e1461044e57806323b872dd146104775780632d88af4a1461048a57600080fd5b80630c7d5cd8116103615780630c7d5cd8146103de578063178a6670146103fe57806318160ddd146104115780631bf5fc4d1461042357600080fd5b80630522658d1461038857806306fdde031461039d578063095ea7b3146103bb575b600080fd5b61039b6103963660046132e9565b610806565b005b6103a561092f565b6040516103b29190613313565b60405180910390f35b6103ce6103c93660046132e9565b61093e565b60405190151581526020016103b2565b6103e6610999565b6040516001600160c01b0390911681526020016103b2565b61039b61040c3660046132e9565b610a50565b60cf545b6040519081526020016103b2565b60d654610436906001600160a01b031681565b6040516001600160a01b0390911681526020016103b2565b61041561045c366004613368565b6001600160a01b0316600090815260d1602052604090205490565b6103ce610485366004613383565b610bdb565b61039b610498366004613368565b610d17565b61039b6104ab3660046133bf565b610d68565b6104157f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c981565b6104df61116f565b60405160ff90911681526020016103b2565b61041560ce5481565b61041561117d565b610415610510366004613368565b60d16020526000908152604090205481565b61039b61053036600461347b565b611229565b6103ce6105433660046132e9565b611378565b61041560cf5481565b61039b6113ec565b60d454610436906001600160a01b031681565b61039b61057a3660046133bf565b611447565b61039b61161c565b60335460ff166103ce565b60d554610436906001600160a01b031681565b6104156105b3366004613368565b611898565b61039b6118bf565b60d5546001600160a01b0316610436565b6103a5604051806040016040528060018152602001603160f81b81525081565b6104156105ff366004613368565b6001600160a01b0316600090815260d3602052604090205490565b61039b6118f8565b6103ce6106303660046134df565b611951565b61039b611a62565b61039b61064b366004613368565b611de8565b610436611e6b565b60cc54610436906001600160a01b031681565b6103a5611e7f565b61039b610681366004613368565b611e89565b60d6546001600160a01b0316610436565b61039b6106a53660046133bf565b611eda565b61039b6106b8366004613523565b612095565b6103ce6106cb366004613368565b61213b565b6103ce6106de3660046132e9565b61220b565b6104156106f1366004613597565b61229b565b6103ce6107043660046132e9565b6123a3565b60cd54610415565b61039b61071f3660046133bf565b61247c565b61041560d05481565b61039b61073b366004613368565b6127cc565b61039b61074e3660046133bf565b6128a3565b61039b6107613660046135c3565b6128e2565b6104156107743660046134df565b6001600160a01b03918216600090815260d26020908152604080832093909416825291909152205490565b6104157f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f81565b61039b6107d43660046133bf565b612aac565b61039b6107e7366004613368565b612d48565b60d4546001600160a01b0316610436565b61041560cd5481565b60d5546001600160a01b0316336001600160a01b0316146108425760405162461bcd60e51b81526004016108399061362d565b60405180910390fd5b60d05461084f9082613671565b6001600160a01b038316600090815260d160205260409020546108729190613690565b6001600160a01b038316600090815260d1602052604090205560cf54610899908290613690565b60cf5560d0546108a99082613671565b60cd546108b69190613690565b60cd556040518181526001600160a01b038316906000906000805160206139bb8339815191529060200160405180910390a3604080516001600160a01b0384168152602081018390527f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d412139688591015b60405180910390a15050565b6060610939612de5565b905090565b33600081815260d2602090815260408083206001600160a01b038716808552925280832085905551919290916000805160206139db833981519152906109879086815260200190565b60405180910390a35060015b92915050565b60cf5460d4546040516370a0823160e01b8152306004820152600092610939929091670de0b6b3a7640000916001600160a01b0316906370a082319060240160206040518083038186803b1580156109f057600080fd5b505afa158015610a04573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a2891906136a8565b610a329190613671565b610a3c91906136c1565b610a4b9064e8d4a51000613671565b612e77565b60d5546001600160a01b0316336001600160a01b031614610a835760405162461bcd60e51b81526004016108399061362d565b60d054610a909082613671565b6001600160a01b038316600090815260d1602052604090205411610af65760405162461bcd60e51b815260206004820152601860248201527f555344493a206e6f7420656e6f7567682062616c616e636500000000000000006044820152606401610839565b60d054610b039082613671565b6001600160a01b038316600090815260d16020526040902054610b2691906136e3565b6001600160a01b038316600090815260d1602052604090205560cf54610b4d9082906136e3565b60cf5560d054610b5d9082613671565b60cd54610b6a91906136e3565b60cd556040518181526000906001600160a01b038416906000805160206139bb8339815191529060200160405180910390a3604080516001600160a01b0384168152602081018390527fcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca59101610923565b6000826001600160a01b038116610bf157600080fd5b6001600160a01b038116301415610c0757600080fd5b6001600160a01b038516600090815260d260209081526040808320338452909152902054610c369084906136e3565b6001600160a01b038616600090815260d26020908152604080832033845290915281209190915560d054610c6a9085613671565b6001600160a01b038716600090815260d16020526040902054909150610c919082906136e3565b6001600160a01b03808816600090815260d160205260408082209390935590871681522054610cc1908290613690565b6001600160a01b03808716600081815260d1602052604090819020939093559151908816906000805160206139bb83398151915290610d039088815260200190565b60405180910390a350600195945050505050565b33610d20611e6b565b6001600160a01b031614610d465760405162461bcd60e51b8152600401610839906136fa565b60d680546001600160a01b0319166001600160a01b0392909216919091179055565b60d560009054906101000a90046001600160a01b03166001600160a01b031663eb0c49556040518163ffffffff1660e01b8152600401602060405180830381600087803b158015610db857600080fd5b505af1158015610dcc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610df091906136a8565b5060335460ff1615610e145760405162461bcd60e51b81526004016108399061372f565b6000610e258264e8d4a51000613671565b9050306370a08231336040516001600160e01b031960e084901b1681526001600160a01b03909116600482015260240160206040518083038186803b158015610e6d57600080fd5b505afa158015610e81573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ea591906136a8565b811115610ee95760405162461bcd60e51b8152602060048201526012602482015271696e73756666696369656e742066756e647360701b6044820152606401610839565b60008111610f2d5760405162461bcd60e51b8152602060048201526011602482015270043616e6e6f74207769746864726177203607c1b6044820152606401610839565b60d4546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a082319060240160206040518083038186803b158015610f7157600080fd5b505afa158015610f85573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fa991906136a8565b905082811015610ffb5760405162461bcd60e51b815260206004820152601c60248201527f496e73756666696369656e74205265736572766520696e2042616e6b000000006044820152606401610839565b60d4546001600160a01b031663a9059cbb336040516001600160e01b031960e084901b1681526001600160a01b03909116600482015260248101869052604401602060405180830381600087803b15801561105557600080fd5b505af1158015611069573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061108d9190613759565b6110a95760405162461bcd60e51b81526004016108399061377b565b60d0546110b69083613671565b33600090815260d160205260409020546110d091906136e3565b33600090815260d1602052604090205560cf546110ee9083906136e3565b60cf5560d0546110fe9083613671565b60cd5461110b91906136e3565b60cd5560405182815260009033906000805160206139bb8339815191529060200160405180910390a360405182815233907f884edad9ce6fa2440d8a54cc123490eb96d2768479d49ff9c7366125a9424364906020015b60405180910390a2505050565b600061093960995460ff1690565b6000467f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6111a961092f565b805160209182012060408051808201825260018152603160f81b90840152805192830193909352918101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc66060820152608081018290523060a082015260c0016040516020818303038152906040528051906020012091505090565b600054610100900460ff1680611242575060005460ff16155b61125e5760405162461bcd60e51b8152600401610839906137a4565b600054610100900460ff16158015611280576000805461ffff19166101011790555b611288612ebe565b61129483836012612095565b6112a06012600a6138d6565b6112ab906001613671565b6112c99073af298d050e4395d69670b12b7f41000000000000613671565b60cd556fffffffffffffffffffffffffffffffff60ce556112ec6012600a6138d6565b6112f7906001613671565b60cf81905560cd546000805260d16020527efa5413e7b01fc543d01f0911de573ace463b956369df4472f39030e8d98b7781905561133591906136c1565b60d05560cf5460405190815260009030906000805160206139bb8339815191529060200160405180910390a38015611373576000805461ff00191690555b505050565b33600090815260d2602090815260408083206001600160a01b03861684529091528120546113a7908390613690565b33600081815260d2602090815260408083206001600160a01b038916808552908352928190208590555193845290926000805160206139db8339815191529101610987565b60d6546001600160a01b0316336001600160a01b03161461143d5760405162461bcd60e51b815260206004820152600b60248201526a37b7363c903830bab9b2b960a91b6044820152606401610839565b611445612f39565b565b60d560009054906101000a90046001600160a01b03166001600160a01b031663eb0c49556040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561149757600080fd5b505af11580156114ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114cf91906136a8565b50336114d9611e6b565b6001600160a01b0316146114ff5760405162461bcd60e51b8152600401610839906136fa565b8061153c5760405162461bcd60e51b815260206004820152600d60248201526c043616e6e6f74206275726e203609c1b6044820152606401610839565b600061154d8264e8d4a51000613671565b905060d0548161155d9190613671565b33600090815260d1602052604090205461157791906136e3565b33600090815260d1602052604090205560cf546115959082906136e3565b60cf5560d0546115a59082613671565b60cd546115b291906136e3565b60cd5560405181815260009033906000805160206139bb8339815191529060200160405180910390a37fcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca5335b604080516001600160a01b0390921682526020820184905201610923565b33611625611e6b565b6001600160a01b03161461164b5760405162461bcd60e51b8152600401610839906136fa565b60335460ff161561166e5760405162461bcd60e51b81526004016108399061372f565b60d4546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a082319060240160206040518083038186803b1580156116b257600080fd5b505afa1580156116c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116ea91906136a8565b6116f99064e8d4a51000613671565b9050600061182460d560009054906101000a90046001600160a01b03166001600160a01b03166356dc3ac96040518163ffffffff1660e01b815260040160206040518083038186803b15801561174e57600080fd5b505afa158015611762573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061178691906138e2565b60d560009054906101000a90046001600160a01b03166001600160a01b031663adddb3f26040518163ffffffff1660e01b815260040160206040518083038186803b1580156117d457600080fd5b505afa1580156117e8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061180c91906138e2565b611816919061390b565b6001600160c01b0316612fcc565b60cf549091506118348284613690565b116118745760405162461bcd60e51b815260206004820152601060248201526f4e6f206578747261207265736572766560801b6044820152606401610839565b60cf54611894906118858385613690565b61188f91906136e3565b612fe0565b5050565b60d0546001600160a01b038216600090815260d160205260408120549091610993916136c1565b336118c8611e6b565b6001600160a01b0316146118ee5760405162461bcd60e51b8152600401610839906136fa565b6114456000613058565b60d6546001600160a01b0316336001600160a01b0316146119495760405162461bcd60e51b815260206004820152600b60248201526a37b7363c903830bab9b2b960a91b6044820152606401610839565b6114456130aa565b6000816001600160a01b03811661196757600080fd5b6001600160a01b03811630141561197d57600080fd5b6001600160a01b038416600090815260d1602052604081205460d0549091906119a690836136c1565b6001600160a01b038716600090815260d2602090815260408083203384529091529020549091506119d89082906136e3565b6001600160a01b03808816600081815260d26020908152604080832033845282528083209590955591815260d190915282812081905590871681522054611a20908390613690565b6001600160a01b03808716600081815260d1602052604090819020939093559151908816906000805160206139bb83398151915290610d039085815260200190565b60d560009054906101000a90046001600160a01b03166001600160a01b031663eb0c49556040518163ffffffff1660e01b8152600401602060405180830381600087803b158015611ab257600080fd5b505af1158015611ac6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611aea91906136a8565b5060335460ff1615611b0e5760405162461bcd60e51b81526004016108399061372f565b60d4546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a082319060240160206040518083038186803b158015611b5257600080fd5b505afa158015611b66573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b8a91906136a8565b905080611bcc5760405162461bcd60e51b815260206004820152601060248201526f5265736572766520697320656d70747960801b6044820152606401610839565b600064e8d4a51000306370a08231336040516001600160e01b031960e084901b1681526001600160a01b03909116600482015260240160206040518083038186803b158015611c1a57600080fd5b505afa158015611c2e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c5291906136a8565b611c5c91906136c1565b905081811115611c695750805b6000611c7a8264e8d4a51000613671565b60d4549091506001600160a01b031663a9059cbb336040516001600160e01b031960e084901b1681526001600160a01b03909116600482015260248101859052604401602060405180830381600087803b158015611cd757600080fd5b505af1158015611ceb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d0f9190613759565b611d2b5760405162461bcd60e51b81526004016108399061377b565b60d054611d389082613671565b33600090815260d16020526040902054611d5291906136e3565b33600090815260d1602052604090205560cf54611d709082906136e3565b60cf5560d054611d809082613671565b60cd54611d8d91906136e3565b60cd5560405181815260009033906000805160206139bb8339815191529060200160405180910390a360405181815233907f884edad9ce6fa2440d8a54cc123490eb96d2768479d49ff9c7366125a942436490602001611162565b33611df1611e6b565b6001600160a01b031614611e175760405162461bcd60e51b8152600401610839906136fa565b60cc80546001600160a01b0319166001600160a01b0383169081179091556040519081527f0e6961f1a1afb87eaf51fd64f22ddc10062e23aa7838eac5d0bdf140bfd389729060200160405180910390a150565b60006109396065546001600160a01b031690565b6060610939613102565b33611e92611e6b565b6001600160a01b031614611eb85760405162461bcd60e51b8152600401610839906136fa565b60d580546001600160a01b0319166001600160a01b0392909216919091179055565b60d560009054906101000a90046001600160a01b03166001600160a01b031663eb0c49556040518163ffffffff1660e01b8152600401602060405180830381600087803b158015611f2a57600080fd5b505af1158015611f3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f6291906136a8565b5033611f6c611e6b565b6001600160a01b031614611f925760405162461bcd60e51b8152600401610839906136fa565b80611fcf5760405162461bcd60e51b815260206004820152600d60248201526c043616e6e6f74206d696e74203609c1b6044820152606401610839565b6000611fe08264e8d4a51000613671565b905060d05481611ff09190613671565b33600090815260d1602052604090205461200a9190613690565b33600090815260d1602052604090205560cf54612028908290613690565b60cf5560d0546120389082613671565b60cd546120459190613690565b60cd5560405181815233906000906000805160206139bb8339815191529060200160405180910390a37f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d4121396885336115fe565b600054610100900460ff16806120ae575060005460ff16155b6120ca5760405162461bcd60e51b8152600401610839906137a4565b600054610100900460ff161580156120ec576000805461ffff19166101011790555b83516120ff90609790602087019061323d565b50825161211390609890602086019061323d565b506099805460ff191660ff84161790558015612135576000805461ff00191690555b50505050565b6000816001600160a01b03811661215157600080fd5b6001600160a01b03811630141561216757600080fd5b33600090815260d1602052604081205460d05490919061218790836136c1565b33600090815260d160205260408082208290556001600160a01b03881682529020549091506121b7908390613690565b6001600160a01b038616600081815260d160205260409081902092909255905133906000805160206139bb833981519152906121f69085815260200190565b60405180910390a36001935050505b50919050565b33600090815260d2602090815260408083206001600160a01b0386168452909152812054808310156122465761224183826136e3565b612249565b60005b33600081815260d2602090815260408083206001600160a01b038a16808552908352928190208590555193845290926000805160206139db833981519152910160405180910390a35060019392505050565b60cc546000906001600160a01b031633146122b557600080fd5b821580156122c1575081155b1561230b57837f72725a3b1e5bd622d6bcd1339bb31279c351abe8f541ac7fd320f24e1b1641f260cf546040516122fa91815260200190565b60405180910390a25060cf5461239c565b8215612327578260cf5461231f9190613690565b60cf55612339565b8160cf5461233591906136e3565b60cf555b60ce5460cf54111561234c5760ce5460cf555b60cf5460cd5461235c91906136c1565b60d05560cf5460405190815284907f72725a3b1e5bd622d6bcd1339bb31279c351abe8f541ac7fd320f24e1b1641f29060200160405180910390a25060cf545b9392505050565b6000826001600160a01b0381166123b957600080fd5b6001600160a01b0381163014156123cf57600080fd5b600060d054846123df9190613671565b33600090815260d160205260409020549091506123fd9082906136e3565b33600090815260d16020526040808220929092556001600160a01b0387168152205461242a908290613690565b6001600160a01b038616600081815260d160205260409081902092909255905133906000805160206139bb833981519152906124699088815260200190565b60405180910390a3506001949350505050565b60d560009054906101000a90046001600160a01b03166001600160a01b031663eb0c49556040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156124cc57600080fd5b505af11580156124e0573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061250491906136a8565b5060335460ff16156125285760405162461bcd60e51b81526004016108399061372f565b60006125398264e8d4a51000613671565b90506000811161257e5760405162461bcd60e51b815260206004820152601060248201526f043616e6e6f74206465706f73697420360841b6044820152606401610839565b60d4546000906001600160a01b031663dd62ed3e336040516001600160e01b031960e084901b1681526001600160a01b03909116600482015230602482015260440160206040518083038186803b1580156125d857600080fd5b505afa1580156125ec573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061261091906136a8565b90508281101561265b5760405162461bcd60e51b8152602060048201526016602482015275496e73756666696369656e7420416c6c6f77616e636560501b6044820152606401610839565b60d4546001600160a01b03166323b872dd336040516001600160e01b031960e084901b1681526001600160a01b03909116600482015230602482015260448101869052606401602060405180830381600087803b1580156126bb57600080fd5b505af11580156126cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126f39190613759565b61270f5760405162461bcd60e51b81526004016108399061377b565b60d05461271c9083613671565b33600090815260d160205260409020546127369190613690565b33600090815260d1602052604090205560cf54612754908390613690565b60cf5560d0546127649083613671565b60cd546127719190613690565b60cd5560405182815233906000906000805160206139bb8339815191529060200160405180910390a360405182815233907fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c90602001611162565b600054610100900460ff16806127e5575060005460ff16155b6128015760405162461bcd60e51b8152600401610839906137a4565b600054610100900460ff16158015612823576000805461ffff19166101011790555b61286b6040518060400160405280600a8152602001692aa9a224902a37b5b2b760b11b815250604051806040016040528060048152602001635553444960e01b815250611229565b612873613111565b60d480546001600160a01b0319166001600160a01b0384161790558015611894576000805461ff00191690555050565b60d5546001600160a01b0316336001600160a01b0316146128d65760405162461bcd60e51b81526004016108399061362d565b6128df81612fe0565b50565b834211156128ef57600080fd5b6001600160a01b03878116600081815260d3602090815260408083205481517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98185015280830195909552948b166060850152608084018a905260a0840185905260c08085018a90528151808603909101815260e0909401905282519201919091209061297a61117d565b60405161190160f01b602082015260228101919091526042810183905260620160408051601f1981840301815282825280516020918201206000845290830180835281905260ff8916918301919091526060820187905260808201869052915060019060a0016020604051602081039080840390855afa158015612a02573d6000803e3d6000fd5b505050602060405103516001600160a01b03168a6001600160a01b031614612a2957600080fd5b6001600160a01b038a16612a3c57600080fd5b612a47836001613690565b6001600160a01b038b8116600081815260d3602090815260408083209590955560d28152848220938e16808352938152908490208c905592518b8152919290916000805160206139db833981519152910160405180910390a350505050505050505050565b60d560009054906101000a90046001600160a01b03166001600160a01b031663eb0c49556040518163ffffffff1660e01b8152600401602060405180830381600087803b158015612afc57600080fd5b505af1158015612b10573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b3491906136a8565b5060335460ff1615612b585760405162461bcd60e51b81526004016108399061372f565b6000612b698264e8d4a51000613671565b905060008111612bae5760405162461bcd60e51b815260206004820152601060248201526f043616e6e6f74206465706f73697420360841b6044820152606401610839565b60d4546000906001600160a01b031663dd62ed3e336040516001600160e01b031960e084901b1681526001600160a01b03909116600482015230602482015260440160206040518083038186803b158015612c0857600080fd5b505afa158015612c1c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c4091906136a8565b905082811015612c8b5760405162461bcd60e51b8152602060048201526016602482015275496e73756666696369656e7420416c6c6f77616e636560501b6044820152606401610839565b60d4546001600160a01b03166323b872dd336040516001600160e01b031960e084901b1681526001600160a01b03909116600482015230602482015260448101869052606401602060405180830381600087803b158015612ceb57600080fd5b505af1158015612cff573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d239190613759565b612d3f5760405162461bcd60e51b81526004016108399061377b565b61137382612fe0565b33612d51611e6b565b6001600160a01b031614612d775760405162461bcd60e51b8152600401610839906136fa565b6001600160a01b038116612ddc5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610839565b6128df81613058565b606060978054612df49061393a565b80601f0160208091040260200160405190810160405280929190818152602001828054612e209061393a565b8015612e6d5780601f10612e4257610100808354040283529160200191612e6d565b820191906000526020600020905b815481529060010190602001808311612e5057829003601f168201915b5050505050905090565b60006001600160c01b038210612eba5760405162461bcd60e51b81526020600482015260086024820152676f766572666c6f7760c01b6044820152606401610839565b5090565b600054610100900460ff1680612ed7575060005460ff16155b612ef35760405162461bcd60e51b8152600401610839906137a4565b600054610100900460ff16158015612f15576000805461ffff19166101011790555b612f1d613140565b612f256131aa565b80156128df576000805461ff001916905550565b60335460ff16612f825760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610839565b6033805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6000610993670de0b6b3a7640000836136c1565b8060cf54612fee9190613690565b60cf81905560ce5410156130035760ce5460cf555b60cf5460cd5461301391906136c1565b60d05560cf5460408051838152602081019290925233917f106aac375bbcf013d1e52338bbf9e740009a1a3a6869f8daa1b72aa1620f5fec910160405180910390a250565b606580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60335460ff16156130cd5760405162461bcd60e51b81526004016108399061372f565b6033805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258612faf3390565b606060988054612df49061393a565b600054610100900460ff166131385760405162461bcd60e51b81526004016108399061396f565b61144561320a565b600054610100900460ff1680613159575060005460ff16155b6131755760405162461bcd60e51b8152600401610839906137a4565b600054610100900460ff16158015612f25576000805461ffff191661010117905580156128df576000805461ff001916905550565b600054610100900460ff16806131c3575060005460ff16155b6131df5760405162461bcd60e51b8152600401610839906137a4565b600054610100900460ff16158015613201576000805461ffff19166101011790555b612f2533613058565b600054610100900460ff166132315760405162461bcd60e51b81526004016108399061396f565b6033805460ff19169055565b8280546132499061393a565b90600052602060002090601f01602090048101928261326b57600085556132b1565b82601f1061328457805160ff19168380011785556132b1565b828001600101855582156132b1579182015b828111156132b1578251825591602001919060010190613296565b50612eba9291505b80821115612eba57600081556001016132b9565b80356001600160a01b03811681146132e457600080fd5b919050565b600080604083850312156132fc57600080fd5b613305836132cd565b946020939093013593505050565b600060208083528351808285015260005b8181101561334057858101830151858201604001528201613324565b81811115613352576000604083870101525b50601f01601f1916929092016040019392505050565b60006020828403121561337a57600080fd5b61239c826132cd565b60008060006060848603121561339857600080fd5b6133a1846132cd565b92506133af602085016132cd565b9150604084013590509250925092565b6000602082840312156133d157600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126133ff57600080fd5b813567ffffffffffffffff8082111561341a5761341a6133d8565b604051601f8301601f19908116603f01168101908282118183101715613442576134426133d8565b8160405283815286602085880101111561345b57600080fd5b836020870160208301376000602085830101528094505050505092915050565b6000806040838503121561348e57600080fd5b823567ffffffffffffffff808211156134a657600080fd5b6134b2868387016133ee565b935060208501359150808211156134c857600080fd5b506134d5858286016133ee565b9150509250929050565b600080604083850312156134f257600080fd5b6134fb836132cd565b9150613509602084016132cd565b90509250929050565b803560ff811681146132e457600080fd5b60008060006060848603121561353857600080fd5b833567ffffffffffffffff8082111561355057600080fd5b61355c878388016133ee565b9450602086013591508082111561357257600080fd5b5061357f868287016133ee565b92505061358e60408501613512565b90509250925092565b6000806000606084860312156135ac57600080fd5b505081359360208301359350604090920135919050565b600080600080600080600060e0888a0312156135de57600080fd5b6135e7886132cd565b96506135f5602089016132cd565b9550604088013594506060880135935061361160808901613512565b925060a0880135915060c0880135905092959891949750929550565b60208082526014908201527337b7363c902b30bab63a21b7b73a3937b63632b960611b604082015260600190565b634e487b7160e01b600052601160045260246000fd5b600081600019048311821515161561368b5761368b61365b565b500290565b600082198211156136a3576136a361365b565b500190565b6000602082840312156136ba57600080fd5b5051919050565b6000826136de57634e487b7160e01b600052601260045260246000fd5b500490565b6000828210156136f5576136f561365b565b500390565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b60208082526010908201526f14185d5cd8589b194e881c185d5cd95960821b604082015260600190565b60006020828403121561376b57600080fd5b8151801515811461239c57600080fd5b6020808252600f908201526e1d1c985b9cd9995c8819985a5b1959608a1b604082015260600190565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b600181815b8085111561382d5781600019048211156138135761381361365b565b8085161561382057918102915b93841c93908002906137f7565b509250929050565b60008261384457506001610993565b8161385157506000610993565b816001811461386757600281146138715761388d565b6001915050610993565b60ff8411156138825761388261365b565b50506001821b610993565b5060208310610133831016604e8410600b84101617156138b0575081810a610993565b6138ba83836137f2565b80600019048211156138ce576138ce61365b565b029392505050565b600061239c8383613835565b6000602082840312156138f457600080fd5b81516001600160c01b038116811461239c57600080fd5b60006001600160c01b03828116848216811515828404821116156139315761393161365b565b02949350505050565b600181811c9082168061394e57607f821691505b6020821081141561220557634e487b7160e01b600052602260045260246000fd5b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b60608201526080019056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925a2646970667358221220af54bd5125b96b6aa07228065133a1ddaef3bbd3b8d5772a52594080eee77d4c64736f6c63430008090033

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

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.