Overview
ETH Balance
0 ETH
Eth Value
$0.00Token Holdings
More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 25 from a total of 30 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Un Pause | 17784154 | 529 days ago | IN | 0 ETH | 0.00073481 | ||||
Set Vault Versio... | 17769660 | 531 days ago | IN | 0 ETH | 0.00058294 | ||||
Un Pause | 17669630 | 545 days ago | IN | 0 ETH | 0.00057905 | ||||
Update Interest ... | 17664530 | 546 days ago | IN | 0 ETH | 0.00255069 | ||||
Set Interest Con... | 17664034 | 546 days ago | IN | 0 ETH | 0.00146723 | ||||
Update Interest ... | 16976743 | 643 days ago | IN | 0 ETH | 0.00322103 | ||||
Set Interest Con... | 16976715 | 643 days ago | IN | 0 ETH | 0.0010176 | ||||
Do Action With L... | 16877599 | 657 days ago | IN | 0 ETH | 0.01744321 | ||||
Do Action With L... | 16877484 | 657 days ago | IN | 0 ETH | 0.01802414 | ||||
Do Action With L... | 16877479 | 657 days ago | IN | 0 ETH | 0.01706226 | ||||
Set Interest Con... | 16876800 | 657 days ago | IN | 0 ETH | 0.00093602 | ||||
Set Borrow Cap | 16876798 | 657 days ago | IN | 0 ETH | 0.00169809 | ||||
Set Interest Con... | 16835034 | 663 days ago | IN | 0 ETH | 0.00116592 | ||||
Set Borrow Cap | 16829697 | 663 days ago | IN | 0 ETH | 0.0007899 | ||||
Set Vault Versio... | 16829697 | 663 days ago | IN | 0 ETH | 0.00150215 | ||||
Set Supply Cap | 16792197 | 669 days ago | IN | 0 ETH | 0.00185585 | ||||
Change Guardian | 16779012 | 670 days ago | IN | 0 ETH | 0.00163097 | ||||
Set Supply Cap | 16777462 | 671 days ago | IN | 0 ETH | 0.00114184 | ||||
Set Treasury | 16777353 | 671 days ago | IN | 0 ETH | 0.00131148 | ||||
Set Interest Con... | 16777147 | 671 days ago | IN | 0 ETH | 0.00185244 | ||||
Set Borrow Cap | 16777147 | 671 days ago | IN | 0 ETH | 0.00183608 | ||||
Set Supply Cap | 16777147 | 671 days ago | IN | 0 ETH | 0.00116848 | ||||
Set Treasury Liq... | 16777147 | 671 days ago | IN | 0 ETH | 0.00118593 | ||||
Set Treasury Int... | 16777147 | 671 days ago | IN | 0 ETH | 0.00118542 | ||||
Add Tranche | 16777147 | 671 days ago | IN | 0 ETH | 0.00555768 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
LendingPool
Compiler Version
v0.8.17+commit.8df45f5f
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
/** * Created by Pragma Labs * SPDX-License-Identifier: BUSL-1.1 */ pragma solidity ^0.8.13; import { SafeTransferLib } from "../lib/solmate/src/utils/SafeTransferLib.sol"; import { SafeCastLib } from "../lib/solmate/src/utils/SafeCastLib.sol"; import { FixedPointMathLib } from "../lib/solmate/src/utils/FixedPointMathLib.sol"; import { LogExpMath } from "./utils/LogExpMath.sol"; import { ITranche } from "./interfaces/ITranche.sol"; import { IFactory } from "./interfaces/IFactory.sol"; import { IVault } from "./interfaces/IVault.sol"; import { ILiquidator } from "./interfaces/ILiquidator.sol"; import { ILendingPool } from "./interfaces/ILendingPool.sol"; import { TrustedCreditor } from "./TrustedCreditor.sol"; import { ERC20, ERC4626, DebtToken } from "./DebtToken.sol"; import { InterestRateModule } from "./InterestRateModule.sol"; import { Guardian } from "./security/Guardian.sol"; /** * @title Arcadia LendingPool. * @author Pragma Labs * @notice The Lending pool contains the main logic to provide liquidity and take or repay loans for a certain asset * and does the accounting of the debtTokens (ERC4626). * @dev Implementation not vulnerable to ERC4626 inflation attacks, * since totalAssets() cannot be manipulated by the first minter. * For more information, see https://github.com/OpenZeppelin/openzeppelin-contracts/issues/3706 */ contract LendingPool is Guardian, TrustedCreditor, DebtToken, InterestRateModule, ILendingPool { using SafeTransferLib for ERC20; using FixedPointMathLib for uint256; /* ////////////////////////////////////////////////////////////// STORAGE ////////////////////////////////////////////////////////////// */ // Seconds per year, leap years ignored. uint256 public constant YEARLY_SECONDS = 31_536_000; // Contract address of the Arcadia Vault Factory. address public immutable vaultFactory; // Contract address of the Liquidator contract. address public immutable liquidator; // Last timestamp that interests were realized. uint32 public lastSyncedTimestamp; // Origination fee, 4 decimals precision (10 equals 0.001 or 0.1%), capped at 255 (2.55%). uint8 public originationFee; // Sum of all the interest weights of the tranches + treasury. uint24 public totalInterestWeight; // Fraction (interestWeightTreasury / totalInterestWeight) of the interest fees that go to the treasury. uint16 public interestWeightTreasury; // Sum of the liquidation weights of the tranches + treasury. uint24 public totalLiquidationWeight; // Fraction (liquidationWeightTreasury / totalLiquidationWeight) of the liquidation fees that goes to the treasury. uint16 public liquidationWeightTreasury; // Total amount of `underlying asset` that is claimable by the LPs. Does not take into account pending interests. uint128 public totalRealisedLiquidity; // Maximum amount of `underlying asset` that can be supplied to the pool. uint128 public supplyCap; // Conservative estimate of the maximal gas cost to liquidate a position (fixed cost, independent of openDebt). uint96 public fixedLiquidationCost; // Maximum amount of `underlying asset` that is paid as fee to the initiator of a liquidation. uint80 public maxInitiatorFee; // Number of auctions that are currently in progress. uint16 public auctionsInProgress; // Address of the protocol treasury. address public treasury; // Array of the interest weights of each Tranche. // Fraction (interestWeightTranches[i] / totalInterestWeight) of the interest fees that go to Tranche i. uint16[] public interestWeightTranches; // Array of the liquidation weights of each Tranche. // Fraction (liquidationWeightTranches[i] / totalLiquidationWeight) of the liquidation fees that go to Tranche i. uint16[] public liquidationWeightTranches; // Array of the contract addresses of the Tranches. address[] public tranches; // Map tranche => status. mapping(address => bool) public isTranche; // Map tranche => interestWeight. // Fraction (interestWeightTranches[i] / totalInterestWeight) of the interest fees that go to Tranche i. mapping(address => uint256) public interestWeight; // Map tranche => realisedLiquidity. // Amount of `underlying asset` that is claimable by the Tranche. Does not take into account pending interests. mapping(address => uint256) public realisedLiquidityOf; // Map vault => initiator. // Stores the address of the initiator of an auction, used to pay out the initiation fee after auction is ended. mapping(address => address) public liquidationInitiator; // Map vault => owner => beneficiary => amount. // Stores the credit allowances for a beneficiary per Vault and per Owner. mapping(address => mapping(address => mapping(address => uint256))) public creditAllowance; /* ////////////////////////////////////////////////////////////// EVENTS ////////////////////////////////////////////////////////////// */ event TrancheAdded(address indexed tranche, uint8 indexed index, uint16 interestWeight, uint16 liquidationWeight); event InterestWeightSet(uint256 indexed index, uint16 weight); event LiquidationWeightSet(uint256 indexed index, uint16 weight); event MaxInitiatorFeeSet(uint80 maxInitiatorFee); event TranchePopped(address tranche); event TreasuryInterestWeightSet(uint16 weight); event TreasuryLiquidationWeightSet(uint16 weight); event OriginationFeeSet(uint8 originationFee); event BorrowCapSet(uint128 borrowCap); event SupplyCapSet(uint128 supplyCap); event CreditApproval(address indexed vault, address indexed owner, address indexed beneficiary, uint256 amount); event Borrow( address indexed vault, address indexed by, address to, uint256 amount, uint256 fee, bytes3 indexed referrer ); event Repay(address indexed vault, address indexed from, uint256 amount); event FixedLiquidationCostSet(uint96 fixedLiquidationCost); event VaultVersionSet(uint256 indexed vaultVersion, bool valid); error supplyCapExceeded(); /* ////////////////////////////////////////////////////////////// MODIFIERS ////////////////////////////////////////////////////////////// */ modifier onlyLiquidator() { require(liquidator == msg.sender, "LP: Only liquidator"); _; } modifier onlyTranche() { require(isTranche[msg.sender], "LP: Only tranche"); _; } modifier processInterests() { _syncInterests(); _; //_updateInterestRate() modifies the state (effect), but can safely be called after interactions. //Cannot be exploited by re-entrancy attack. _updateInterestRate(realisedDebt, totalRealisedLiquidity); } /* ////////////////////////////////////////////////////////////// CONSTRUCTOR ////////////////////////////////////////////////////////////// */ /** * @notice The constructor for a lending pool. * @param asset_ The underlying ERC-20 token of the Lending Pool. * @param treasury_ The address of the protocol treasury. * @param vaultFactory_ The address of the Vault Factory. * @param liquidator_ The address of the Liquidator. * @dev The name and symbol of the DebtToken are automatically generated, based on the name and symbol of the underlying token. */ constructor(ERC20 asset_, address treasury_, address vaultFactory_, address liquidator_) Guardian() TrustedCreditor() DebtToken(asset_) { treasury = treasury_; vaultFactory = vaultFactory_; liquidator = liquidator_; } /* ////////////////////////////////////////////////////////////// TRANCHES LOGIC ////////////////////////////////////////////////////////////// */ /** * @notice Adds a tranche to the Lending Pool. * @param tranche The address of the Tranche. * @param interestWeight_ The interestWeight of the specific Tranche. * @param liquidationWeight The liquidationWeight of the specific Tranche. * @dev The order of the tranches is important, the most senior tranche is added first at index 0, the most junior at the last index. * @dev Each Tranche is an ERC-4626 contract. * @dev The interestWeight of each Tranche determines the relative share of the yield (interest payments) that goes to its Liquidity providers. * @dev The liquidationWeight of each Tranche determines the relative share of the liquidation fee that goes to its Liquidity providers. */ function addTranche(address tranche, uint16 interestWeight_, uint16 liquidationWeight) external onlyOwner { require(!isTranche[tranche], "TR_AD: Already exists"); totalInterestWeight += interestWeight_; interestWeightTranches.push(interestWeight_); interestWeight[tranche] = interestWeight_; totalLiquidationWeight += liquidationWeight; liquidationWeightTranches.push(liquidationWeight); tranches.push(tranche); isTranche[tranche] = true; emit TrancheAdded(tranche, uint8(tranches.length - 1), interestWeight_, liquidationWeight); } /** * @notice Changes the interestWeight of a specific Tranche. * @param index The index of the Tranche for which a new interestWeight is being set. * @param weight The new interestWeight of the Tranche at the index. * @dev The interestWeight of each Tranche determines the relative share yield (interest payments) that goes to its Liquidity providers. */ function setInterestWeight(uint256 index, uint16 weight) external onlyOwner { require(index < tranches.length, "TR_SIW: Non Existing Tranche"); totalInterestWeight = totalInterestWeight - interestWeightTranches[index] + weight; interestWeightTranches[index] = weight; interestWeight[tranches[index]] = weight; emit InterestWeightSet(index, weight); } /** * @notice Changes the liquidationWeight of a specific tranche. * @param index The index of the Tranche for which a new liquidationWeight is being set. * @param weight The new liquidationWeight of the Tranche at the index. * @dev The liquidationWeight determines the relative share of the liquidation fee that goes to its Liquidity providers. */ function setLiquidationWeight(uint256 index, uint16 weight) external onlyOwner { require(index < tranches.length, "TR_SLW: Non Existing Tranche"); totalLiquidationWeight = totalLiquidationWeight - liquidationWeightTranches[index] + weight; liquidationWeightTranches[index] = weight; emit LiquidationWeightSet(index, weight); } /** * @notice Removes the Tranche at the last index (most junior). * @param index The index of the last Tranche. * @param tranche The address of the last Tranche. * @dev This function can only be called by the function _processDefault(uint256 assets), * when there is a default as big as (or bigger than) the complete principal of the most junior tranche. * @dev Passing the input parameters to the function saves gas compared to reading the address and index of the last tranche from memory. * No need to check if index and Tranche are indeed of the last tranche since function is only called by _processDefault. */ function _popTranche(uint256 index, address tranche) internal { totalInterestWeight -= interestWeightTranches[index]; totalLiquidationWeight -= liquidationWeightTranches[index]; isTranche[tranche] = false; interestWeightTranches.pop(); liquidationWeightTranches.pop(); tranches.pop(); emit TranchePopped(tranche); } /* /////////////////////////////////////////////////////////////// TREASURY FEE CONFIGURATION ////////////////////////////////////////////////////////////// */ /** * @notice Changes the fraction of the interest payments that go to the treasury. * @param interestWeightTreasury_ The new interestWeight of the treasury. * @dev The interestWeight determines the relative share of the yield (interest payments) that goes to the protocol treasury. * @dev Setting interestWeightTreasury to a very high value will cause the treasury to collect all interest fees from that moment on. * Although this will affect the future profits of liquidity providers, no funds nor realized interest are at risk for LPs. */ function setTreasuryInterestWeight(uint16 interestWeightTreasury_) external onlyOwner { totalInterestWeight = totalInterestWeight - interestWeightTreasury + interestWeightTreasury_; interestWeightTreasury = interestWeightTreasury_; emit TreasuryInterestWeightSet(interestWeightTreasury_); } /** * @notice Changes the fraction of the liquidation fees that go to the treasury. * @param liquidationWeightTreasury_ The new liquidationWeight of the liquidation fee fee. * @dev The liquidationWeight determines the relative share of the liquidation fee that goes to the protocol treasury. * @dev Setting liquidationWeightTreasury to a very high value will cause the treasury to collect all liquidation fees from that moment on. * Although this will affect the future profits of liquidity providers in the Jr tranche, no funds nor realized interest are at risk for LPs. */ function setTreasuryLiquidationWeight(uint16 liquidationWeightTreasury_) external onlyOwner { totalLiquidationWeight = totalLiquidationWeight - liquidationWeightTreasury + liquidationWeightTreasury_; liquidationWeightTreasury = liquidationWeightTreasury_; emit TreasuryLiquidationWeightSet(liquidationWeightTreasury_); } /** * @notice Sets new treasury address. * @param treasury_ The new address of the treasury. */ function setTreasury(address treasury_) external onlyOwner { treasury = treasury_; } /** * @notice Sets the new origination fee. * @param originationFee_ The new origination fee. * @dev originationFee is limited by being a uint8 -> max value is 2.55% * 4 decimal precision (10 = 0.1%). */ function setOriginationFee(uint8 originationFee_) external onlyOwner { originationFee = originationFee_; emit OriginationFeeSet(originationFee_); } /* ////////////////////////////////////////////////////////////// PROTOCOL CAP LOGIC ////////////////////////////////////////////////////////////// */ /** * @notice Sets the maximum amount of assets that can be borrowed per Vault. * @param borrowCap_ The new maximum amount that can be borrowed. * @dev The borrowCap is the maximum amount of assets that can be borrowed per Vault. * @dev If it is set to 0, there is no borrow cap. */ function setBorrowCap(uint128 borrowCap_) external onlyOwner { borrowCap = borrowCap_; emit BorrowCapSet(borrowCap_); } /** * @notice Sets the maximum amount of assets that can be deposited in the pool. * @param supplyCap_ The new maximum amount of assets that can be deposited. * @dev The supplyCap is the maximum amount of assets that can be deposited in the pool at any given time. * @dev If it is set to 0, there is no supply cap. */ function setSupplyCap(uint128 supplyCap_) external onlyOwner { supplyCap = supplyCap_; emit SupplyCapSet(supplyCap_); } /* ////////////////////////////////////////////////////////////// DEPOSIT/WITHDRAWAL LOGIC ////////////////////////////////////////////////////////////// */ /** * @notice Deposit assets in the Lending Pool. * @param assets The amount of assets of the underlying ERC-20 tokens being deposited. * @param from The address of the Liquidity Provider who deposits the underlying ERC-20 token via a Tranche. * @dev This function can only be called by Tranches. */ function depositInLendingPool(uint256 assets, address from) external whenDepositNotPaused onlyTranche processInterests { if (supplyCap > 0) { if (totalRealisedLiquidity + assets > supplyCap) revert supplyCapExceeded(); } // Need to transfer before minting or ERC777s could reenter. // Address(this) is trusted -> no risk on re-entrancy attack after transfer. asset.safeTransferFrom(from, address(this), assets); unchecked { realisedLiquidityOf[msg.sender] += assets; totalRealisedLiquidity += SafeCastLib.safeCastTo128(assets); } //Event emitted by Tranche. } /** * @notice Donate assets to the Lending Pool. * @param trancheIndex The index of the tranche to donate to. * @param assets The amount of assets of the underlying ERC-20 tokens being deposited. * @dev Can be used by anyone to donate assets to the Lending Pool. * It is supposed to serve as a way to compensate the jrTranche after an * auction didn't get sold and was manually Liquidated by the Protocol. * @dev First minter of a tranche could abuse this function by mining only 1 share, * frontrun next minter by calling this function and inflate the share price. * This is mitigated by checking that there are at least 10 ** decimals shares outstanding. */ function donateToTranche(uint256 trancheIndex, uint256 assets) external whenDepositNotPaused processInterests { require(assets > 0, "LP_DTT: Amount is 0"); if (supplyCap > 0) { if (totalRealisedLiquidity + assets > supplyCap) revert supplyCapExceeded(); } address tranche = tranches[trancheIndex]; //Mitigate share manipulation, where first Liquidity Provider mints just 1 share. //See https://github.com/OpenZeppelin/openzeppelin-contracts/issues/3706 for more information. require(ERC4626(tranche).totalSupply() >= 10 ** decimals, "LP_DTT: Insufficient shares"); asset.safeTransferFrom(msg.sender, address(this), assets); unchecked { realisedLiquidityOf[tranche] += assets; //[̲̅$̲̅(̲̅ ͡° ͜ʖ ͡°̲̅)̲̅$̲̅] totalRealisedLiquidity += SafeCastLib.safeCastTo128(assets); } } /** * @notice Withdraw assets from the Lending Pool. * @param assets The amount of assets of the underlying ERC-20 tokens being withdrawn. * @param receiver The address of the receiver of the underlying ERC-20 tokens. * @dev This function can be called by anyone with an open balance (realisedLiquidityOf[address] bigger than 0), * which can be both Tranches as other address (treasury, Liquidation Initiators, Liquidated Vault Owner...). */ function withdrawFromLendingPool(uint256 assets, address receiver) external whenWithdrawNotPaused processInterests { require(realisedLiquidityOf[msg.sender] >= assets, "LP_WFLP: Amount exceeds balance"); unchecked { realisedLiquidityOf[msg.sender] -= assets; } totalRealisedLiquidity -= SafeCastLib.safeCastTo128(assets); asset.safeTransfer(receiver, assets); //Event emitted by Tranche. } /* ////////////////////////////////////////////////////////////// LENDING LOGIC ////////////////////////////////////////////////////////////// */ /** * @notice Approve a beneficiary to take out a loan against an Arcadia Vault. * @param beneficiary The address of the beneficiary who can take out a loan backed by an Arcadia Vault. * @param amount The amount of underlying ERC-20 tokens to be lent out. * @param vault The address of the Arcadia Vault backing the loan. */ function approveBeneficiary(address beneficiary, uint256 amount, address vault) external { //If vault is not an actual address of a vault, ownerOfVault(address) will return the zero address. require(IFactory(vaultFactory).ownerOfVault(vault) == msg.sender, "LP_AB: UNAUTHORIZED"); creditAllowance[vault][msg.sender][beneficiary] = amount; emit CreditApproval(vault, msg.sender, beneficiary, amount); } /** * @notice Takes out a loan backed by collateral in an Arcadia Vault. * @param amount The amount of underlying ERC-20 tokens to be lent out. * @param vault The address of the Arcadia Vault backing the loan. * @param to The address who receives the lent out underlying tokens. * @param referrer A unique identifier of the referrer, who will receive part of the fees generated by this transaction. * @dev The sender might be different than the owner if they have the proper allowances. */ function borrow(uint256 amount, address vault, address to, bytes3 referrer) external whenBorrowNotPaused processInterests { //If vault is not an actual address of a vault, ownerOfVault(address) will return the zero address. address vaultOwner = IFactory(vaultFactory).ownerOfVault(vault); require(vaultOwner != address(0), "LP_B: Not a vault"); uint256 amountWithFee = amount + (amount * originationFee) / 10_000; //Check allowances to take debt. if (vaultOwner != msg.sender) { uint256 allowed = creditAllowance[vault][vaultOwner][msg.sender]; if (allowed != type(uint256).max) { creditAllowance[vault][vaultOwner][msg.sender] = allowed - amountWithFee; } } //Mint debt tokens to the vault. _deposit(amountWithFee, vault); //Add origination fee to the treasury. unchecked { totalRealisedLiquidity += SafeCastLib.safeCastTo128(amountWithFee - amount); realisedLiquidityOf[treasury] += amountWithFee - amount; } //Call vault to check if it is still healthy after the debt is increased with amountWithFee. (bool isHealthy, address trustedCreditor, uint256 vaultVersion) = IVault(vault).isVaultHealthy(0, maxWithdraw(vault)); require(isHealthy && trustedCreditor == address(this) && isValidVersion[vaultVersion], "LP_B: Reverted"); //Transfer fails if there is insufficient liquidity in the pool. asset.safeTransfer(to, amount); emit Borrow(vault, msg.sender, to, amount, amountWithFee - amount, referrer); } /** * @notice Repays a loan. * @param amount The amount of underlying ERC-20 tokens to be repaid. * @param vault The address of the Arcadia Vault backing the loan. * @dev if Vault is not an actual address of a Vault, maxWithdraw(vault) will always return 0. * Function will not revert, but transferAmount is always 0. * @dev Anyone (EOAs and contracts) can repay debt in the name of a vault. */ function repay(uint256 amount, address vault) external whenRepayNotPaused processInterests { uint256 vaultDebt = maxWithdraw(vault); uint256 transferAmount = vaultDebt > amount ? amount : vaultDebt; // Need to transfer before burning debt or ERC777s could reenter. // Address(this) is trusted -> no risk on re-entrancy attack after transfer. asset.safeTransferFrom(msg.sender, address(this), transferAmount); _withdraw(transferAmount, vault, vault); emit Repay(vault, msg.sender, transferAmount); } /* ////////////////////////////////////////////////////////////// LEVERAGED ACTIONS LOGIC ////////////////////////////////////////////////////////////// */ /** * @notice Execute and interact with external logic on leverage. * @param amountBorrowed The amount of underlying ERC-20 tokens to be lent out. * @param vault The address of the Arcadia Vault backing the loan. * @param actionHandler the address of the action handler to call. * @param actionData a bytes object containing two actionAssetData structs, an address array and a bytes array. * @param referrer A unique identifier of the referrer, who will receive part of the fees generated by this transaction. * @dev The sender might be different than the owner if they have the proper allowances. * @dev vaultManagementAction() works similar to flash loans, this function optimistically calls external logic and checks for the vault state at the very end. */ function doActionWithLeverage( uint256 amountBorrowed, address vault, address actionHandler, bytes calldata actionData, bytes3 referrer ) external whenBorrowNotPaused processInterests { //If vault is not an actual address of a vault, ownerOfVault(address) will return the zero address. address vaultOwner = IFactory(vaultFactory).ownerOfVault(vault); require(vaultOwner != address(0), "LP_DAWL: Not a vault"); uint256 amountBorrowedWithFee = amountBorrowed + (amountBorrowed * originationFee) / 10_000; //Check allowances to take debt. if (vaultOwner != msg.sender) { //Since calling vaultManagementAction() gives the sender full control over all assets in the vault, //Only Beneficiaries with maximum allowance can call the doActionWithLeverage function. require(creditAllowance[vault][vaultOwner][msg.sender] == type(uint256).max, "LP_DAWL: UNAUTHORIZED"); } //Mint debt tokens to the vault, debt must be minted Before the actions in the vault are performed. _deposit(amountBorrowedWithFee, vault); //Add origination fee to the treasury. unchecked { totalRealisedLiquidity += SafeCastLib.safeCastTo128(amountBorrowedWithFee - amountBorrowed); realisedLiquidityOf[treasury] += amountBorrowedWithFee - amountBorrowed; } //Send Borrowed funds to the actionHandler. asset.safeTransfer(actionHandler, amountBorrowed); //The actionHandler will use the borrowed funds (optionally with additional assets withdrawn from the Vault) //to execute one or more actions (swap, deposit, mint...). //Next the actionHandler will deposit any of the remaining funds or any of the recipient token //resulting from the actions back into the vault. //As last step, after all assets are deposited back into the vault a final health check is done: //The Collateral Value of all assets in the vault is bigger than the total liabilities against the vault (including the margin taken during this function). (address trustedCreditor, uint256 vaultVersion) = IVault(vault).vaultManagementAction(actionHandler, actionData); require(trustedCreditor == address(this) && isValidVersion[vaultVersion], "LP_DAWL: Reverted"); emit Borrow(vault, msg.sender, actionHandler, amountBorrowed, amountBorrowedWithFee - amountBorrowed, referrer); } /* ////////////////////////////////////////////////////////////// ACCOUNTING LOGIC ////////////////////////////////////////////////////////////// */ /** * @notice Returns the total amount of outstanding debt in the underlying asset. * @return totalDebt The total debt in underlying assets. */ function totalAssets() public view override returns (uint256 totalDebt) { // Avoid a second calculation of unrealised debt (expensive) // if interests are already synced this block. if (lastSyncedTimestamp != uint32(block.timestamp)) { totalDebt = realisedDebt + calcUnrealisedDebt(); } else { totalDebt = realisedDebt; } } /** * @notice Returns the redeemable amount of liquidity in the underlying asset of an address. * @param owner_ The address of the liquidity provider. * @return assets The redeemable amount of liquidity in the underlying asset. * @dev This function syncs the interests to prevent calculating UnrealisedDebt twice when depositing/withdrawing through the Tranches. * @dev After calling this function, the interest rate will not be updated until the next processInterests() call. */ function liquidityOfAndSync(address owner_) external returns (uint256 assets) { _syncInterests(); assets = realisedLiquidityOf[owner_]; } /** * @notice Returns the redeemable amount of liquidity in the underlying asset of an address. * @param owner_ The address of the liquidity provider. * @return assets The redeemable amount of liquidity in the underlying asset. */ function liquidityOf(address owner_) external view returns (uint256 assets) { // Avoid a second calculation of unrealised debt (expensive). // if interests are already synced this block. if (lastSyncedTimestamp != uint32(block.timestamp)) { // The total liquidity of a tranche equals the sum of the realised liquidity // of the tranche, and its pending interests. uint256 interest = calcUnrealisedDebt().mulDivUp(interestWeight[owner_], totalInterestWeight); unchecked { assets = realisedLiquidityOf[owner_] + interest; } } else { assets = realisedLiquidityOf[owner_]; } } /** * @notice Skims any surplus funds in the LendingPool to the treasury. * @dev In normal conditions (when there are no ongoing auctions), the total Claimable Liquidity should be equal * to the sum of the available funds (the balanceOf() the underlying asset) in the pool and the total open debt. * In practice the actual sum of available funds and total open debt will always be bigger than the total Claimable Liquidity. * This because of the rounding errors of the ERC4626 calculations (conversions between assets and shares), * or because someone accidentally sent funds directly to the pool instead of depositing via a Tranche. * This functions makes the surplus available to the Treasury (otherwise they would be lost forever). * @dev In case you accidentally sent funds to the pool, contact the current treasury manager. */ function skim() external processInterests { //During auctions, debt tokens are burned at start of the auction, while auctions proceeds are only returned //at the end of the auction -> skim function must be blocked during auctions. require(auctionsInProgress == 0, "LP_S: Auctions Ongoing"); //Pending interests are synced via the processInterests modifier. uint256 delta = asset.balanceOf(address(this)) + realisedDebt - totalRealisedLiquidity; //Add difference to the treasury. unchecked { totalRealisedLiquidity += SafeCastLib.safeCastTo128(delta); realisedLiquidityOf[treasury] += delta; } } /* ////////////////////////////////////////////////////////////// INTERESTS LOGIC ////////////////////////////////////////////////////////////// */ /** * @notice Syncs all unrealised debt (= interest for LP and treasury). * @dev Calculates the unrealised debt since last sync, and realises it by minting an equal amount of * debt tokens to all debt holders and interests to LPs and the treasury. */ function _syncInterests() internal { // Only Sync interests once per block. if (lastSyncedTimestamp != uint32(block.timestamp)) { uint256 unrealisedDebt = calcUnrealisedDebt(); lastSyncedTimestamp = uint32(block.timestamp); //Sync interests for borrowers. unchecked { realisedDebt += unrealisedDebt; } //Sync interests for LPs and Protocol Treasury. _syncInterestsToLiquidityProviders(unrealisedDebt); } } /** * @notice Calculates the unrealised debt (interests). * @return unrealisedDebt The unrealised debt. * @dev To Find the unrealised debt over an amount of time, you need to calculate D[(1+r)^x-1]. * The base of the exponential: 1 + r, is a 18 decimals fixed point number * with r the yearly interest rate. * The exponent of the exponential: x, is a 18 decimals fixed point number. * The exponent x is calculated as: the amount of seconds passed since last sync timestamp divided by the average of * seconds per year. _yearlyInterestRate = 1 + r expressed as 18 decimals fixed point number. */ function calcUnrealisedDebt() public view returns (uint256 unrealisedDebt) { uint256 base; uint256 exponent; unchecked { //gas: Can't overflow for reasonable interest rates. base = 1e18 + interestRate; //gas: Only overflows when (block.timestamp - lastSyncedBlockTimestamp) > 1e59 //in practice: exponent in LogExpMath lib is limited to 130e18, //Corresponding to a delta of timestamps of 4099680000 (or 130 years), //much bigger than any realistic time difference between two syncs. exponent = ((block.timestamp - lastSyncedTimestamp) * 1e18) / YEARLY_SECONDS; //gas: Taking an imaginary worst-case scenario with max interest of 1000% //over a period of 5 years. //This won't overflow as long as openDebt < 3402823669209384912995114146594816 //which is 3.4 million billion *10**18 decimals. unrealisedDebt = (realisedDebt * (LogExpMath.pow(base, exponent) - 1e18)) / 1e18; } return SafeCastLib.safeCastTo128(unrealisedDebt); } /** * @notice Syncs interest payments to the Lending providers and the treasury. * @param assets The total amount of underlying assets to be paid out as interests. * @dev The interestWeight of each Tranche determines the relative share yield (interest payments) that goes to its Liquidity providers. */ function _syncInterestsToLiquidityProviders(uint256 assets) internal { uint256 remainingAssets = assets; uint256 trancheShare; for (uint256 i; i < tranches.length;) { trancheShare = assets.mulDivDown(interestWeightTranches[i], totalInterestWeight); unchecked { realisedLiquidityOf[tranches[i]] += trancheShare; remainingAssets -= trancheShare; ++i; } } unchecked { totalRealisedLiquidity += SafeCastLib.safeCastTo128(assets); // Add the remainingAssets to the treasury balance. realisedLiquidityOf[treasury] += remainingAssets; } } /* ////////////////////////////////////////////////////////////// INTEREST RATE LOGIC ////////////////////////////////////////////////////////////// */ /** * @notice Set's the configuration parameters of InterestRateConfiguration struct. * @param newConfig New set of configuration parameters. */ function setInterestConfig(InterestRateConfiguration calldata newConfig) external onlyOwner { _setInterestConfig(newConfig); } /** * @notice Updates the interest rate. * @dev Any address can call this, it will sync unrealised interests and update the interest rate. */ function updateInterestRate() external processInterests { } /* ////////////////////////////////////////////////////////////// LIQUIDATION LOGIC ////////////////////////////////////////////////////////////// */ /** * @notice Sets the maxInitiatorFee. * @param maxInitiatorFee_ The maximum fee that is paid to the initiator of a liquidation. * @dev The liquidator sets the % of the debt that is paid to the initiator of a liquidation. * This fee is capped by the maxInitiatorFee. */ function setMaxInitiatorFee(uint80 maxInitiatorFee_) external onlyOwner { maxInitiatorFee = maxInitiatorFee_; emit MaxInitiatorFeeSet(maxInitiatorFee_); } /** * @notice Sets the estimated max gas cost to liquidate a position, denominated in baseCurrency. * @param fixedLiquidationCost_ The new fixedLiquidationCost. * @dev Conservative estimate of the maximal gas cost to liquidate a position (fixed cost, independent of openDebt). * The fixedLiquidationCost prevents dusting attacks, and ensures that upon Liquidations positions are big enough to cover. * gas costs of the Liquidator without resulting in badDebt. */ function setFixedLiquidationCost(uint96 fixedLiquidationCost_) external onlyOwner { fixedLiquidationCost = fixedLiquidationCost_; emit FixedLiquidationCostSet(fixedLiquidationCost_); } /** * @notice Starts liquidation of a Vault. * @param vault The vault address. * @dev At the start of the liquidation the debt tokens are burned, * as such interests are not accrued during the liquidation. */ function liquidateVault(address vault) external whenLiquidationNotPaused processInterests { //Only Vaults can have debt, and debtTokens are non-transferrable. //Hence by checking that the balance of the address passed as vault is not 0, we know the address //passed as vault is indeed a vault and has debt. uint256 openDebt = maxWithdraw(vault); require(openDebt != 0, "LP_LV: Not a Vault with debt"); //Store liquidation initiator to pay out initiator reward when auction is finished. liquidationInitiator[vault] = msg.sender; //Start the auction of the collateralised assets to repay debt. ILiquidator(liquidator).startAuction(vault, openDebt, maxInitiatorFee); //Hook to the most junior Tranche, to inform that auctions are ongoing, //already done if there are other auctions in progress (auctionsInProgress > O). if (auctionsInProgress == 0) { ITranche(tranches[tranches.length - 1]).setAuctionInProgress(true); } unchecked { ++auctionsInProgress; } //Remove debt from Vault (burn DebtTokens). _withdraw(openDebt, vault, vault); //Event emitted by Liquidator. } /** * @notice Settles the liquidation after the auction is finished and pays out Creditor, Original owner and Service providers. * @param vault The contract address of the vault. * @param originalOwner The original owner of the vault before the auction. * @param badDebt The amount of liabilities that was not recouped by the auction. * @param liquidationInitiatorReward The Reward for the Liquidation Initiator. * @param liquidationFee The additional fee the `originalOwner` has to pay to the protocol. * @param remainder Any funds remaining after the auction are returned back to the `originalOwner`. * @dev This function is called by the Liquidator after a liquidation is finished. * @dev The liquidator will transfer the auction proceeds (the underlying asset) * back to the liquidity pool after liquidation, before calling this function. */ function settleLiquidation( address vault, address originalOwner, uint256 badDebt, uint256 liquidationInitiatorReward, uint256 liquidationFee, uint256 remainder ) external onlyLiquidator processInterests { //Make Initiator rewards claimable for liquidationInitiator[vault]. realisedLiquidityOf[liquidationInitiator[vault]] += liquidationInitiatorReward; if (badDebt > 0) { //Collateral was auctioned for less than the liabilities (openDebt + Liquidation Initiator Reward) //-> Default event, deduct badDebt from LPs, starting with most Junior Tranche. totalRealisedLiquidity = SafeCastLib.safeCastTo128(uint256(totalRealisedLiquidity) + liquidationInitiatorReward - badDebt); _processDefault(badDebt); } else { //Collateral was auctioned for more than the liabilities //-> Pay out the Liquidation Fee to treasury and Tranches. _syncLiquidationFeeToLiquidityProviders(liquidationFee); totalRealisedLiquidity = SafeCastLib.safeCastTo128( uint256(totalRealisedLiquidity) + liquidationInitiatorReward + liquidationFee + remainder ); //Any remaining assets after paying off liabilities and the fee go back to the original Vault Owner. if (remainder > 0) { //Make remainder claimable by originalOwner. realisedLiquidityOf[originalOwner] += remainder; } } unchecked { --auctionsInProgress; } //Hook to the most junior Tranche to inform that there are no ongoing auctions. if (auctionsInProgress == 0 && tranches.length > 0) { ITranche(tranches[tranches.length - 1]).setAuctionInProgress(false); } //Event emitted by Liquidator. } /** * @notice Handles the bookkeeping in case of bad debt (Vault became undercollateralised). * @param badDebt The total amount of underlying assets that need to be written off as bad debt. * @dev The order of the Tranches is important, the most senior tranche is at index 0, the most junior at the last index. * @dev The most junior tranche will lose its underlying assets first. If all liquidity of a certain Tranche is written off, * the complete tranche is locked and removed. If there is still remaining bad debt, the next Tranche starts losing capital. */ function _processDefault(uint256 badDebt) internal { address tranche; uint256 maxBurnable; for (uint256 i = tranches.length; i > 0;) { unchecked { --i; } tranche = tranches[i]; maxBurnable = realisedLiquidityOf[tranche]; if (badDebt < maxBurnable) { //Deduct badDebt from the balance of the most junior Tranche. unchecked { realisedLiquidityOf[tranche] -= badDebt; } break; } else { //Unhappy flow, should never occur in practice! //badDebt is bigger than balance most junior Tranche -> tranche is completely wiped out //and temporarily locked (no new deposits or withdraws possible). //DAO or insurance might refund (Part of) the losses, and add Tranche back. realisedLiquidityOf[tranche] = 0; _popTranche(i, tranche); unchecked { badDebt -= maxBurnable; } ITranche(tranche).lock(); //Hook to the new most junior Tranche to inform that auctions are ongoing. if (i != 0) ITranche(tranches[i - 1]).setAuctionInProgress(true); } } } /** * @notice Syncs liquidation penalties to the Lending providers and the treasury. * @param assets The total amount of underlying assets to be paid out as liquidation fee. * @dev The liquidationWeight of each Tranche determines the relative share yield (interest payments) that goes to its Liquidity providers. */ function _syncLiquidationFeeToLiquidityProviders(uint256 assets) internal { uint256 remainingAssets = assets; uint256 trancheShare; uint256 weightOfTranche; for (uint256 i; i < tranches.length;) { weightOfTranche = liquidationWeightTranches[i]; if (weightOfTranche != 0) { //skip if weight is zero, which is the case for Sr tranche. trancheShare = assets.mulDivDown(weightOfTranche, totalLiquidationWeight); unchecked { realisedLiquidityOf[tranches[i]] += trancheShare; remainingAssets -= trancheShare; } } unchecked { ++i; } } unchecked { // Add the remainingAssets to the treasury balance. realisedLiquidityOf[treasury] += remainingAssets; } } /* ////////////////////////////////////////////////////////////// VAULT LOGIC ////////////////////////////////////////////////////////////// */ /** * @notice Enables or disables a certain Vault version to be used as margin account. * @param vaultVersion The Vault version to be enabled/disabled. * @param valid The validity of the respective vaultVersion. */ function setVaultVersion(uint256 vaultVersion, bool valid) external onlyOwner { _setVaultVersion(vaultVersion, valid); emit VaultVersionSet(vaultVersion, valid); } /** * @inheritdoc TrustedCreditor */ function openMarginAccount(uint256 vaultVersion) external view override returns (bool success, address baseCurrency, address liquidator_, uint256 fixedLiquidationCost_) { if (isValidVersion[vaultVersion]) { success = true; baseCurrency = address(asset); liquidator_ = liquidator; fixedLiquidationCost_ = fixedLiquidationCost; } } /** * @inheritdoc TrustedCreditor */ function getOpenPosition(address vault) external view override returns (uint256 openPosition) { openPosition = maxWithdraw(vault); } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; /// @notice Simple single owner authorization mixin. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/auth/Owned.sol) abstract contract Owned { /*////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ event OwnershipTransferred(address indexed user, address indexed newOwner); /*////////////////////////////////////////////////////////////// OWNERSHIP STORAGE //////////////////////////////////////////////////////////////*/ address public owner; modifier onlyOwner() virtual { require(msg.sender == owner, "UNAUTHORIZED"); _; } /*////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////*/ constructor(address _owner) { owner = _owner; emit OwnershipTransferred(address(0), _owner); } /*////////////////////////////////////////////////////////////// OWNERSHIP LOGIC //////////////////////////////////////////////////////////////*/ function transferOwnership(address newOwner) public virtual onlyOwner { owner = newOwner; emit OwnershipTransferred(msg.sender, newOwner); } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; import {ERC20} from "../tokens/ERC20.sol"; import {SafeTransferLib} from "../utils/SafeTransferLib.sol"; import {FixedPointMathLib} from "../utils/FixedPointMathLib.sol"; /// @notice Minimal ERC4626 tokenized Vault implementation. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/mixins/ERC4626.sol) abstract contract ERC4626 is ERC20 { using SafeTransferLib for ERC20; using FixedPointMathLib for uint256; /*////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ event Deposit(address indexed caller, address indexed owner, uint256 assets, uint256 shares); event Withdraw( address indexed caller, address indexed receiver, address indexed owner, uint256 assets, uint256 shares ); /*////////////////////////////////////////////////////////////// IMMUTABLES //////////////////////////////////////////////////////////////*/ ERC20 public immutable asset; constructor( ERC20 _asset, string memory _name, string memory _symbol ) ERC20(_name, _symbol, _asset.decimals()) { asset = _asset; } /*////////////////////////////////////////////////////////////// DEPOSIT/WITHDRAWAL LOGIC //////////////////////////////////////////////////////////////*/ function deposit(uint256 assets, address receiver) public virtual returns (uint256 shares) { // Check for rounding error since we round down in previewDeposit. require((shares = previewDeposit(assets)) != 0, "ZERO_SHARES"); // Need to transfer before minting or ERC777s could reenter. asset.safeTransferFrom(msg.sender, address(this), assets); _mint(receiver, shares); emit Deposit(msg.sender, receiver, assets, shares); afterDeposit(assets, shares); } function mint(uint256 shares, address receiver) public virtual returns (uint256 assets) { assets = previewMint(shares); // No need to check for rounding error, previewMint rounds up. // Need to transfer before minting or ERC777s could reenter. asset.safeTransferFrom(msg.sender, address(this), assets); _mint(receiver, shares); emit Deposit(msg.sender, receiver, assets, shares); afterDeposit(assets, shares); } function withdraw( uint256 assets, address receiver, address owner ) public virtual returns (uint256 shares) { shares = previewWithdraw(assets); // No need to check for rounding error, previewWithdraw rounds up. if (msg.sender != owner) { uint256 allowed = allowance[owner][msg.sender]; // Saves gas for limited approvals. if (allowed != type(uint256).max) allowance[owner][msg.sender] = allowed - shares; } beforeWithdraw(assets, shares); _burn(owner, shares); emit Withdraw(msg.sender, receiver, owner, assets, shares); asset.safeTransfer(receiver, assets); } function redeem( uint256 shares, address receiver, address owner ) public virtual returns (uint256 assets) { if (msg.sender != owner) { uint256 allowed = allowance[owner][msg.sender]; // Saves gas for limited approvals. if (allowed != type(uint256).max) allowance[owner][msg.sender] = allowed - shares; } // Check for rounding error since we round down in previewRedeem. require((assets = previewRedeem(shares)) != 0, "ZERO_ASSETS"); beforeWithdraw(assets, shares); _burn(owner, shares); emit Withdraw(msg.sender, receiver, owner, assets, shares); asset.safeTransfer(receiver, assets); } /*////////////////////////////////////////////////////////////// ACCOUNTING LOGIC //////////////////////////////////////////////////////////////*/ function totalAssets() public view virtual returns (uint256); function convertToShares(uint256 assets) public view virtual returns (uint256) { uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero. return supply == 0 ? assets : assets.mulDivDown(supply, totalAssets()); } function convertToAssets(uint256 shares) public view virtual returns (uint256) { uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero. return supply == 0 ? shares : shares.mulDivDown(totalAssets(), supply); } function previewDeposit(uint256 assets) public view virtual returns (uint256) { return convertToShares(assets); } function previewMint(uint256 shares) public view virtual returns (uint256) { uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero. return supply == 0 ? shares : shares.mulDivUp(totalAssets(), supply); } function previewWithdraw(uint256 assets) public view virtual returns (uint256) { uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero. return supply == 0 ? assets : assets.mulDivUp(supply, totalAssets()); } function previewRedeem(uint256 shares) public view virtual returns (uint256) { return convertToAssets(shares); } /*////////////////////////////////////////////////////////////// DEPOSIT/WITHDRAWAL LIMIT LOGIC //////////////////////////////////////////////////////////////*/ function maxDeposit(address) public view virtual returns (uint256) { return type(uint256).max; } function maxMint(address) public view virtual returns (uint256) { return type(uint256).max; } function maxWithdraw(address owner) public view virtual returns (uint256) { return convertToAssets(balanceOf[owner]); } function maxRedeem(address owner) public view virtual returns (uint256) { return balanceOf[owner]; } /*////////////////////////////////////////////////////////////// INTERNAL HOOKS LOGIC //////////////////////////////////////////////////////////////*/ function beforeWithdraw(uint256 assets, uint256 shares) internal virtual {} function afterDeposit(uint256 assets, uint256 shares) internal virtual {} }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; /// @notice Modern and gas efficient ERC20 + EIP-2612 implementation. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol) /// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol) /// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it. abstract contract ERC20 { /*////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ event Transfer(address indexed from, address indexed to, uint256 amount); event Approval(address indexed owner, address indexed spender, uint256 amount); /*////////////////////////////////////////////////////////////// METADATA STORAGE //////////////////////////////////////////////////////////////*/ string public name; string public symbol; uint8 public immutable decimals; /*////////////////////////////////////////////////////////////// ERC20 STORAGE //////////////////////////////////////////////////////////////*/ uint256 public totalSupply; mapping(address => uint256) public balanceOf; mapping(address => mapping(address => uint256)) public allowance; /*////////////////////////////////////////////////////////////// EIP-2612 STORAGE //////////////////////////////////////////////////////////////*/ uint256 internal immutable INITIAL_CHAIN_ID; bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR; mapping(address => uint256) public nonces; /*////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////*/ constructor( string memory _name, string memory _symbol, uint8 _decimals ) { name = _name; symbol = _symbol; decimals = _decimals; INITIAL_CHAIN_ID = block.chainid; INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator(); } /*////////////////////////////////////////////////////////////// ERC20 LOGIC //////////////////////////////////////////////////////////////*/ function approve(address spender, uint256 amount) public virtual returns (bool) { allowance[msg.sender][spender] = amount; emit Approval(msg.sender, spender, amount); return true; } function transfer(address to, uint256 amount) public virtual returns (bool) { balanceOf[msg.sender] -= amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(msg.sender, to, amount); return true; } function transferFrom( address from, address to, uint256 amount ) public virtual returns (bool) { uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals. if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount; balanceOf[from] -= amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(from, to, amount); return true; } /*////////////////////////////////////////////////////////////// EIP-2612 LOGIC //////////////////////////////////////////////////////////////*/ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) public virtual { require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED"); // Unchecked because the only math done is incrementing // the owner's nonce which cannot realistically overflow. unchecked { address recoveredAddress = ecrecover( keccak256( abi.encodePacked( "\x19\x01", DOMAIN_SEPARATOR(), keccak256( abi.encode( keccak256( "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)" ), owner, spender, value, nonces[owner]++, deadline ) ) ) ), v, r, s ); require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER"); allowance[recoveredAddress][spender] = value; } emit Approval(owner, spender, value); } function DOMAIN_SEPARATOR() public view virtual returns (bytes32) { return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator(); } function computeDomainSeparator() internal view virtual returns (bytes32) { return keccak256( abi.encode( keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), keccak256(bytes(name)), keccak256("1"), block.chainid, address(this) ) ); } /*////////////////////////////////////////////////////////////// INTERNAL MINT/BURN LOGIC //////////////////////////////////////////////////////////////*/ function _mint(address to, uint256 amount) internal virtual { totalSupply += amount; // Cannot overflow because the sum of all user // balances can't exceed the max uint256 value. unchecked { balanceOf[to] += amount; } emit Transfer(address(0), to, amount); } function _burn(address from, uint256 amount) internal virtual { balanceOf[from] -= amount; // Cannot underflow because a user's balance // will never be larger than the total supply. unchecked { totalSupply -= amount; } emit Transfer(from, address(0), amount); } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; /// @notice Arithmetic library with operations for fixed-point numbers. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol) /// @author Inspired by USM (https://github.com/usmfum/USM/blob/master/contracts/WadMath.sol) library FixedPointMathLib { /*////////////////////////////////////////////////////////////// SIMPLIFIED FIXED POINT OPERATIONS //////////////////////////////////////////////////////////////*/ uint256 internal constant MAX_UINT256 = 2**256 - 1; uint256 internal constant WAD = 1e18; // The scalar of ETH and most ERC20s. function mulWadDown(uint256 x, uint256 y) internal pure returns (uint256) { return mulDivDown(x, y, WAD); // Equivalent to (x * y) / WAD rounded down. } function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256) { return mulDivUp(x, y, WAD); // Equivalent to (x * y) / WAD rounded up. } function divWadDown(uint256 x, uint256 y) internal pure returns (uint256) { return mulDivDown(x, WAD, y); // Equivalent to (x * WAD) / y rounded down. } function divWadUp(uint256 x, uint256 y) internal pure returns (uint256) { return mulDivUp(x, WAD, y); // Equivalent to (x * WAD) / y rounded up. } /*////////////////////////////////////////////////////////////// LOW LEVEL FIXED POINT OPERATIONS //////////////////////////////////////////////////////////////*/ function mulDivDown( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y)) if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) { revert(0, 0) } // Divide x * y by the denominator. z := div(mul(x, y), denominator) } } function mulDivUp( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y)) if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) { revert(0, 0) } // If x * y modulo the denominator is strictly greater than 0, // 1 is added to round up the division of x * y by the denominator. z := add(gt(mod(mul(x, y), denominator), 0), div(mul(x, y), denominator)) } } function rpow( uint256 x, uint256 n, uint256 scalar ) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { switch x case 0 { switch n case 0 { // 0 ** 0 = 1 z := scalar } default { // 0 ** n = 0 z := 0 } } default { switch mod(n, 2) case 0 { // If n is even, store scalar in z for now. z := scalar } default { // If n is odd, store x in z for now. z := x } // Shifting right by 1 is like dividing by 2. let half := shr(1, scalar) for { // Shift n right by 1 before looping to halve it. n := shr(1, n) } n { // Shift n right by 1 each iteration to halve it. n := shr(1, n) } { // Revert immediately if x ** 2 would overflow. // Equivalent to iszero(eq(div(xx, x), x)) here. if shr(128, x) { revert(0, 0) } // Store x squared. let xx := mul(x, x) // Round to the nearest number. let xxRound := add(xx, half) // Revert if xx + half overflowed. if lt(xxRound, xx) { revert(0, 0) } // Set x to scaled xxRound. x := div(xxRound, scalar) // If n is even: if mod(n, 2) { // Compute z * x. let zx := mul(z, x) // If z * x overflowed: if iszero(eq(div(zx, x), z)) { // Revert if x is non-zero. if iszero(iszero(x)) { revert(0, 0) } } // Round to the nearest number. let zxRound := add(zx, half) // Revert if zx + half overflowed. if lt(zxRound, zx) { revert(0, 0) } // Return properly scaled zxRound. z := div(zxRound, scalar) } } } } } /*////////////////////////////////////////////////////////////// GENERAL NUMBER UTILITIES //////////////////////////////////////////////////////////////*/ function sqrt(uint256 x) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { let y := x // We start y at x, which will help us make our initial estimate. z := 181 // The "correct" value is 1, but this saves a multiplication later. // This segment is to get a reasonable initial estimate for the Babylonian method. With a bad // start, the correct # of bits increases ~linearly each iteration instead of ~quadratically. // We check y >= 2^(k + 8) but shift right by k bits // each branch to ensure that if x >= 256, then y >= 256. if iszero(lt(y, 0x10000000000000000000000000000000000)) { y := shr(128, y) z := shl(64, z) } if iszero(lt(y, 0x1000000000000000000)) { y := shr(64, y) z := shl(32, z) } if iszero(lt(y, 0x10000000000)) { y := shr(32, y) z := shl(16, z) } if iszero(lt(y, 0x1000000)) { y := shr(16, y) z := shl(8, z) } // Goal was to get z*z*y within a small factor of x. More iterations could // get y in a tighter range. Currently, we will have y in [256, 256*2^16). // We ensured y >= 256 so that the relative difference between y and y+1 is small. // That's not possible if x < 256 but we can just verify those cases exhaustively. // Now, z*z*y <= x < z*z*(y+1), and y <= 2^(16+8), and either y >= 256, or x < 256. // Correctness can be checked exhaustively for x < 256, so we assume y >= 256. // Then z*sqrt(y) is within sqrt(257)/sqrt(256) of sqrt(x), or about 20bps. // For s in the range [1/256, 256], the estimate f(s) = (181/1024) * (s+1) is in the range // (1/2.84 * sqrt(s), 2.84 * sqrt(s)), with largest error when s = 1 and when s = 256 or 1/256. // Since y is in [256, 256*2^16), let a = y/65536, so that a is in [1/256, 256). Then we can estimate // sqrt(y) using sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2^18. // There is no overflow risk here since y < 2^136 after the first branch above. z := shr(18, mul(z, add(y, 65536))) // A mul() is saved from starting z at 181. // Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough. z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) z := shr(1, add(z, div(x, z))) // If x+1 is a perfect square, the Babylonian method cycles between // floor(sqrt(x)) and ceil(sqrt(x)). This statement ensures we return floor. // See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division // Since the ceil is rare, we save gas on the assignment and repeat division in the rare case. // If you don't care whether the floor or ceil square root is returned, you can remove this statement. z := sub(z, lt(div(x, z), z)) } } function unsafeMod(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Mod x by y. Note this will return // 0 instead of reverting if y is zero. z := mod(x, y) } } function unsafeDiv(uint256 x, uint256 y) internal pure returns (uint256 r) { /// @solidity memory-safe-assembly assembly { // Divide x by y. Note this will return // 0 instead of reverting if y is zero. r := div(x, y) } } function unsafeDivUp(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly assembly { // Add 1 to x * y if x % y > 0. Note this will // return 0 instead of reverting if y is zero. z := add(gt(mod(x, y), 0), div(x, y)) } } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; /// @notice Safe unsigned integer casting library that reverts on overflow. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeCastLib.sol) /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/SafeCast.sol) library SafeCastLib { function safeCastTo248(uint256 x) internal pure returns (uint248 y) { require(x < 1 << 248); y = uint248(x); } function safeCastTo224(uint256 x) internal pure returns (uint224 y) { require(x < 1 << 224); y = uint224(x); } function safeCastTo192(uint256 x) internal pure returns (uint192 y) { require(x < 1 << 192); y = uint192(x); } function safeCastTo160(uint256 x) internal pure returns (uint160 y) { require(x < 1 << 160); y = uint160(x); } function safeCastTo128(uint256 x) internal pure returns (uint128 y) { require(x < 1 << 128); y = uint128(x); } function safeCastTo96(uint256 x) internal pure returns (uint96 y) { require(x < 1 << 96); y = uint96(x); } function safeCastTo64(uint256 x) internal pure returns (uint64 y) { require(x < 1 << 64); y = uint64(x); } function safeCastTo32(uint256 x) internal pure returns (uint32 y) { require(x < 1 << 32); y = uint32(x); } function safeCastTo24(uint256 x) internal pure returns (uint24 y) { require(x < 1 << 24); y = uint24(x); } function safeCastTo16(uint256 x) internal pure returns (uint16 y) { require(x < 1 << 16); y = uint16(x); } function safeCastTo8(uint256 x) internal pure returns (uint8 y) { require(x < 1 << 8); y = uint8(x); } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; import {ERC20} from "../tokens/ERC20.sol"; /// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol) /// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer. /// @dev Note that none of the functions in this library check that a token has code at all! That responsibility is delegated to the caller. library SafeTransferLib { /*////////////////////////////////////////////////////////////// ETH OPERATIONS //////////////////////////////////////////////////////////////*/ function safeTransferETH(address to, uint256 amount) internal { bool success; /// @solidity memory-safe-assembly assembly { // Transfer the ETH and store if it succeeded or not. success := call(gas(), to, amount, 0, 0, 0, 0) } require(success, "ETH_TRANSFER_FAILED"); } /*////////////////////////////////////////////////////////////// ERC20 OPERATIONS //////////////////////////////////////////////////////////////*/ function safeTransferFrom( ERC20 token, address from, address to, uint256 amount ) internal { bool success; /// @solidity memory-safe-assembly assembly { // Get a pointer to some free memory. let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000) mstore(add(freeMemoryPointer, 4), from) // Append the "from" argument. mstore(add(freeMemoryPointer, 36), to) // Append the "to" argument. mstore(add(freeMemoryPointer, 68), amount) // Append the "amount" argument. success := and( // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())), // We use 100 because the length of our calldata totals up like so: 4 + 32 * 3. // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space. // Counterintuitively, this call must be positioned second to the or() call in the // surrounding and() call or else returndatasize() will be zero during the computation. call(gas(), token, 0, freeMemoryPointer, 100, 0, 32) ) } require(success, "TRANSFER_FROM_FAILED"); } function safeTransfer( ERC20 token, address to, uint256 amount ) internal { bool success; /// @solidity memory-safe-assembly assembly { // Get a pointer to some free memory. let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000) mstore(add(freeMemoryPointer, 4), to) // Append the "to" argument. mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. success := and( // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())), // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2. // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space. // Counterintuitively, this call must be positioned second to the or() call in the // surrounding and() call or else returndatasize() will be zero during the computation. call(gas(), token, 0, freeMemoryPointer, 68, 0, 32) ) } require(success, "TRANSFER_FAILED"); } function safeApprove( ERC20 token, address to, uint256 amount ) internal { bool success; /// @solidity memory-safe-assembly assembly { // Get a pointer to some free memory. let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000) mstore(add(freeMemoryPointer, 4), to) // Append the "to" argument. mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. success := and( // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())), // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2. // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space. // Counterintuitively, this call must be positioned second to the or() call in the // surrounding and() call or else returndatasize() will be zero during the computation. call(gas(), token, 0, freeMemoryPointer, 68, 0, 32) ) } require(success, "APPROVE_FAILED"); } }
/** * Created by Pragma Labs * SPDX-License-Identifier: BUSL-1.1 */ pragma solidity ^0.8.13; import { ERC20, ERC4626 } from "../lib/solmate/src/mixins/ERC4626.sol"; import { FixedPointMathLib } from "../lib/solmate/src/utils/FixedPointMathLib.sol"; /** * @title Debt Token. * @author Pragma Labs * @notice The Logic to do the debt accounting for a lending pool for a certain ERC20 token. * @dev Protocol is according the ERC4626 standard, with a certain ERC20 as underlying. * @dev Implementation not vulnerable to ERC4626 inflation attacks, * since totalAssets() cannot be manipulated by first minter when total amount of shares are low. * For more information, see https://github.com/OpenZeppelin/openzeppelin-contracts/issues/3706. */ abstract contract DebtToken is ERC4626 { using FixedPointMathLib for uint256; /* ////////////////////////////////////////////////////////////// STORAGE ////////////////////////////////////////////////////////////// */ // Total amount of `underlying asset` that debtors have in debt, does not take into account pending interests. uint256 public realisedDebt; // Maximum amount of `underlying asset` in debt that a single debtor can take. uint128 public borrowCap; error FunctionNotImplemented(); /* ////////////////////////////////////////////////////////////// CONSTRUCTOR ////////////////////////////////////////////////////////////// */ /** * @notice The constructor for the debt token. * @param asset_ The underlying ERC-20 token in which the debt is denominated. */ constructor(ERC20 asset_) ERC4626( asset_, string(abi.encodePacked("Arcadia ", asset_.name(), " Debt")), string(abi.encodePacked("darc", asset_.symbol())) ) { } /*////////////////////////////////////////////////////////////// ACCOUNTING LOGIC //////////////////////////////////////////////////////////////*/ /** * @notice Returns the total amount of outstanding debt in the underlying asset. * @return totalDebt The total debt in underlying assets. * @dev Implementation overwritten in LendingPool.sol which inherits DebtToken.sol. * Implementation not vulnerable to ERC4626 inflation attacks, * totaLAssets() does not rely on balanceOf call. */ function totalAssets() public view virtual override returns (uint256) { } /*////////////////////////////////////////////////////////////// DEPOSIT/WITHDRAWAL LOGIC //////////////////////////////////////////////////////////////*/ /** * @notice Modification of the standard ERC-4626 deposit implementation. * @dev No public deposit allowed. */ function deposit(uint256, address) public pure override returns (uint256) { revert FunctionNotImplemented(); } /** * @notice Modification of the standard ERC-4626 deposit implementation. * @param assets The amount of assets of the underlying ERC-20 token being loaned out. * @param receiver The Arcadia vault with collateral covering the loan. * @return shares The corresponding amount of debt shares minted. * @dev Only the Lending Pool (which inherits this contract) can issue debt. */ function _deposit(uint256 assets, address receiver) internal returns (uint256 shares) { shares = previewDeposit(assets); // No need to check for rounding error, previewDeposit rounds up. if (borrowCap > 0) require(maxWithdraw(receiver) + assets <= borrowCap, "DT_D: BORROW_CAP_EXCEEDED"); _mint(receiver, shares); realisedDebt += assets; emit Deposit(msg.sender, receiver, assets, shares); } /** * @notice Modification of the standard ERC-4626 deposit implementation. * @dev No public mint allowed. */ function mint(uint256, address) public pure override returns (uint256) { revert FunctionNotImplemented(); } /** * @notice Modification of the standard ERC-4626 withdraw implementation. * @dev No public withdraw allowed. */ function withdraw(uint256, address, address) public pure override returns (uint256) { revert FunctionNotImplemented(); } /** * @notice Modification of the standard ERC-4626 withdraw implementation. * @param assets The amount of assets of the underlying ERC-20 token being paid back. * @param receiver Will always be the Lending Pool. * @param owner_ The Arcadia vault with collateral covering the loan. * @return shares The corresponding amount of debt shares redeemed. * @dev Only the Lending Pool (which inherits this contract) can issue debt. */ function _withdraw(uint256 assets, address receiver, address owner_) internal returns (uint256 shares) { // Check for rounding error since we round down in previewWithdraw. require((shares = previewWithdraw(assets)) != 0, "DT_W: ZERO_SHARES"); _burn(owner_, shares); realisedDebt -= assets; emit Withdraw(msg.sender, receiver, owner_, assets, shares); } /** * @notice Modification of the standard ERC-4626 redeem implementation. * @dev No public redeem allowed. */ function redeem(uint256, address, address) public pure override returns (uint256) { revert FunctionNotImplemented(); } /*////////////////////////////////////////////////////////////// ACCOUNTING LOGIC //////////////////////////////////////////////////////////////*/ /** * @notice Modification of the standard ERC-4626 convertToShares implementation. * @dev Since debt is a liability instead of an asset, roundUp and roundDown are inverted compared to the standard implementation. */ function convertToShares(uint256 assets) public view override returns (uint256) { uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero. return supply == 0 ? assets : assets.mulDivUp(supply, totalAssets()); } /** * @notice Modification of the standard ERC-4626 convertToShares implementation. * @dev Since debt is a liability instead of an asset, roundUp and roundDown are inverted compared to the standard implementation. */ function convertToAssets(uint256 shares) public view override returns (uint256) { uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero. return supply == 0 ? shares : shares.mulDivUp(totalAssets(), supply); } /** * @notice Modification of the standard ERC-4626 previewMint implementation. * @dev Since debt is a liability instead of an asset, roundUp and roundDown are inverted compared to the standard implementation. */ function previewMint(uint256 shares) public view override returns (uint256) { uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero. return supply == 0 ? shares : shares.mulDivDown(totalAssets(), supply); } /** * @notice Modification of the standard ERC-4626 previewWithdraw implementation. * @dev Since debt is a liability instead of an asset, roundUp and roundDown are inverted compared to the standard implementation. */ function previewWithdraw(uint256 assets) public view override returns (uint256) { uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero. return supply == 0 ? assets : assets.mulDivDown(supply, totalAssets()); } /*////////////////////////////////////////////////////////////// TRANSFER LOGIC //////////////////////////////////////////////////////////////*/ /** * @notice Modification of the standard ERC-4626 approve implementation. * @dev No public approve allowed. */ function approve(address, uint256) public pure override returns (bool) { revert FunctionNotImplemented(); } /** * @notice Modification of the standard ERC-4626 transfer implementation. * @dev No public transfer allowed. */ function transfer(address, uint256) public pure override returns (bool) { revert FunctionNotImplemented(); } /** * @notice Modification of the standard ERC-4626 transferFrom implementation. * @dev No public transferFrom allowed. */ function transferFrom(address, address, uint256) public pure override returns (bool) { revert FunctionNotImplemented(); } /** * @notice Modification of the standard ERC-4626 permit implementation. * @dev No public permit allowed. */ function permit(address, address, uint256, uint256, uint8, bytes32, bytes32) public pure override { revert FunctionNotImplemented(); } }
/** * Created by Pragma Labs * SPDX-License-Identifier: BUSL-1.1 */ pragma solidity ^0.8.13; /** * @title Interest Rate Module. * @author Pragma Labs * @notice The Logic to calculate and store the interest rate of the Lending Pool. */ contract InterestRateModule { /* ////////////////////////////////////////////////////////////// STORAGE ////////////////////////////////////////////////////////////// */ // The current interest rate, 18 decimals precision. uint256 public interestRate; // A struct with the configuration of the interest rate curves, // which give the interest rate in function of the utilisation of the Lending Pool. InterestRateConfiguration public interestRateConfig; /** * A struct with the set of interest rate configuration parameters: * - baseRatePerYear The interest rate when utilisation is 0. * - lowSlopePerYear The slope of the first curve, defined as the delta in interest rate for a delta in utilisation of 100%. * - highSlopePerYear The slope of the second curve, defined as the delta in interest rate for a delta in utilisation of 100%. * - utilisationThreshold the optimal utilisation, where we go from the flat first curve to the steeper second curve. */ struct InterestRateConfiguration { uint72 baseRatePerYear; //18 decimals precision. uint72 lowSlopePerYear; //18 decimals precision. uint72 highSlopePerYear; //18 decimals precision. uint40 utilisationThreshold; //5 decimal precision. } /* ////////////////////////////////////////////////////////////// EVENTS ////////////////////////////////////////////////////////////// */ event InterestRate(uint80 interestRate); /* ////////////////////////////////////////////////////////////// INTEREST RATE LOGIC ////////////////////////////////////////////////////////////// */ /** * @notice Sets the configuration parameters of InterestRateConfiguration struct. * @param newConfig A struct with a new set of interest rate configuration parameters: * - baseRatePerYear The interest rate when utilisation is 0, 18 decimals precision. * - lowSlopePerYear The slope of the first curve, defined as the delta in interest rate for a delta in utilisation of 100%, * 18 decimals precision. * - highSlopePerYear The slope of the second curve, defined as the delta in interest rate for a delta in utilisation of 100%, * 18 decimals precision. * - utilisationThreshold the optimal utilisation, where we go from the flat first curve to the steeper second curve, * 5 decimal precision. */ function _setInterestConfig(InterestRateConfiguration calldata newConfig) internal { interestRateConfig = newConfig; } /** * @notice Calculates the interest rate. * @param utilisation Utilisation rate, 5 decimal precision. * @return interestRate The current interest rate, 18 decimal precision. * @dev The interest rate is a function of the utilisation of the Lending Pool. * We use two linear curves: a flat one below the optimal utilisation and a steep one above. */ function _calculateInterestRate(uint256 utilisation) internal view returns (uint256) { unchecked { if (utilisation >= interestRateConfig.utilisationThreshold) { // 1e23 = uT (1e5) * ls (1e18). uint256 lowSlopeInterest = uint256(interestRateConfig.utilisationThreshold) * interestRateConfig.lowSlopePerYear; // 1e23 = (uT - u) (1e5) * hs (e18). uint256 highSlopeInterest = uint256((utilisation - interestRateConfig.utilisationThreshold)) * interestRateConfig.highSlopePerYear; // 1e18 = bs (1e18) + (lsIR (e23) + hsIR (1e23)) / 1e5. return uint256(interestRateConfig.baseRatePerYear) + ((lowSlopeInterest + highSlopeInterest) / 100_000); } else { // 1e18 = br (1e18) + (ls (1e18) * u (1e5)) / 1e5. return uint256( uint256(interestRateConfig.baseRatePerYear) + ((uint256(interestRateConfig.lowSlopePerYear) * utilisation) / 100_000) ); } } } /** * @notice Updates the interest rate. * @param totalDebt Total amount of debt. * @param totalLiquidity Total amount of Liquidity (sum of borrowed out assets and assets still available in the Lending Pool). * @dev This function is only be called by the function _updateInterestRate(uint256 realisedDebt_, uint256 totalRealisedLiquidity_), * calculates the interest rate, if the totalRealisedLiquidity_ is zero then utilisation is zero. */ function _updateInterestRate(uint256 totalDebt, uint256 totalLiquidity) internal { uint256 utilisation; // 5 decimals precision if (totalLiquidity > 0) { utilisation = (100_000 * totalDebt) / totalLiquidity; } //Calculates and stores interestRate as a uint256, emits interestRate as a uint80 (interestRate is maximally equal to uint72 + uint72). //_updateInterestRate() will be called a lot, saves a read from from storage or a write+read from memory. emit InterestRate(uint80(interestRate = _calculateInterestRate(utilisation))); } }
/** * Created by Pragma Labs * SPDX-License-Identifier: BUSL-1.1 */ pragma solidity ^0.8.13; /** * @title Trusted Creditor implementation. * @author Pragma Labs * @notice This contract contains the minimum functionality a Trusted Creditor, interacting with Arcadia Vaults, needs to implement. * @dev For the implementation of Arcadia Vaults, see: https://github.com/arcadia-finance/arcadia-vaults. */ abstract contract TrustedCreditor { /* ////////////////////////////////////////////////////////////// STORAGE ////////////////////////////////////////////////////////////// */ // Map vaultVersion => status. mapping(uint256 => bool) public isValidVersion; /* ////////////////////////////////////////////////////////////// VAULT LOGIC ////////////////////////////////////////////////////////////// */ /** * @notice Sets the validity of vault version to valid. * @param vaultVersion The version current version of the vault. * @param valid The validity of the respective vaultVersion. */ function _setVaultVersion(uint256 vaultVersion, bool valid) internal { isValidVersion[vaultVersion] = valid; } /** * @notice Checks if vault fulfills all requirements and returns application settings. * @param vaultVersion The current version of the vault. * @return success Bool indicating if all requirements are met. * @return baseCurrency The base currency of the application. * @return liquidator The liquidator of the application. * @return fixedLiquidationCost Estimated fixed costs (independent of size of debt) to liquidate a position. */ function openMarginAccount(uint256 vaultVersion) external virtual returns (bool success, address baseCurrency, address liquidator, uint256 fixedLiquidationCost); /** * @notice Returns the open position of the vault. * @param vault The vault address. * @return openPosition The open position of the vault. */ function getOpenPosition(address vault) external view virtual returns (uint256 openPosition); }
/** * Created by Pragma Labs * SPDX-License-Identifier: MIT */ pragma solidity ^0.8.13; interface IFactory { /** * @notice View function returning if an address is a vault. * @param vault The address to be checked. * @return bool Whether the address is a vault or not. */ function isVault(address vault) external view returns (bool); /** * @notice Returns the owner of a vault. * @param vault The Vault address. * @return owner The Vault owner. */ function ownerOfVault(address vault) external view returns (address); }
/** * Created by Pragma Labs * SPDX-License-Identifier: MIT */ pragma solidity ^0.8.13; import { ERC20 } from "../../lib/solmate/src/tokens/ERC20.sol"; interface ILendingPool { /** * @notice returns the supply cap of the Lending Pool. * @return supplyCap The supply cap of the Lending Pool. */ function supplyCap() external view returns (uint128); /** * @notice returns the total realised liquidity of the Lending Pool. * @return totalRealisedLiquidity The total realised liquidity of the Lending Pool. */ function totalRealisedLiquidity() external view returns (uint128); /** * @notice Deposit assets in the Lending Pool. * @param assets The amount of assets of the underlying ERC-20 token being deposited. * @param from The address of the Liquidity Provider who deposits the underlying ERC-20 token via a Tranche. */ function depositInLendingPool(uint256 assets, address from) external; /** * @notice Withdraw assets from the Lending Pool. * @param assets The amount of assets of the underlying ERC-20 tokens being withdrawn. * @param receiver The address of the receiver of the underlying ERC-20 tokens. */ function withdrawFromLendingPool(uint256 assets, address receiver) external; /** * @notice Returns the redeemable amount of liquidity in the underlying asset of an address. * @param owner The address of the liquidity provider. * @return assets The redeemable amount of liquidity in the underlying asset. */ function liquidityOf(address owner) external view returns (uint256); /** * @notice liquidityOf, but syncs the unrealised interest first. * @param owner The address of the liquidity provider. * @return assets The redeemable amount of liquidity in the underlying asset. */ function liquidityOfAndSync(address owner) external returns (uint256); /** * @notice Calculates the unrealised debt (interests). * @return unrealisedDebt The unrealised debt. */ function calcUnrealisedDebt() external view returns (uint256); }
/** * Created by Pragma Labs * SPDX-License-Identifier: MIT */ pragma solidity ^0.8.13; interface ILiquidator { /** * @notice Called by a Creditor to start an auction to liquidate collateral of a vault. * @param vault The contract address of the Vault to liquidate. * @param openDebt The open debt taken by `originalOwner`. * @param maxInitiatorFee The maximum fee that is paid to the initiator of a liquidation. */ function startAuction(address vault, uint256 openDebt, uint80 maxInitiatorFee) external; }
/** * Created by Pragma Labs * SPDX-License-Identifier: MIT */ pragma solidity ^0.8.13; interface ITranche { /** * @notice Locks the tranche in case all liquidity of the tranche is written of due to bad debt. */ function lock() external; /** * @notice Locks the tranche while an auction is in progress. * @param auctionInProgress Flag indicating if there are auctions in progress. */ function setAuctionInProgress(bool auctionInProgress) external; }
/** * Created by Pragma Labs * SPDX-License-Identifier: MIT */ pragma solidity ^0.8.13; interface IVault { /** * @notice Returns the address of the owner of the Vault. */ function owner() external view returns (address); /** * @notice Checks if the Vault is healthy and still has free margin. * @param amount The amount with which the position is increased. * @param totalOpenDebt The total open Debt against the Vault. * @return success Boolean indicating if there is sufficient margin to back a certain amount of Debt. * @return trustedCreditor_ The contract address of the trusted creditor. * @return vaultVersion_ The vault version. * @dev Only one of the values can be non-zero, or we check on a certain increase of debt, or we check on a total amount of debt. */ function isVaultHealthy(uint256 amount, uint256 totalOpenDebt) external view returns (bool, address, uint256); /** * @notice Calls external action handler to execute and interact with external logic. * @param actionHandler The address of the action handler. * @param actionData A bytes object containing two actionAssetData structs, an address array and a bytes array. * @return trustedCreditor_ The contract address of the trusted creditor. * @return vaultVersion_ The vault version. */ function vaultManagementAction(address actionHandler, bytes calldata actionData) external returns (address, uint256); }
/** * Created by Pragma Labs * SPDX-License-Identifier: BUSL-1.1 */ pragma solidity ^0.8.13; import { Owned } from "../../lib/solmate/src/auth/Owned.sol"; /** * @title Guardian * @author Pragma Labs * @notice This module provides the logic that allows authorized accounts to trigger an emergency stop. */ abstract contract Guardian is Owned { /* ////////////////////////////////////////////////////////////// STORAGE ////////////////////////////////////////////////////////////// */ // Address of the Guardian. address public guardian; // Flag indicating if the repay() function is paused. bool public repayPaused; // Flag indicating if the withdraw() function is paused. bool public withdrawPaused; // Flag indicating if the borrow() function is paused. bool public borrowPaused; // Flag indicating if the deposit() function is paused. bool public depositPaused; // Flag indicating if the liquidation() function is paused. bool public liquidationPaused; // Last timestamp an emergency stop was triggered. uint256 public pauseTimestamp; /* ////////////////////////////////////////////////////////////// EVENTS ////////////////////////////////////////////////////////////// */ event GuardianChanged(address indexed oldGuardian, address indexed newGuardian); event PauseUpdate( bool repayPauseUpdate, bool withdrawPauseUpdate, bool borrowPauseUpdate, bool supplyPauseUpdate, bool liquidationPauseUpdate ); /* ////////////////////////////////////////////////////////////// ERRORS ////////////////////////////////////////////////////////////// */ error FunctionIsPaused(); /* ////////////////////////////////////////////////////////////// MODIFIERS ////////////////////////////////////////////////////////////// */ /** * @dev Throws if called by any account other than the guardian. */ modifier onlyGuardian() { require(msg.sender == guardian, "Guardian: Only guardian"); _; } /** * @dev This modifier is used to restrict access to certain functions when the contract is paused for repay. * It throws if repay is paused. */ modifier whenRepayNotPaused() { if (repayPaused) revert FunctionIsPaused(); _; } /** * @dev This modifier is used to restrict access to certain functions when the contract is paused for withdraw. * It throws if withdraw is paused. */ modifier whenWithdrawNotPaused() { if (withdrawPaused) revert FunctionIsPaused(); _; } /** * @dev This modifier is used to restrict access to certain functions when the contract is paused for borrow. * It throws if borrow is paused. */ modifier whenBorrowNotPaused() { if (borrowPaused) revert FunctionIsPaused(); _; } /** * @dev This modifier is used to restrict access to certain functions when the contract is paused for deposit. * It throws if deposit is paused. */ modifier whenDepositNotPaused() { if (depositPaused) revert FunctionIsPaused(); _; } /** * @dev This modifier is used to restrict access to certain functions when the contract is paused for liquidation. * It throws if liquidation is paused. */ modifier whenLiquidationNotPaused() { if (liquidationPaused) revert FunctionIsPaused(); _; } /* ////////////////////////////////////////////////////////////// CONSTRUCTOR ////////////////////////////////////////////////////////////// */ constructor() Owned(msg.sender) { } /* ////////////////////////////////////////////////////////////// GUARDIAN LOGIC ////////////////////////////////////////////////////////////// */ /** * @notice This function is used to set the guardian address. * @param guardian_ The address of the new guardian. * @dev Allows onlyOwner to change the guardian address. */ function changeGuardian(address guardian_) external onlyOwner { emit GuardianChanged(guardian, guardian_); guardian = guardian_; } /* ////////////////////////////////////////////////////////////// PAUSING LOGIC ////////////////////////////////////////////////////////////// */ /** * @notice This function is used to pause all the flags of the contract. * @dev This function can be called by the guardian to pause all functionality in the event of an emergency. * This function pauses repay, withdraw, borrow, deposit and liquidation. * This function can only be called by the guardian. * The guardian can only pause the protocol again after 32 days have past since the last pause. * This is to prevent that a malicious guardian can take user-funds hostage for an indefinite time. * @dev After the guardian has paused the protocol, the owner has 30 days to find potential problems, * find a solution and unpause the protocol. If the protocol is not unpaused after 30 days, * an emergency procedure can be started by any user to unpause the protocol. * All users have now at least a two-day window to withdraw assets and close positions before * the protocol can again be paused (after 32 days). */ function pause() external onlyGuardian { require(block.timestamp > pauseTimestamp + 32 days, "G_P: Cannot pause"); repayPaused = true; withdrawPaused = true; borrowPaused = true; depositPaused = true; liquidationPaused = true; pauseTimestamp = block.timestamp; emit PauseUpdate(true, true, true, true, true); } /** * @notice This function is used to unpause one or more flags. * @param repayPaused_ false when repay functionality should be unPaused. * @param withdrawPaused_ false when withdraw functionality should be unPaused. * @param borrowPaused_ false when borrow functionality should be unPaused. * @param depositPaused_ false when deposit functionality should be unPaused. * @param liquidationPaused_ false when liquidation functionality should be unPaused. * @dev This function can unPause repay, withdraw, borrow, and deposit individually. * @dev Can only update flags from paused (true) to unPaused (false), cannot be used the other way around * (to set unPaused flags to paused). */ function unPause( bool repayPaused_, bool withdrawPaused_, bool borrowPaused_, bool depositPaused_, bool liquidationPaused_ ) external onlyOwner { repayPaused = repayPaused && repayPaused_; withdrawPaused = withdrawPaused && withdrawPaused_; borrowPaused = borrowPaused && borrowPaused_; depositPaused = depositPaused && depositPaused_; liquidationPaused = liquidationPaused && liquidationPaused_; emit PauseUpdate(repayPaused, withdrawPaused, borrowPaused, depositPaused, liquidationPaused); } /** * @notice This function is used to unPause all flags. * @dev If the protocol is not unpaused after 30 days, any user can unpause the protocol. * This ensures that no rogue owner or guardian can lock user funds for an indefinite amount of time. * All users have now at least a two-day window to withdraw assets and close positions before * the protocol can again be paused (after 32 days). */ function unPause() external { require(block.timestamp > pauseTimestamp + 30 days, "G_UP: Cannot unPause"); if (repayPaused || withdrawPaused || borrowPaused || depositPaused || liquidationPaused) { repayPaused = false; withdrawPaused = false; borrowPaused = false; depositPaused = false; liquidationPaused = false; emit PauseUpdate(false, false, false, false, false); } } }
// SPDX-License-Identifier: GPL-3.0-or-later // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. pragma solidity ^0.8.13; // solhint-disable /** * @dev Reverts if `condition` is false, with a revert reason containing `errorCode`. Only codes up to 999 are * supported. */ function _require(bool condition, uint256 errorCode) pure { if (!condition) { _revert(errorCode); } } /** * @dev Reverts with a revert reason containing `errorCode`. Only codes up to 999 are supported. */ function _revert(uint256 errorCode) pure { // We're going to dynamically create a revert string based on the error code, with the following format: // 'BAL#{errorCode}' // where the code is left-padded with zeroes to three digits (so they range from 000 to 999). // // We don't have revert strings embedded in the contract to save bytecode size: it takes much less space to store a // number (8 to 16 bits) than the individual string characters. // // The dynamic string creation algorithm that follows could be implemented in Solidity, but assembly allows for a // much denser implementation, again saving bytecode size. Given this function unconditionally reverts, this is a // safe place to rely on it without worrying about how its usage might affect e.g. memory contents. assembly { // First, we need to compute the ASCII representation of the error code. We assume that it is in the 0-999 // range, so we only need to convert three digits. To convert the digits to ASCII, we add 0x30, the value for // the '0' character. let units := add(mod(errorCode, 10), 0x30) errorCode := div(errorCode, 10) let tenths := add(mod(errorCode, 10), 0x30) errorCode := div(errorCode, 10) let hundreds := add(mod(errorCode, 10), 0x30) // With the individual characters, we can now construct the full string. The "BAL#" part is a known constant // (0x42414c23): we simply shift this by 24 (to provide space for the 3 bytes of the error code), and add the // characters to it, each shifted by a multiple of 8. // The revert reason is then shifted left by 200 bits (256 minus the length of the string, 7 characters * 8 bits // per character = 56) to locate it in the most significant part of the 256 slot (the beginning of a byte // array). let revertReason := shl(200, add(0x42414c23000000, add(add(units, shl(8, tenths)), shl(16, hundreds)))) // We can now encode the reason in memory, which can be safely overwritten as we're about to revert. The encoded // message will have the following layout: // [ revert reason identifier ] [ string location offset ] [ string length ] [ string contents ] // The Solidity revert reason identifier is 0x08c739a0, the function selector of the Error(string) function. We // also write zeroes to the next 28 bytes of memory, but those are about to be overwritten. mstore(0x0, 0x08c379a000000000000000000000000000000000000000000000000000000000) // Next is the offset to the location of the string, which will be placed immediately after (20 bytes away). mstore(0x04, 0x0000000000000000000000000000000000000000000000000000000000000020) // The string length is fixed: 7 characters. mstore(0x24, 7) // Finally, the string itself is stored. mstore(0x44, revertReason) // Even if the string is only 7 bytes long, we need to return a full 32 byte slot containing it. The length of // the encoded message is therefore 4 + 32 + 32 + 32 = 100. revert(0, 100) } } library Errors { // Math uint256 internal constant ADD_OVERFLOW = 0; uint256 internal constant SUB_OVERFLOW = 1; uint256 internal constant SUB_UNDERFLOW = 2; uint256 internal constant MUL_OVERFLOW = 3; uint256 internal constant ZERO_DIVISION = 4; uint256 internal constant DIV_INTERNAL = 5; uint256 internal constant X_OUT_OF_BOUNDS = 6; uint256 internal constant Y_OUT_OF_BOUNDS = 7; uint256 internal constant PRODUCT_OUT_OF_BOUNDS = 8; uint256 internal constant INVALID_EXPONENT = 9; // Input uint256 internal constant OUT_OF_BOUNDS = 100; uint256 internal constant UNSORTED_ARRAY = 101; uint256 internal constant UNSORTED_TOKENS = 102; uint256 internal constant INPUT_LENGTH_MISMATCH = 103; uint256 internal constant ZERO_TOKEN = 104; // Shared pools uint256 internal constant MIN_TOKENS = 200; uint256 internal constant MAX_TOKENS = 201; uint256 internal constant MAX_SWAP_FEE_PERCENTAGE = 202; uint256 internal constant MIN_SWAP_FEE_PERCENTAGE = 203; uint256 internal constant MINIMUM_BPT = 204; uint256 internal constant CALLER_NOT_VAULT = 205; uint256 internal constant UNINITIALIZED = 206; uint256 internal constant BPT_IN_MAX_AMOUNT = 207; uint256 internal constant BPT_OUT_MIN_AMOUNT = 208; uint256 internal constant EXPIRED_PERMIT = 209; // Pools uint256 internal constant MIN_AMP = 300; uint256 internal constant MAX_AMP = 301; uint256 internal constant MIN_WEIGHT = 302; uint256 internal constant MAX_STABLE_TOKENS = 303; uint256 internal constant MAX_IN_RATIO = 304; uint256 internal constant MAX_OUT_RATIO = 305; uint256 internal constant MIN_BPT_IN_FOR_TOKEN_OUT = 306; uint256 internal constant MAX_OUT_BPT_FOR_TOKEN_IN = 307; uint256 internal constant NORMALIZED_WEIGHT_INVARIANT = 308; uint256 internal constant INVALID_TOKEN = 309; uint256 internal constant UNHANDLED_JOIN_KIND = 310; uint256 internal constant ZERO_INVARIANT = 311; uint256 internal constant ORACLE_INVALID_SECONDS_QUERY = 312; uint256 internal constant ORACLE_NOT_INITIALIZED = 313; uint256 internal constant ORACLE_QUERY_TOO_OLD = 314; uint256 internal constant ORACLE_INVALID_INDEX = 315; uint256 internal constant ORACLE_BAD_SECS = 316; // Lib uint256 internal constant REENTRANCY = 400; uint256 internal constant SENDER_NOT_ALLOWED = 401; uint256 internal constant PAUSED = 402; uint256 internal constant PAUSE_WINDOW_EXPIRED = 403; uint256 internal constant MAX_PAUSE_WINDOW_DURATION = 404; uint256 internal constant MAX_BUFFER_PERIOD_DURATION = 405; uint256 internal constant INSUFFICIENT_BALANCE = 406; uint256 internal constant INSUFFICIENT_ALLOWANCE = 407; uint256 internal constant ERC20_TRANSFER_FROM_ZERO_ADDRESS = 408; uint256 internal constant ERC20_TRANSFER_TO_ZERO_ADDRESS = 409; uint256 internal constant ERC20_MINT_TO_ZERO_ADDRESS = 410; uint256 internal constant ERC20_BURN_FROM_ZERO_ADDRESS = 411; uint256 internal constant ERC20_APPROVE_FROM_ZERO_ADDRESS = 412; uint256 internal constant ERC20_APPROVE_TO_ZERO_ADDRESS = 413; uint256 internal constant ERC20_TRANSFER_EXCEEDS_ALLOWANCE = 414; uint256 internal constant ERC20_DECREASED_ALLOWANCE_BELOW_ZERO = 415; uint256 internal constant ERC20_TRANSFER_EXCEEDS_BALANCE = 416; uint256 internal constant ERC20_BURN_EXCEEDS_ALLOWANCE = 417; uint256 internal constant SAFE_ERC20_CALL_FAILED = 418; uint256 internal constant ADDRESS_INSUFFICIENT_BALANCE = 419; uint256 internal constant ADDRESS_CANNOT_SEND_VALUE = 420; uint256 internal constant SAFE_CAST_VALUE_CANT_FIT_INT256 = 421; uint256 internal constant GRANT_SENDER_NOT_ADMIN = 422; uint256 internal constant REVOKE_SENDER_NOT_ADMIN = 423; uint256 internal constant RENOUNCE_SENDER_NOT_ALLOWED = 424; uint256 internal constant BUFFER_PERIOD_EXPIRED = 425; // Vault uint256 internal constant INVALID_POOL_ID = 500; uint256 internal constant CALLER_NOT_POOL = 501; uint256 internal constant SENDER_NOT_ASSET_MANAGER = 502; uint256 internal constant USER_DOESNT_ALLOW_RELAYER = 503; uint256 internal constant INVALID_SIGNATURE = 504; uint256 internal constant EXIT_BELOW_MIN = 505; uint256 internal constant JOIN_ABOVE_MAX = 506; uint256 internal constant SWAP_LIMIT = 507; uint256 internal constant SWAP_DEADLINE = 508; uint256 internal constant CANNOT_SWAP_SAME_TOKEN = 509; uint256 internal constant UNKNOWN_AMOUNT_IN_FIRST_SWAP = 510; uint256 internal constant MALCONSTRUCTED_MULTIHOP_SWAP = 511; uint256 internal constant INTERNAL_BALANCE_OVERFLOW = 512; uint256 internal constant INSUFFICIENT_INTERNAL_BALANCE = 513; uint256 internal constant INVALID_ETH_INTERNAL_BALANCE = 514; uint256 internal constant INVALID_POST_LOAN_BALANCE = 515; uint256 internal constant INSUFFICIENT_ETH = 516; uint256 internal constant UNALLOCATED_ETH = 517; uint256 internal constant ETH_TRANSFER = 518; uint256 internal constant CANNOT_USE_ETH_SENTINEL = 519; uint256 internal constant TOKENS_MISMATCH = 520; uint256 internal constant TOKEN_NOT_REGISTERED = 521; uint256 internal constant TOKEN_ALREADY_REGISTERED = 522; uint256 internal constant TOKENS_ALREADY_SET = 523; uint256 internal constant TOKENS_LENGTH_MUST_BE_2 = 524; uint256 internal constant NONZERO_TOKEN_BALANCE = 525; uint256 internal constant BALANCE_TOTAL_OVERFLOW = 526; uint256 internal constant POOL_NO_TOKENS = 527; uint256 internal constant INSUFFICIENT_FLASH_LOAN_BALANCE = 528; // Fees uint256 internal constant SWAP_FEE_PERCENTAGE_TOO_HIGH = 600; uint256 internal constant FLASH_LOAN_FEE_PERCENTAGE_TOO_HIGH = 601; uint256 internal constant INSUFFICIENT_FLASH_LOAN_FEE_AMOUNT = 602; }
// SPDX-License-Identifier: MIT // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated // documentation files (the “Software”), to deal in the Software without restriction, including without limitation the // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to the following conditions: // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the // Software. // THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE // WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. pragma solidity ^0.8.13; import "./BalancerErrors.sol"; /* solhint-disable */ /** * @dev Exponentiation and logarithm functions for 18 decimal fixed point numbers (both base and exponent/argument). * * Exponentiation and logarithm with arbitrary bases (x^y and log_x(y)) are implemented by conversion to natural * exponentiation and logarithm (where the base is Euler's number). * * @author Fernando Martinelli - @fernandomartinelli * @author Sergio Yuhjtman - @sergioyuhjtman * @author Daniel Fernandez - @dmf7z */ library LogExpMath { // All fixed point multiplications and divisions are inlined. This means we need to divide by ONE when multiplying // two numbers, and multiply by ONE when dividing them. // All arguments and return values are 18 decimal fixed point numbers. int256 constant ONE_18 = 1e18; // Internally, intermediate values are computed with higher precision as 20 decimal fixed point numbers, and in the // case of ln36, 36 decimals. int256 constant ONE_20 = 1e20; int256 constant ONE_36 = 1e36; // The domain of natural exponentiation is bound by the word size and number of decimals used. // // Because internally the result will be stored using 20 decimals, the largest possible result is // (2^255 - 1) / 10^20, which makes the largest exponent ln((2^255 - 1) / 10^20) = 130.700829182905140221. // The smallest possible result is 10^(-18), which makes largest negative argument // ln(10^(-18)) = -41.446531673892822312. // We use 130.0 and -41.0 to have some safety margin. int256 constant MAX_NATURAL_EXPONENT = 130e18; int256 constant MIN_NATURAL_EXPONENT = -41e18; // Bounds for ln_36's argument. Both ln(0.9) and ln(1.1) can be represented with 36 decimal places in a fixed point // 256 bit integer. int256 constant LN_36_LOWER_BOUND = ONE_18 - 1e17; int256 constant LN_36_UPPER_BOUND = ONE_18 + 1e17; uint256 constant MILD_EXPONENT_BOUND = 2 ** 254 / uint256(ONE_20); // 18 decimal constants int256 constant x0 = 128_000_000_000_000_000_000; // 2ˆ7 int256 constant a0 = 38_877_084_059_945_950_922_200_000_000_000_000_000_000_000_000_000_000_000; // eˆ(x0) (no decimals) int256 constant x1 = 64_000_000_000_000_000_000; // 2ˆ6 int256 constant a1 = 6_235_149_080_811_616_882_910_000_000; // eˆ(x1) (no decimals) // 20 decimal constants int256 constant x2 = 3_200_000_000_000_000_000_000; // 2ˆ5 int256 constant a2 = 7_896_296_018_268_069_516_100_000_000_000_000; // eˆ(x2) int256 constant x3 = 1_600_000_000_000_000_000_000; // 2ˆ4 int256 constant a3 = 888_611_052_050_787_263_676_000_000; // eˆ(x3) int256 constant x4 = 800_000_000_000_000_000_000; // 2ˆ3 int256 constant a4 = 298_095_798_704_172_827_474_000; // eˆ(x4) int256 constant x5 = 400_000_000_000_000_000_000; // 2ˆ2 int256 constant a5 = 5_459_815_003_314_423_907_810; // eˆ(x5) int256 constant x6 = 200_000_000_000_000_000_000; // 2ˆ1 int256 constant a6 = 738_905_609_893_065_022_723; // eˆ(x6) int256 constant x7 = 100_000_000_000_000_000_000; // 2ˆ0 int256 constant a7 = 271_828_182_845_904_523_536; // eˆ(x7) int256 constant x8 = 50_000_000_000_000_000_000; // 2ˆ-1 int256 constant a8 = 164_872_127_070_012_814_685; // eˆ(x8) int256 constant x9 = 25_000_000_000_000_000_000; // 2ˆ-2 int256 constant a9 = 128_402_541_668_774_148_407; // eˆ(x9) int256 constant x10 = 12_500_000_000_000_000_000; // 2ˆ-3 int256 constant a10 = 113_314_845_306_682_631_683; // eˆ(x10) int256 constant x11 = 6_250_000_000_000_000_000; // 2ˆ-4 int256 constant a11 = 106_449_445_891_785_942_956; // eˆ(x11) /** * @dev Exponentiation (x^y) with unsigned 18 decimal fixed point base and exponent. * * Reverts if ln(x) * y is smaller than `MIN_NATURAL_EXPONENT`, or larger than `MAX_NATURAL_EXPONENT`. */ function pow(uint256 x, uint256 y) internal pure returns (uint256) { if (y == 0) { // We solve the 0^0 indetermination by making it equal one. return uint256(ONE_18); } if (x == 0) { return 0; } // Instead of computing x^y directly, we instead rely on the properties of logarithms and exponentiation to // arrive at that result. In particular, exp(ln(x)) = x, and ln(x^y) = y * ln(x). This means // x^y = exp(y * ln(x)). // The ln function takes a signed value, so we need to make sure x fits in the signed 256 bit range. _require(x < 2 ** 255, Errors.X_OUT_OF_BOUNDS); int256 x_int256 = int256(x); // We will compute y * ln(x) in a single step. Depending on the value of x, we can either use ln or ln_36. In // both cases, we leave the division by ONE_18 (due to fixed point multiplication) to the end. // This prevents y * ln(x) from overflowing, and at the same time guarantees y fits in the signed 256 bit range. _require(y < MILD_EXPONENT_BOUND, Errors.Y_OUT_OF_BOUNDS); int256 y_int256 = int256(y); int256 logx_times_y; if (LN_36_LOWER_BOUND < x_int256 && x_int256 < LN_36_UPPER_BOUND) { int256 ln_36_x = _ln_36(x_int256); // ln_36_x has 36 decimal places, so multiplying by y_int256 isn't as straightforward, since we can't just // bring y_int256 to 36 decimal places, as it might overflow. Instead, we perform two 18 decimal // multiplications and add the results: one with the first 18 decimals of ln_36_x, and one with the // (downscaled) last 18 decimals. logx_times_y = ((ln_36_x / ONE_18) * y_int256 + ((ln_36_x % ONE_18) * y_int256) / ONE_18); } else { logx_times_y = _ln(x_int256) * y_int256; } logx_times_y /= ONE_18; // Finally, we compute exp(y * ln(x)) to arrive at x^y _require( MIN_NATURAL_EXPONENT <= logx_times_y && logx_times_y <= MAX_NATURAL_EXPONENT, Errors.PRODUCT_OUT_OF_BOUNDS ); return uint256(exp(logx_times_y)); } /** * @dev Natural exponentiation (e^x) with signed 18 decimal fixed point exponent. * * Reverts if `x` is smaller than MIN_NATURAL_EXPONENT, or larger than `MAX_NATURAL_EXPONENT`. */ function exp(int256 x) internal pure returns (int256) { _require(x >= MIN_NATURAL_EXPONENT && x <= MAX_NATURAL_EXPONENT, Errors.INVALID_EXPONENT); if (x < 0) { // We only handle positive exponents: e^(-x) is computed as 1 / e^x. We can safely make x positive since it // fits in the signed 256 bit range (as it is larger than MIN_NATURAL_EXPONENT). // Fixed point division requires multiplying by ONE_18. return ((ONE_18 * ONE_18) / exp(-x)); } // First, we use the fact that e^(x+y) = e^x * e^y to decompose x into a sum of powers of two, which we call x_n, // where x_n == 2^(7 - n), and e^x_n = a_n has been precomputed. We choose the first x_n, x0, to equal 2^7 // because all larger powers are larger than MAX_NATURAL_EXPONENT, and therefore not present in the // decomposition. // At the end of this process we will have the product of all e^x_n = a_n that apply, and the remainder of this // decomposition, which will be lower than the smallest x_n. // exp(x) = k_0 * a_0 * k_1 * a_1 * ... + k_n * a_n * exp(remainder), where each k_n equals either 0 or 1. // We mutate x by subtracting x_n, making it the remainder of the decomposition. // The first two a_n (e^(2^7) and e^(2^6)) are too large if stored as 18 decimal numbers, and could cause // intermediate overflows. Instead we store them as plain integers, with 0 decimals. // Additionally, x0 + x1 is larger than MAX_NATURAL_EXPONENT, which means they will not both be present in the // decomposition. // For each x_n, we test if that term is present in the decomposition (if x is larger than it), and if so deduct // it and compute the accumulated product. int256 firstAN; if (x >= x0) { x -= x0; firstAN = a0; } else if (x >= x1) { x -= x1; firstAN = a1; } else { firstAN = 1; // One with no decimal places } // We now transform x into a 20 decimal fixed point number, to have enhanced precision when computing the // smaller terms. x *= 100; // `product` is the accumulated product of all a_n (except a0 and a1), which starts at 20 decimal fixed point // one. Recall that fixed point multiplication requires dividing by ONE_20. int256 product = ONE_20; if (x >= x2) { x -= x2; product = (product * a2) / ONE_20; } if (x >= x3) { x -= x3; product = (product * a3) / ONE_20; } if (x >= x4) { x -= x4; product = (product * a4) / ONE_20; } if (x >= x5) { x -= x5; product = (product * a5) / ONE_20; } if (x >= x6) { x -= x6; product = (product * a6) / ONE_20; } if (x >= x7) { x -= x7; product = (product * a7) / ONE_20; } if (x >= x8) { x -= x8; product = (product * a8) / ONE_20; } if (x >= x9) { x -= x9; product = (product * a9) / ONE_20; } // x10 and x11 are unnecessary here since we have high enough precision already. // Now we need to compute e^x, where x is small (in particular, it is smaller than x9). We use the Taylor series // expansion for e^x: 1 + x + (x^2 / 2!) + (x^3 / 3!) + ... + (x^n / n!). int256 seriesSum = ONE_20; // The initial one in the sum, with 20 decimal places. int256 term; // Each term in the sum, where the nth term is (x^n / n!). // The first term is simply x. term = x; seriesSum += term; // Each term (x^n / n!) equals the previous one times x, divided by n. Since x is a fixed point number, // multiplying by it requires dividing by ONE_20, but dividing by the non-fixed point n values does not. term = ((term * x) / ONE_20) / 2; seriesSum += term; term = ((term * x) / ONE_20) / 3; seriesSum += term; term = ((term * x) / ONE_20) / 4; seriesSum += term; term = ((term * x) / ONE_20) / 5; seriesSum += term; term = ((term * x) / ONE_20) / 6; seriesSum += term; term = ((term * x) / ONE_20) / 7; seriesSum += term; term = ((term * x) / ONE_20) / 8; seriesSum += term; term = ((term * x) / ONE_20) / 9; seriesSum += term; term = ((term * x) / ONE_20) / 10; seriesSum += term; term = ((term * x) / ONE_20) / 11; seriesSum += term; term = ((term * x) / ONE_20) / 12; seriesSum += term; // 12 Taylor terms are sufficient for 18 decimal precision. // We now have the first a_n (with no decimals), and the product of all other a_n present, and the Taylor // approximation of the exponentiation of the remainder (both with 20 decimals). All that remains is to multiply // all three (one 20 decimal fixed point multiplication, dividing by ONE_20, and one integer multiplication), // and then drop two digits to return an 18 decimal value. return (((product * seriesSum) / ONE_20) * firstAN) / 100; } /** * @dev Internal natural logarithm (ln(a)) with signed 18 decimal fixed point argument. */ function _ln(int256 a) private pure returns (int256) { if (a < ONE_18) { // Since ln(a^k) = k * ln(a), we can compute ln(a) as ln(a) = ln((1/a)^(-1)) = - ln((1/a)). If a is less // than one, 1/a will be greater than one, and this if statement will not be entered in the recursive call. // Fixed point division requires multiplying by ONE_18. return (-_ln((ONE_18 * ONE_18) / a)); } // First, we use the fact that ln^(a * b) = ln(a) + ln(b) to decompose ln(a) into a sum of powers of two, which // we call x_n, where x_n == 2^(7 - n), which are the natural logarithm of precomputed quantities a_n (that is, // ln(a_n) = x_n). We choose the first x_n, x0, to equal 2^7 because the exponential of all larger powers cannot // be represented as 18 fixed point decimal numbers in 256 bits, and are therefore larger than a. // At the end of this process we will have the sum of all x_n = ln(a_n) that apply, and the remainder of this // decomposition, which will be lower than the smallest a_n. // ln(a) = k_0 * x_0 + k_1 * x_1 + ... + k_n * x_n + ln(remainder), where each k_n equals either 0 or 1. // We mutate a by subtracting a_n, making it the remainder of the decomposition. // For reasons related to how `exp` works, the first two a_n (e^(2^7) and e^(2^6)) are not stored as fixed point // numbers with 18 decimals, but instead as plain integers with 0 decimals, so we need to multiply them by // ONE_18 to convert them to fixed point. // For each a_n, we test if that term is present in the decomposition (if a is larger than it), and if so divide // by it and compute the accumulated sum. int256 sum = 0; if (a >= a0 * ONE_18) { a /= a0; // Integer, not fixed point division sum += x0; } if (a >= a1 * ONE_18) { a /= a1; // Integer, not fixed point division sum += x1; } // All other a_n and x_n are stored as 20 digit fixed point numbers, so we convert the sum and a to this format. sum *= 100; a *= 100; // Because further a_n are 20 digit fixed point numbers, we multiply by ONE_20 when dividing by them. if (a >= a2) { a = (a * ONE_20) / a2; sum += x2; } if (a >= a3) { a = (a * ONE_20) / a3; sum += x3; } if (a >= a4) { a = (a * ONE_20) / a4; sum += x4; } if (a >= a5) { a = (a * ONE_20) / a5; sum += x5; } if (a >= a6) { a = (a * ONE_20) / a6; sum += x6; } if (a >= a7) { a = (a * ONE_20) / a7; sum += x7; } if (a >= a8) { a = (a * ONE_20) / a8; sum += x8; } if (a >= a9) { a = (a * ONE_20) / a9; sum += x9; } if (a >= a10) { a = (a * ONE_20) / a10; sum += x10; } if (a >= a11) { a = (a * ONE_20) / a11; sum += x11; } // a is now a small number (smaller than a_11, which roughly equals 1.06). This means we can use a Taylor series // that converges rapidly for values of `a` close to one - the same one used in ln_36. // Let z = (a - 1) / (a + 1). // ln(a) = 2 * (z + z^3 / 3 + z^5 / 5 + z^7 / 7 + ... + z^(2 * n + 1) / (2 * n + 1)) // Recall that 20 digit fixed point division requires multiplying by ONE_20, and multiplication requires // division by ONE_20. int256 z = ((a - ONE_20) * ONE_20) / (a + ONE_20); int256 z_squared = (z * z) / ONE_20; // num is the numerator of the series: the z^(2 * n + 1) term int256 num = z; // seriesSum holds the accumulated sum of each term in the series, starting with the initial z int256 seriesSum = num; // In each step, the numerator is multiplied by z^2 num = (num * z_squared) / ONE_20; seriesSum += num / 3; num = (num * z_squared) / ONE_20; seriesSum += num / 5; num = (num * z_squared) / ONE_20; seriesSum += num / 7; num = (num * z_squared) / ONE_20; seriesSum += num / 9; num = (num * z_squared) / ONE_20; seriesSum += num / 11; // 6 Taylor terms are sufficient for 36 decimal precision. // Finally, we multiply by 2 (non fixed point) to compute ln(remainder) seriesSum *= 2; // We now have the sum of all x_n present, and the Taylor approximation of the logarithm of the remainder (both // with 20 decimals). All that remains is to sum these two, and then drop two digits to return a 18 decimal // value. return (sum + seriesSum) / 100; } /** * @dev Intrnal high precision (36 decimal places) natural logarithm (ln(x)) with signed 18 decimal fixed point argument, * for x close to one. * * Should only be used if x is between LN_36_LOWER_BOUND and LN_36_UPPER_BOUND. */ function _ln_36(int256 x) private pure returns (int256) { // Since ln(1) = 0, a value of x close to one will yield a very small result, which makes using 36 digits // worthwhile. // First, we transform x to a 36 digit fixed point value. x *= ONE_18; // We will use the following Taylor expansion, which converges very rapidly. Let z = (x - 1) / (x + 1). // ln(x) = 2 * (z + z^3 / 3 + z^5 / 5 + z^7 / 7 + ... + z^(2 * n + 1) / (2 * n + 1)) // Recall that 36 digit fixed point division requires multiplying by ONE_36, and multiplication requires // division by ONE_36. int256 z = ((x - ONE_36) * ONE_36) / (x + ONE_36); int256 z_squared = (z * z) / ONE_36; // num is the numerator of the series: the z^(2 * n + 1) term int256 num = z; // seriesSum holds the accumulated sum of each term in the series, starting with the initial z int256 seriesSum = num; // In each step, the numerator is multiplied by z^2 num = (num * z_squared) / ONE_36; seriesSum += num / 3; num = (num * z_squared) / ONE_36; seriesSum += num / 5; num = (num * z_squared) / ONE_36; seriesSum += num / 7; num = (num * z_squared) / ONE_36; seriesSum += num / 9; num = (num * z_squared) / ONE_36; seriesSum += num / 11; num = (num * z_squared) / ONE_36; seriesSum += num / 13; num = (num * z_squared) / ONE_36; seriesSum += num / 15; // 8 Taylor terms are sufficient for 36 decimal precision. // All that remains is multiplying by 2 (non fixed point). return seriesSum * 2; } }
{ "remappings": [ "arcadia-lending/=lib/arcadia-lending/", "ds-test/=lib/ds-test/src/", "forge-std/=lib/forge-std/src/", "solmate/=lib/solmate/src/", "v2-periphery/=lib/v2-periphery/contracts/" ], "optimizer": { "enabled": true, "runs": 200 }, "metadata": { "bytecodeHash": "ipfs" }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "london", "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"contract ERC20","name":"asset_","type":"address"},{"internalType":"address","name":"treasury_","type":"address"},{"internalType":"address","name":"vaultFactory_","type":"address"},{"internalType":"address","name":"liquidator_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"FunctionIsPaused","type":"error"},{"inputs":[],"name":"FunctionNotImplemented","type":"error"},{"inputs":[],"name":"supplyCapExceeded","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"vault","type":"address"},{"indexed":true,"internalType":"address","name":"by","type":"address"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"},{"indexed":true,"internalType":"bytes3","name":"referrer","type":"bytes3"}],"name":"Borrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint128","name":"borrowCap","type":"uint128"}],"name":"BorrowCapSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"vault","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"beneficiary","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"CreditApproval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint96","name":"fixedLiquidationCost","type":"uint96"}],"name":"FixedLiquidationCostSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldGuardian","type":"address"},{"indexed":true,"internalType":"address","name":"newGuardian","type":"address"}],"name":"GuardianChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint80","name":"interestRate","type":"uint80"}],"name":"InterestRate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"index","type":"uint256"},{"indexed":false,"internalType":"uint16","name":"weight","type":"uint16"}],"name":"InterestWeightSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"index","type":"uint256"},{"indexed":false,"internalType":"uint16","name":"weight","type":"uint16"}],"name":"LiquidationWeightSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint80","name":"maxInitiatorFee","type":"uint80"}],"name":"MaxInitiatorFeeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"originationFee","type":"uint8"}],"name":"OriginationFeeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"repayPauseUpdate","type":"bool"},{"indexed":false,"internalType":"bool","name":"withdrawPauseUpdate","type":"bool"},{"indexed":false,"internalType":"bool","name":"borrowPauseUpdate","type":"bool"},{"indexed":false,"internalType":"bool","name":"supplyPauseUpdate","type":"bool"},{"indexed":false,"internalType":"bool","name":"liquidationPauseUpdate","type":"bool"}],"name":"PauseUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"vault","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Repay","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint128","name":"supplyCap","type":"uint128"}],"name":"SupplyCapSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"tranche","type":"address"},{"indexed":true,"internalType":"uint8","name":"index","type":"uint8"},{"indexed":false,"internalType":"uint16","name":"interestWeight","type":"uint16"},{"indexed":false,"internalType":"uint16","name":"liquidationWeight","type":"uint16"}],"name":"TrancheAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"tranche","type":"address"}],"name":"TranchePopped","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":"amount","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"weight","type":"uint16"}],"name":"TreasuryInterestWeightSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"weight","type":"uint16"}],"name":"TreasuryLiquidationWeightSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"vaultVersion","type":"uint256"},{"indexed":false,"internalType":"bool","name":"valid","type":"bool"}],"name":"VaultVersionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"YEARLY_SECONDS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tranche","type":"address"},{"internalType":"uint16","name":"interestWeight_","type":"uint16"},{"internalType":"uint16","name":"liquidationWeight","type":"uint16"}],"name":"addTranche","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"beneficiary","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"vault","type":"address"}],"name":"approveBeneficiary","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"asset","outputs":[{"internalType":"contract ERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"auctionsInProgress","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"vault","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bytes3","name":"referrer","type":"bytes3"}],"name":"borrow","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"borrowCap","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"borrowPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"calcUnrealisedDebt","outputs":[{"internalType":"uint256","name":"unrealisedDebt","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"guardian_","type":"address"}],"name":"changeGuardian","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"convertToAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"convertToShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"creditAllowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"from","type":"address"}],"name":"depositInLendingPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"depositPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountBorrowed","type":"uint256"},{"internalType":"address","name":"vault","type":"address"},{"internalType":"address","name":"actionHandler","type":"address"},{"internalType":"bytes","name":"actionData","type":"bytes"},{"internalType":"bytes3","name":"referrer","type":"bytes3"}],"name":"doActionWithLeverage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"trancheIndex","type":"uint256"},{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"donateToTranche","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"fixedLiquidationCost","outputs":[{"internalType":"uint96","name":"","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"vault","type":"address"}],"name":"getOpenPosition","outputs":[{"internalType":"uint256","name":"openPosition","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"guardian","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"interestRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"interestRateConfig","outputs":[{"internalType":"uint72","name":"baseRatePerYear","type":"uint72"},{"internalType":"uint72","name":"lowSlopePerYear","type":"uint72"},{"internalType":"uint72","name":"highSlopePerYear","type":"uint72"},{"internalType":"uint40","name":"utilisationThreshold","type":"uint40"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"interestWeight","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"interestWeightTranches","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"interestWeightTreasury","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isTranche","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"isValidVersion","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastSyncedTimestamp","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"vault","type":"address"}],"name":"liquidateVault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"liquidationInitiator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"liquidationPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"liquidationWeightTranches","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"liquidationWeightTreasury","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"liquidator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner_","type":"address"}],"name":"liquidityOf","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner_","type":"address"}],"name":"liquidityOfAndSync","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"maxDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxInitiatorFee","outputs":[{"internalType":"uint80","name":"","type":"uint80"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"maxMint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"maxRedeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"maxWithdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"mint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"vaultVersion","type":"uint256"}],"name":"openMarginAccount","outputs":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"address","name":"baseCurrency","type":"address"},{"internalType":"address","name":"liquidator_","type":"address"},{"internalType":"uint256","name":"fixedLiquidationCost_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"originationFee","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"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":"pauseTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint8","name":"","type":"uint8"},{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"previewDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"previewMint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"previewRedeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"previewWithdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"realisedDebt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"realisedLiquidityOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"redeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"vault","type":"address"}],"name":"repay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"repayPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint128","name":"borrowCap_","type":"uint128"}],"name":"setBorrowCap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint96","name":"fixedLiquidationCost_","type":"uint96"}],"name":"setFixedLiquidationCost","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint72","name":"baseRatePerYear","type":"uint72"},{"internalType":"uint72","name":"lowSlopePerYear","type":"uint72"},{"internalType":"uint72","name":"highSlopePerYear","type":"uint72"},{"internalType":"uint40","name":"utilisationThreshold","type":"uint40"}],"internalType":"struct InterestRateModule.InterestRateConfiguration","name":"newConfig","type":"tuple"}],"name":"setInterestConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint16","name":"weight","type":"uint16"}],"name":"setInterestWeight","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint16","name":"weight","type":"uint16"}],"name":"setLiquidationWeight","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint80","name":"maxInitiatorFee_","type":"uint80"}],"name":"setMaxInitiatorFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"originationFee_","type":"uint8"}],"name":"setOriginationFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint128","name":"supplyCap_","type":"uint128"}],"name":"setSupplyCap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"treasury_","type":"address"}],"name":"setTreasury","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"interestWeightTreasury_","type":"uint16"}],"name":"setTreasuryInterestWeight","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"liquidationWeightTreasury_","type":"uint16"}],"name":"setTreasuryLiquidationWeight","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"vaultVersion","type":"uint256"},{"internalType":"bool","name":"valid","type":"bool"}],"name":"setVaultVersion","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"vault","type":"address"},{"internalType":"address","name":"originalOwner","type":"address"},{"internalType":"uint256","name":"badDebt","type":"uint256"},{"internalType":"uint256","name":"liquidationInitiatorReward","type":"uint256"},{"internalType":"uint256","name":"liquidationFee","type":"uint256"},{"internalType":"uint256","name":"remainder","type":"uint256"}],"name":"settleLiquidation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"skim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"supplyCap","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalAssets","outputs":[{"internalType":"uint256","name":"totalDebt","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalInterestWeight","outputs":[{"internalType":"uint24","name":"","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalLiquidationWeight","outputs":[{"internalType":"uint24","name":"","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalRealisedLiquidity","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"tranches","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"treasury","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"repayPaused_","type":"bool"},{"internalType":"bool","name":"withdrawPaused_","type":"bool"},{"internalType":"bool","name":"borrowPaused_","type":"bool"},{"internalType":"bool","name":"depositPaused_","type":"bool"},{"internalType":"bool","name":"liquidationPaused_","type":"bool"}],"name":"unPause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unPause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"updateInterestRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"vaultFactory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"withdrawFromLendingPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
6101406040523480156200001257600080fd5b506040516200675a3803806200675a83398101604081905262000035916200032d565b8380816001600160a01b03166306fdde036040518163ffffffff1660e01b8152600401600060405180830381865afa15801562000076573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052620000a09190810190620003d1565b604051602001620000b2919062000489565b604051602081830303815290604052826001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa15801562000100573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526200012a9190810190620003d1565b6040516020016200013c9190620004ca565b6040516020818303038152906040528181846001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200018c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001b29190620004f8565b600080546001600160a01b031916339081178255604051909182917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a3506004620002018482620005b3565b506005620002108382620005b3565b5060ff81166080524660a0526200022662000278565b60c0525050506001600160a01b0392831660e0525050601080549582166c01000000000000000000000000026001600160601b03909616959095179094555090821661010052166101205250620006fd565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6004604051620002ac91906200067f565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b6001600160a01b03811681146200032a57600080fd5b50565b600080600080608085870312156200034457600080fd5b8451620003518162000314565b6020860151909450620003648162000314565b6040860151909350620003778162000314565b60608601519092506200038a8162000314565b939692955090935050565b634e487b7160e01b600052604160045260246000fd5b60005b83811015620003c8578181015183820152602001620003ae565b50506000910152565b600060208284031215620003e457600080fd5b81516001600160401b0380821115620003fc57600080fd5b818401915084601f8301126200041157600080fd5b81518181111562000426576200042662000395565b604051601f8201601f19908116603f0116810190838211818310171562000451576200045162000395565b816040528281528760208487010111156200046b57600080fd5b6200047e836020830160208801620003ab565b979650505050505050565b67020b931b0b234b0960c51b815260008251620004ae816008850160208701620003ab565b64081119589d60da1b6008939091019283015250600d01919050565b636461726360e01b815260008251620004eb816004850160208701620003ab565b9190910160040192915050565b6000602082840312156200050b57600080fd5b815160ff811681146200051d57600080fd5b9392505050565b600181811c908216806200053957607f821691505b6020821081036200055a57634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620005ae57600081815260208120601f850160051c81016020861015620005895750805b601f850160051c820191505b81811015620005aa5782815560010162000595565b5050505b505050565b81516001600160401b03811115620005cf57620005cf62000395565b620005e781620005e0845462000524565b8462000560565b602080601f8311600181146200061f5760008415620006065750858301515b600019600386901b1c1916600185901b178555620005aa565b600085815260208120601f198616915b8281101562000650578886015182559484019460019091019084016200062f565b50858210156200066f5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60008083546200068f8162000524565b60018281168015620006aa5760018114620006c057620006f1565b60ff1984168752821515830287019450620006f1565b8760005260208060002060005b85811015620006e85781548a820152908401908201620006cd565b50505082870194505b50929695505050505050565b60805160a05160c05160e0516101005161012051615fa4620007b66000396000818161088c015281816110a9015281816114430152612b66015260008181610d82015281816121af0152818161277f0152612c920152600081816108130152818161169a01528181611c8601528181611e8d015281816120c70152818161239f01528181612a5c01528181612b43015261326d01526000611a9e01526000611a6e0152600081816107970152611fe40152615fa46000f3fe608060405234801561001057600080fd5b50600436106105665760003560e01c80638456cb59116102ca578063b78891571161018d578063ce96cb77116100f4578063e11a0b83116100ad578063f0f4426011610087578063f0f4426014610e26578063f2fde38b14610e39578063f7b188a514610e4c578063f89d36a514610e5457600080fd5b8063e11a0b8314610df8578063e2dd93a214610e00578063ef8b30f714610e1357600080fd5b8063ce96cb7714610d43578063d505accf14610d56578063d53dc73914610d69578063d8a06f7314610d7d578063d905777e14610da4578063dd62ed3e14610dcd57600080fd5b8063bfcc565711610146578063bfcc565714610cef578063c11002df14610d02578063c63d75b614610872578063c6e6f59214610d15578063cd387b9814610d28578063ce76756f14610d3b57600080fd5b8063b788915714610c6d578063b8bb5c4214610c82578063ba08765214610c3c578063baf5dc4414610c97578063bc861ab714610cc8578063bcb4bbea14610cdb57600080fd5b806395d89b4111610231578063acb70815116101ea578063acb7081514610be4578063ad84f34114610bf7578063b17935f514610c00578063b3d7f6b914610c29578063b460af9414610c3c578063b73c02ff14610c4a57600080fd5b806395d89b4114610b735780639790576a14610b7b578063980a3f7714610b9e5780639bf4964c14610bb15780639f4020d914610bd1578063a9059cbb146105e757600080fd5b80638da5cb5b116102835780638da5cb5b14610af55780638e33f5ee14610b085780638f69a5c514610b3a5780638f770ad014610b4d5780639086c3a114610b6057806394bf804d146109d857600080fd5b80638456cb5914610a555780638618d38d14610a5d5780638710e70c14610a77578063894bacc914610a8a5780638994685f14610a9d5780638c48052314610ab057600080fd5b806336a36ea41161042d5780634e1255f31161039457806362c9b0f01161034d57806372b5e9231161032757806372b5e92314610a065780637bfbb80214610a195780637c3a00fd14610a2c5780637ecebe0014610a3557600080fd5b806362c9b0f0146109c55780636e553f65146109d857806370a08231146109e657600080fd5b80634e1255f314610937578063542b5fd31461094a5780635b6a14951461095f5780635ef904071461098a57806361d027b3146109a0578063626d6f5e146109ba57600080fd5b80634046ebae116103e65780634046ebae1461088757806340573f6e146108ae57806344d9dca6146108d3578063452a9320146108fe5780634cdad506146109115780634da1f9a81461092457600080fd5b806336a36ea4146107d357806338bfd64d146107f957806338d52e0f1461080e5780633c4750df146108355780633f7ee87314610848578063402d267d1461087257600080fd5b80631bd43293116104d15780632db6c63a1161048a5780632db6c63a146107385780632f3ffb9f146107585780632fcb4f041461076c578063306caf961461077f578063313ce567146107925780633644e515146107cb57600080fd5b80631bd43293146106bd5780631dd19cb4146106d05780631e865815146106d85780631e9dbce6146106eb57806323b872dd146106ff57806326c259621461070d57600080fd5b80630a28a477116105235780630a28a477146105fa578063165bf8c51461060d57806318160ddd14610620578063182bfd20146106295780631919e78b1461063c578063194d7494146106aa57600080fd5b806301e1d1141461056b57806302befd241461058657806302d37a2f146105aa57806306fdde03146105bf57806307a2d13a146105d4578063095ea7b3146105e7575b600080fd5b610573610e5d565b6040519081526020015b60405180910390f35b60015461059a90600160b81b900460ff1681565b604051901515815260200161057d565b6105bd6105b83660046153d1565b610e94565b005b6105c7610f2d565b60405161057d91906153fa565b6105736105e2366004615448565b610fbb565b61059a6105f5366004615476565b610fe8565b610573610608366004615448565b611003565b6105bd61061b3660046154b0565b611023565b61057360065481565b6105bd6106373660046154e0565b6110a7565b600d54610673906001600160481b0380821691600160481b8104821691600160901b82041690600160d81b900464ffffffffff1684565b604080516001600160481b0395861681529385166020850152919093169082015264ffffffffff909116606082015260800161057d565b6105bd6106b8366004615539565b61135a565b6105bd6106cb366004615556565b611596565b6105bd61160e565b6105bd6106e6366004615590565b61179d565b60015461059a90600160a01b900460ff1681565b61059a6105f53660046155ab565b61072061071b366004615448565b611817565b6040516001600160a01b03909116815260200161057d565b610573610746366004615539565b60166020526000908152604090205481565b60015461059a90600160a81b900460ff1681565b6105bd61077a366004615539565b611841565b6105bd61078d3660046155ec565b6118c7565b6107b97f000000000000000000000000000000000000000000000000000000000000000081565b60405160ff909116815260200161057d565b610573611a6a565b6107e66107e1366004615448565b611ac0565b60405161ffff909116815260200161057d565b600e546107e690600160681b900461ffff1681565b6107207f000000000000000000000000000000000000000000000000000000000000000081565b610573610843366004615539565b611af8565b600e5461085e90600160281b900462ffffff1681565b60405162ffffff909116815260200161057d565b610573610880366004615539565b5060001990565b6107207f000000000000000000000000000000000000000000000000000000000000000081565b600e546108be9063ffffffff1681565b60405163ffffffff909116815260200161057d565b600b546108e6906001600160801b031681565b6040516001600160801b03909116815260200161057d565b600154610720906001600160a01b031681565b61057361091f366004615448565b611b8d565b6105bd61093236600461565d565b611b9e565b6105bd610945366004615682565b611d14565b6010546107e690600160501b900461ffff1681565b601054610972906001600160501b031681565b6040516001600160501b03909116815260200161057d565b600e5461085e90600160501b900462ffffff1681565b60105461072090600160601b90046001600160a01b031681565b6105736301e1338081565b6105bd6109d336600461565d565b611d8f565b6105736105f536600461565d565b6105736109f4366004615539565b60076020526000908152604090205481565b6105bd610a143660046156ab565b611ee4565b6105bd610a273660046156e5565b61215a565b610573600c5481565b610573610a43366004615539565b60096020526000908152604090205481565b6105bd612536565b600e546108e690600160781b90046001600160801b031681565b6105bd610a853660046157a8565b612654565b610573610a98366004615539565b612720565b6105bd610aab3660046157c3565b61272a565b610ac3610abe366004615448565b612b1b565b60405161057d949392919093151584526001600160a01b03928316602085015291166040830152606082015260800190565b600054610720906001600160a01b031681565b600f54610b2290600160801b90046001600160601b031681565b6040516001600160601b03909116815260200161057d565b6105bd610b483660046157a8565b612b9e565b600f546108e6906001600160801b031681565b6105bd610b6e366004615814565b612c71565b6105c7612db8565b61059a610b89366004615539565b60146020526000908152604090205460ff1681565b6105bd610bac366004615856565b612dc5565b610573610bbf366004615539565b60156020526000908152604090205481565b6105bd610bdf36600461589b565b613050565b6105bd610bf236600461565d565b61320d565b61057360025481565b610720610c0e366004615539565b6017602052600090815260409020546001600160a01b031681565b610573610c37366004615448565b613303565b6105736105f53660046158c7565b61059a610c58366004615448565b60036020526000908152604090205460ff1681565b600e546107e690600160401b900461ffff1681565b600e546107b990640100000000900460ff1681565b610573610ca53660046158fe565b601860209081526000938452604080852082529284528284209052825290205481565b6105bd610cd636600461592e565b613322565b60015461059a90600160b01b900460ff1681565b6105bd610cfd36600461589b565b613355565b610573610d10366004615539565b6134d1565b610573610d23366004615448565b6134dc565b6107e6610d36366004615448565b6134fc565b6105bd61350c565b610573610d51366004615539565b613534565b6105bd610d64366004615946565b613556565b60015461059a90600160c01b900460ff1681565b6107207f000000000000000000000000000000000000000000000000000000000000000081565b610573610db2366004615539565b6001600160a01b031660009081526007602052604090205490565b610573610ddb3660046159b4565b600860209081526000928352604080842090915290825290205481565b61057361356f565b6105bd610e0e366004615556565b6135d1565b610573610e21366004615448565b613649565b6105bd610e34366004615539565b613654565b6105bd610e47366004615539565b6136a6565b6105bd61371b565b610573600a5481565b600e546000904263ffffffff908116911614610e8d57610e7b61356f565b600a54610e8891906159f8565b905090565b50600a5490565b6000546001600160a01b03163314610ec75760405162461bcd60e51b8152600401610ebe90615a0b565b60405180910390fd5b600f80546bffffffffffffffffffffffff60801b1916600160801b6001600160601b038416908102919091179091556040519081527fce76ed33b01ab134c41431ef53932d4130aaf7a443840d0630b94a7474fe19dc906020015b60405180910390a150565b60048054610f3a90615a31565b80601f0160208091040260200160405190810160405280929190818152602001828054610f6690615a31565b8015610fb35780601f10610f8857610100808354040283529160200191610fb3565b820191906000526020600020905b815481529060010190602001808311610f9657829003601f168201915b505050505081565b6006546000908015610fdf57610fda610fd2610e5d565b849083613832565b610fe1565b825b9392505050565b600060405163ced4f63360e01b815260040160405180910390fd5b6006546000908015610fdf57610fda8161101b610e5d565b859190613858565b6000546001600160a01b0316331461104d5760405162461bcd60e51b8152600401610ebe90615a0b565b6000828152600360205260409020805460ff1916821515179055817f6bd62b850d20e8a0251cb2759fd0ebad03703967c804dabab97f9238a0e40e258260405161109b911515815260200190565b60405180910390a25050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031633146111155760405162461bcd60e51b815260206004820152601360248201527226281d1027b7363c903634b8bab4b230ba37b960691b6044820152606401610ebe565b61111d613876565b6001600160a01b0380871660009081526017602090815260408083205490931682526016905290812080548592906111569084906159f8565b909155505083156111c857600e54611194908590611185908690600160781b90046001600160801b03166159f8565b61118f9190615a65565b6138bb565b600e600f6101000a8154816001600160801b0302191690836001600160801b031602179055506111c3846138d1565b61126a565b6111d182613a5d565b600e5461120b90829084906111f7908790600160781b90046001600160801b03166159f8565b61120191906159f8565b61118f91906159f8565b600e80546001600160801b0392909216600160781b02600160781b600160f81b0319909216919091179055801561126a576001600160a01b038516600090815260166020526040812080548392906112649084906159f8565b90915550505b6010805461ffff60501b198116600160501b9182900461ffff908116600019018116830291909117928390559104161580156112a7575060135415155b1561133257601380546112bc90600190615a65565b815481106112cc576112cc615a78565b6000918252602082200154604051633dd217f760e21b815260048101929092526001600160a01b03169063f7485fdc90602401600060405180830381600087803b15801561131957600080fd5b505af115801561132d573d6000803e3d6000fd5b505050505b600a54600e546113529190600160781b90046001600160801b0316613b49565b505050505050565b600154600160c01b900460ff16156113855760405163bbc5234f60e01b815260040160405180910390fd5b61138d613876565b600061139882613534565b9050806000036113ea5760405162461bcd60e51b815260206004820152601c60248201527f4c505f4c563a204e6f742061205661756c7420776974682064656274000000006044820152606401610ebe565b6001600160a01b038281166000818152601760205260409081902080546001600160a01b0319163317905560105490516378d6c03f60e01b81526004810192909252602482018490526001600160501b031660448201527f0000000000000000000000000000000000000000000000000000000000000000909116906378d6c03f90606401600060405180830381600087803b15801561148957600080fd5b505af115801561149d573d6000803e3d6000fd5b5050601054600160501b900461ffff166000039150611540905057601380546114c890600190615a65565b815481106114d8576114d8615a78565b600091825260209091200154604051633dd217f760e21b8152600160048201526001600160a01b039091169063f7485fdc90602401600060405180830381600087803b15801561152757600080fd5b505af115801561153b573d6000803e3d6000fd5b505050505b60108054600161ffff600160501b808404821692909201160261ffff60501b19909116179055611571818380613bbb565b5050600a54600e546115939190600160781b90046001600160801b0316613b49565b50565b6000546001600160a01b031633146115c05760405162461bcd60e51b8152600401610ebe90615a0b565b600b80546001600160801b0319166001600160801b0383169081179091556040519081527ff60cdb66d1290884d4b7cdeee8f7b4d52f8b62b9ff1d89ffc4678d00bc1e3a1490602001610f22565b611616613876565b601054600160501b900461ffff161561166a5760405162461bcd60e51b81526020600482015260166024820152754c505f533a2041756374696f6e73204f6e676f696e6760501b6044820152606401610ebe565b600e54600a546040516370a0823160e01b8152306004820152600092600160781b90046001600160801b031691907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa1580156116e9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061170d9190615a8e565b61171791906159f8565b6117219190615a65565b905061172c816138bb565b600e80546001600160801b03600160781b808304821690940181168402600160781b600160f81b03199092169190911782556010546001600160a01b03600160601b9091041660009081526016602052604090208054909401909355600a54905461179b939192900416613b49565b565b6000546001600160a01b031633146117c75760405162461bcd60e51b8152600401610ebe90615a0b565b600e805464ff00000000191664010000000060ff8416908102919091179091556040519081527f62815047fdec5b7ea69997c870fa83e53a213d8d485f2489b58c049eb76cfd1490602001610f22565b6013818154811061182757600080fd5b6000918252602090912001546001600160a01b0316905081565b6000546001600160a01b0316331461186b5760405162461bcd60e51b8152600401610ebe90615a0b565b6001546040516001600160a01b038084169216907fa14fc14d8620a708a896fd11392a235647d99385500a295f0d7da2a258b2e96790600090a3600180546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b031633146118f15760405162461bcd60e51b8152600401610ebe90615a0b565b600154600160a01b900460ff1680156119075750845b60018054911515600160a01b0260ff60a01b199092169190911790819055600160a81b900460ff1680156119385750835b60018054911515600160a81b0260ff60a81b199092169190911790819055600160b01b900460ff1680156119695750825b60018054911515600160b01b0260ff60b01b199092169190911790819055600160b81b900460ff16801561199a5750815b60018054911515600160b81b0260ff60b81b199092169190911790819055600160c01b900460ff1680156119cb5750805b6001805460ff60c01b1916600160c01b921515830217908190556040805160ff600160a01b8404811615158252600160a81b8404811615156020830152600160b01b84048116151592820192909252600160b81b83048216151560608201529290910416151560808201527f8502e0dfa7512c68fe07e3fd09dba9a9545c1e68fb13e18348da704c2fa7275e9060a00160405180910390a15050505050565b60007f00000000000000000000000000000000000000000000000000000000000000004614611a9b57610e88613c7f565b507f000000000000000000000000000000000000000000000000000000000000000090565b60118181548110611ad057600080fd5b9060005260206000209060109182820401919006600202915054906101000a900461ffff1681565b600e546000904263ffffffff908116911614611b6d576001600160a01b038216600090815260156020526040812054600e54611b4a9190600160281b900462ffffff16611b4361356f565b9190613832565b6001600160a01b038416600090815260166020526040902054019150611b889050565b506001600160a01b0381166000908152601660205260409020545b919050565b6000611b9882610fbb565b92915050565b600154600160b81b900460ff1615611bc95760405163bbc5234f60e01b815260040160405180910390fd5b3360009081526014602052604090205460ff16611c1b5760405162461bcd60e51b815260206004820152601060248201526f4c503a204f6e6c79207472616e63686560801b6044820152606401610ebe565b611c23613876565b600f546001600160801b031615611c7957600f54600e546001600160801b0391821691611c5a918591600160781b909104166159f8565b1115611c7957604051638fd0b1ed60e01b815260040160405180910390fd5b611cae6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016823085613d19565b336000908152601660205260409020805483019055611ccc826138bb565b600e80546001600160801b03600160781b808304821690940181168402600160781b600160f81b03199092169190911791829055600a54611d109390920416613b49565b5050565b6000546001600160a01b03163314611d3e5760405162461bcd60e51b8152600401610ebe90615a0b565b6010805469ffffffffffffffffffff19166001600160501b0383169081179091556040519081527fb459d4513fe6c441f14d1f873f0ac9e675919afdb60c6d63f158dd00fc294ecf90602001610f22565b600154600160a81b900460ff1615611dba5760405163bbc5234f60e01b815260040160405180910390fd5b611dc2613876565b33600090815260166020526040902054821115611e215760405162461bcd60e51b815260206004820152601f60248201527f4c505f57464c503a20416d6f756e7420657863656564732062616c616e6365006044820152606401610ebe565b33600090815260166020526040902080548390039055611e40826138bb565b600e8054600f90611e62908490600160781b90046001600160801b0316615aa7565b92506101000a8154816001600160801b0302191690836001600160801b03160217905550611ec481837f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316613da39092919063ffffffff16565b600a54600e54611d109190600160781b90046001600160801b0316613b49565b600154600160b81b900460ff1615611f0f5760405163bbc5234f60e01b815260040160405180910390fd5b611f17613876565b60008111611f5d5760405162461bcd60e51b815260206004820152601360248201527204c505f4454543a20416d6f756e74206973203606c1b6044820152606401610ebe565b600f546001600160801b031615611fb357600f54600e546001600160801b0391821691611f94918491600160781b909104166159f8565b1115611fb357604051638fd0b1ed60e01b815260040160405180910390fd5b600060138381548110611fc857611fc8615a78565b6000918252602090912001546001600160a01b0316905061200a7f0000000000000000000000000000000000000000000000000000000000000000600a615bb2565b816001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612048573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061206c9190615a8e565b10156120ba5760405162461bcd60e51b815260206004820152601b60248201527f4c505f4454543a20496e73756666696369656e742073686172657300000000006044820152606401610ebe565b6120ef6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016333085613d19565b6001600160a01b0381166000908152601660205260409020805483019055612116826138bb565b600e8054600160781b600160f81b03198116600160781b918290046001600160801b0390811694909401841682021791829055600a54611d10945092910416613b49565b600154600160b01b900460ff16156121855760405163bbc5234f60e01b815260040160405180910390fd5b61218d613876565b604051632724fe0960e01b81526001600160a01b0386811660048301526000917f000000000000000000000000000000000000000000000000000000000000000090911690632724fe0990602401602060405180830381865afa1580156121f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061221c9190615bc1565b90506001600160a01b03811661226b5760405162461bcd60e51b8152602060048201526014602482015273131417d11055d30e88139bdd0818481d985d5b1d60621b6044820152606401610ebe565b600e546000906127109061228a90640100000000900460ff168a615bde565b6122949190615c0b565b61229e90896159f8565b90506001600160a01b0382163314612326576001600160a01b038088166000908152601860209081526040808320938616835292815282822033835290522054600019146123265760405162461bcd60e51b8152602060048201526015602482015274131417d11055d30e8815539055551213d492569151605a1b6044820152606401610ebe565b6123308188613e1b565b5061233c8882036138bb565b600e80546001600160801b03600160781b808304821690940116909202600160781b600160f81b03199092169190911790556010546001600160a01b03600160601b9091048116600090815260166020526040902080548a84030190556123c6907f000000000000000000000000000000000000000000000000000000000000000016878a613da3565b600080886001600160a01b0316634d401a368989896040518463ffffffff1660e01b81526004016123f993929190615c1f565b60408051808303816000875af1158015612417573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061243b9190615c5f565b90925090506001600160a01b03821630148015612466575060008181526003602052604090205460ff165b6124a65760405162461bcd60e51b8152602060048201526011602482015270131417d11055d30e8814995d995c9d1959607a1b6044820152606401610ebe565b6001600160e81b03198516336001600160a01b038b167f921c81c17e72f815c88a3e0fa28e7e709d56f0c5832e17b4bcc606dc9ee1a6118b8e6124e9818a615a65565b604080516001600160a01b03909416845260208401929092529082015260600160405180910390a45050600a54600e546113529350909150600160781b90046001600160801b0316613b49565b6001546001600160a01b031633146125905760405162461bcd60e51b815260206004820152601760248201527f477561726469616e3a204f6e6c7920677561726469616e0000000000000000006044820152606401610ebe565b6002546125a090622a30006159f8565b42116125e25760405162461bcd60e51b8152602060048201526011602482015270475f503a2043616e6e6f7420706175736560781b6044820152606401610ebe565b6001805464ffffffffff60a01b191664010101010160a01b1781554260025560408051828152602081018390529081018290526060810182905260808101919091527f8502e0dfa7512c68fe07e3fd09dba9a9545c1e68fb13e18348da704c2fa7275e9060a0015b60405180910390a1565b6000546001600160a01b0316331461267e5760405162461bcd60e51b8152600401610ebe90615a0b565b600e5461ffff828116916126a691600160681b82041690600160501b900462ffffff16615c8d565b6126b09190615ca9565b600e805464ffffffffff60501b1916600160501b62ffffff939093169290920261ffff60681b191691909117600160681b61ffff8416908102919091179091556040519081527f37ff452135135f1d2c10b27bbd9d50b762f72d6184b09337bc9d38d093169c0390602001610f22565b6000611b6d613876565b600154600160b01b900460ff16156127555760405163bbc5234f60e01b815260040160405180910390fd5b61275d613876565b604051632724fe0960e01b81526001600160a01b0384811660048301526000917f000000000000000000000000000000000000000000000000000000000000000090911690632724fe0990602401602060405180830381865afa1580156127c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127ec9190615bc1565b90506001600160a01b0381166128385760405162461bcd60e51b8152602060048201526011602482015270131417d08e88139bdd0818481d985d5b1d607a1b6044820152606401610ebe565b600e546000906127109061285790640100000000900460ff1688615bde565b6128619190615c0b565b61286b90876159f8565b90506001600160a01b03821633146128ef576001600160a01b03808616600090815260186020908152604080832093861683529281528282203383529052205460001981146128ed576128be8282615a65565b6001600160a01b0380881660009081526018602090815260408083209388168352928152828220338352905220555b505b6128f98186613e1b565b506129058682036138bb565b600e80546001600160801b03600160781b808304821690940116909202600160781b600160f81b03199092169190911790556010546001600160a01b03600160601b909104811660009081526016602052604081208054898503019055908190819088166317e62b67826129788b613534565b6040516001600160e01b031960e085901b16815260048101929092526024820152604401606060405180830381865afa1580156129b9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129dd9190615cc5565b9250925092508280156129f857506001600160a01b03821630145b8015612a12575060008181526003602052604090205460ff165b612a4f5760405162461bcd60e51b815260206004820152600e60248201526d131417d08e8814995d995c9d195960921b6044820152606401610ebe565b612a836001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016888b613da3565b6001600160e81b03198616336001600160a01b038a167f921c81c17e72f815c88a3e0fa28e7e709d56f0c5832e17b4bcc606dc9ee1a6118a8d612ac6818b615a65565b604080516001600160a01b03909416845260208401929092529082015260600160405180910390a45050600a54600e54612b159450909250600160781b90046001600160801b03169050613b49565b50505050565b60008181526003602052604081205481908190819060ff1615612b97575050600f54600192507f000000000000000000000000000000000000000000000000000000000000000091507f000000000000000000000000000000000000000000000000000000000000000090600160801b90046001600160601b03165b9193509193565b6000546001600160a01b03163314612bc85760405162461bcd60e51b8152600401610ebe90615a0b565b600e5461ffff82811691612bf091600160401b82041690600160281b900462ffffff16615c8d565b612bfa9190615ca9565b600e805469ffffffffff00000000001916600160281b62ffffff939093169290920269ffff0000000000000000191691909117600160401b61ffff8416908102919091179091556040519081527f553cb4d921add3331757ed1c44f851dcfab622fbc4975007ed008dce680ffe4790602001610f22565b604051632724fe0960e01b81526001600160a01b03828116600483015233917f000000000000000000000000000000000000000000000000000000000000000090911690632724fe0990602401602060405180830381865afa158015612cdb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cff9190615bc1565b6001600160a01b031614612d4b5760405162461bcd60e51b8152602060048201526013602482015272131417d0508e8815539055551213d492569151606a1b6044820152606401610ebe565b6001600160a01b0381811660008181526018602090815260408083203380855290835281842095891680855295835292819020879055518681529192917f9c3c3fddd897f6c3dce14f62fcc742f199fb00b47c0664b980cbdea1be127411910160405180910390a4505050565b60058054610f3a90615a31565b6000546001600160a01b03163314612def5760405162461bcd60e51b8152600401610ebe90615a0b565b6001600160a01b03831660009081526014602052604090205460ff1615612e505760405162461bcd60e51b815260206004820152601560248201527454525f41443a20416c72656164792065786973747360581b6044820152606401610ebe565b8161ffff16600e60058282829054906101000a900462ffffff16612e749190615ca9565b825462ffffff91821661010093840a90810290830219909116179092556011805460018101909155601081047f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c6801805461ffff8089166002600f9095169490940290940a838102908502199091161790556001600160a01b038716600090815260156020526040902055600e8054918516935091600a91612f1e918591600160501b900416615ca9565b825461010092830a62ffffff818102199092169290911602179091556012805460018181019092557fbb8a6a4669ba250d26cd7a459eca9d215f8307e33aebe50379bc5a3617ec344460108204018054600f90921660020290930a61ffff8181021990921691861602179091556013805480830182557f66de8ffda797e3de9c05e8fc57b3bf0ec28a930d40b0d285d93c06501cf6a0900180546001600160a01b0319166001600160a01b0388169081179091556000908152601460205260409020805460ff19168317905554612ff59250615a65565b60ff16836001600160a01b03167f5f77a2c0fccc0d2bdab612b4afae9f6108ce73d48f2ea671605aa7191aa60b58848460405161304392919061ffff92831681529116602082015260400190565b60405180910390a3505050565b6000546001600160a01b0316331461307a5760405162461bcd60e51b8152600401610ebe90615a0b565b60135482106130cb5760405162461bcd60e51b815260206004820152601c60248201527f54525f5349573a204e6f6e204578697374696e67205472616e636865000000006044820152606401610ebe565b8061ffff16601183815481106130e3576130e3615a78565b90600052602060002090601091828204019190066002029054906101000a900461ffff1661ffff16600e60059054906101000a900462ffffff166131279190615c8d565b6131319190615ca9565b600e60056101000a81548162ffffff021916908362ffffff160217905550806011838154811061316357613163615a78565b90600052602060002090601091828204019190066002026101000a81548161ffff021916908361ffff1602179055508061ffff1660156000601385815481106131ae576131ae615a78565b6000918252602080832091909101546001600160a01b03168352828101939093526040918201902092909255905161ffff8316815283917f7283d16027b080a3c9be9ae5695b23b19ef3e5066059566674e4680bacf3c8ca910161109b565b600154600160a01b900460ff16156132385760405163bbc5234f60e01b815260040160405180910390fd5b613240613876565b600061324b82613534565b9050600083821161325c578161325e565b835b90506132956001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016333084613d19565b6132a0818485613bbb565b5060405181815233906001600160a01b038516907f05f2eeda0e08e4b437f487c8d7d29b14537d15e3488170dc3de5dbdf8dac46849060200160405180910390a35050600a54600e54611d109190600160781b90046001600160801b0316613b49565b6006546000908015610fdf57610fda61331a610e5d565b849083613858565b6000546001600160a01b0316331461334c5760405162461bcd60e51b8152600401610ebe90615a0b565b61159381613f15565b6000546001600160a01b0316331461337f5760405162461bcd60e51b8152600401610ebe90615a0b565b60135482106133d05760405162461bcd60e51b815260206004820152601c60248201527f54525f534c573a204e6f6e204578697374696e67205472616e636865000000006044820152606401610ebe565b8061ffff16601283815481106133e8576133e8615a78565b90600052602060002090601091828204019190066002029054906101000a900461ffff1661ffff16600e600a9054906101000a900462ffffff1661342c9190615c8d565b6134369190615ca9565b600e600a6101000a81548162ffffff021916908362ffffff160217905550806012838154811061346857613468615a78565b90600052602060002090601091828204019190066002026101000a81548161ffff021916908361ffff160217905550817fa0bb5ed3a1177ecbc7a7ee676d73ea48b239c9261b6e5b6d781c263e71f0b9018260405161109b919061ffff91909116815260200190565b6000611b9882613534565b6006546000908015610fdf57610fda816134f4610e5d565b859190613832565b60128181548110611ad057600080fd5b613514613876565b600a54600e5461179b9190600160781b90046001600160801b0316613b49565b6001600160a01b038116600090815260076020526040812054611b9890610fbb565b60405163ced4f63360e01b815260040160405180910390fd5b600c54600e54600091670de0b6b3a7640000908101916301e1338063ffffffff909116420382020490806135a38484613f27565b03600a5402816135b5576135b5615bf5565b0492506135c1836138bb565b6001600160801b03169250505090565b6000546001600160a01b031633146135fb5760405162461bcd60e51b8152600401610ebe90615a0b565b600f80546001600160801b0319166001600160801b0383169081179091556040519081527fb01769936feb4d3129c98c6f606578713d8b445ff96e0a744154ab58efb15e5090602001610f22565b6000611b98826134dc565b6000546001600160a01b0316331461367e5760405162461bcd60e51b8152600401610ebe90615a0b565b601080546001600160a01b03909216600160601b026001600160601b03909216919091179055565b6000546001600160a01b031633146136d05760405162461bcd60e51b8152600401610ebe90615a0b565b600080546001600160a01b0319166001600160a01b0383169081178255604051909133917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a350565b60025461372b9062278d006159f8565b42116137705760405162461bcd60e51b8152602060048201526014602482015273475f55503a2043616e6e6f7420756e506175736560601b6044820152606401610ebe565b600154600160a01b900460ff16806137915750600154600160a81b900460ff165b806137a55750600154600160b01b900460ff165b806137b95750600154600160b81b900460ff165b806137cd5750600154600160c01b900460ff165b1561179b576001805464ffffffffff60a01b19169055604080516000808252602082018190529181018290526060810182905260808101919091527f8502e0dfa7512c68fe07e3fd09dba9a9545c1e68fb13e18348da704c2fa7275e9060a00161264a565b600082600019048411830215820261384957600080fd5b50910281810615159190040190565b600082600019048411830215820261386f57600080fd5b5091020490565b600e544263ffffffff90811691161461179b57600061389361356f565b600e805463ffffffff19164263ffffffff16179055600a80548201905590506115938161409c565b6000600160801b82106138cd57600080fd5b5090565b60135460009081905b8015612b155780600190039050601381815481106138fa576138fa615a78565b60009182526020808320909101546001600160a01b03168083526016909152604090912054909350915081841015613950576001600160a01b038316600090815260166020526040902080548590039055612b15565b6001600160a01b03831660009081526016602052604081205561397381846141b4565b8184039350826001600160a01b031663f83d08ba6040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156139b357600080fd5b505af11580156139c7573d6000803e3d6000fd5b5050505080600014613a585760136139e0600183615a65565b815481106139f0576139f0615a78565b600091825260209091200154604051633dd217f760e21b8152600160048201526001600160a01b039091169063f7485fdc90602401600060405180830381600087803b158015613a3f57600080fd5b505af1158015613a53573d6000803e3d6000fd5b505050505b6138da565b80600080805b601354811015613b195760128181548110613a8057613a80615a78565b60009182526020909120601082040154600f9091166002026101000a900461ffff1691508115613b1157600e54613ac69086908490600160501b900462ffffff16613858565b9250826016600060138481548110613ae057613ae0615a78565b60009182526020808320909101546001600160a01b0316835282019290925260400190208054909101905592829003925b600101613a63565b50506010546001600160a01b03600160601b90910416600090815260166020526040902080549092019091555050565b60008115613b6c5781613b5f84620186a0615bde565b613b699190615c0b565b90505b7fe4cc9064635aa3e9263498b6ffb48bd2ad68b96a0e14efdbebc7d78590c682e0613b96826143b3565b600c8190556040516001600160501b03909116815260200160405180910390a1505050565b6000613bc684611003565b905080600003613c0c5760405162461bcd60e51b815260206004820152601160248201527044545f573a205a45524f5f53484152455360781b6044820152606401610ebe565b613c168282614435565b83600a6000828254613c289190615a65565b909155505060408051858152602081018390526001600160a01b03808516929086169133917ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db910160405180910390a49392505050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6004604051613cb19190615d08565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b60006040516323b872dd60e01b81528460048201528360248201528260448201526020600060648360008a5af13d15601f3d1160016000511416171691505080613d9c5760405162461bcd60e51b81526020600482015260146024820152731514905394d1915497d19493d357d1905253115160621b6044820152606401610ebe565b5050505050565b600060405163a9059cbb60e01b8152836004820152826024820152602060006044836000895af13d15601f3d1160016000511416171691505080612b155760405162461bcd60e51b815260206004820152600f60248201526e1514905394d1915497d19052531151608a1b6044820152606401610ebe565b6000613e2683613649565b600b549091506001600160801b031615613ea857600b546001600160801b031683613e5084613534565b613e5a91906159f8565b1115613ea85760405162461bcd60e51b815260206004820152601960248201527f44545f443a20424f52524f575f4341505f4558434545444544000000000000006044820152606401610ebe565b613eb282826144b1565b82600a6000828254613ec491906159f8565b909155505060408051848152602081018390526001600160a01b0384169133917fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7910160405180910390a392915050565b80600d613f228282615dc0565b505050565b600081600003613f405750670de0b6b3a7640000611b98565b82600003613f5057506000611b98565b613f61600160ff1b84106006614515565b82613f85613f7c68056bc75e2d63100000600160fe1b615c0b565b84106007614515565b82600082613fa367016345785d8a0000670de0b6b3a7640000615e82565b128015613fc85750613fc5670de0b6b3a764000067016345785d8a0000615ea2565b83125b15614031576000613fd884614523565b9050670de0b6b3a764000083613fee8284615eca565b613ff89190615ede565b6140029190615f0e565b83614015670de0b6b3a764000084615f0e565b61401f9190615ede565b6140299190615ea2565b915050614048565b8161403b8461475a565b6140459190615ede565b90505b61405a670de0b6b3a764000082615f0e565b905061408981680238fd42c5cf03ffff1913158015614082575068070c1cc73b00c800008213155b6008614515565b61409281614d40565b9695505050505050565b806000805b60135481101561414b576140f9601182815481106140c1576140c1615a78565b60009182526020909120601082040154600e548792600f166002026101000a90910461ffff1690600160281b900462ffffff16613858565b915081601660006013848154811061411357614113615a78565b60009182526020808320909101546001600160a01b0316835282019290925260400190208054909101905591819003916001016140a1565b50614155836138bb565b600e80546001600160801b03600160781b808304821690940116909202600160781b600160f81b0319909216919091179055506010546001600160a01b03600160601b9091041660009081526016602052604090208054909101905550565b601182815481106141c7576141c7615a78565b90600052602060002090601091828204019190066002029054906101000a900461ffff1661ffff16600e60058282829054906101000a900462ffffff1661420e9190615c8d565b92506101000a81548162ffffff021916908362ffffff1602179055506012828154811061423d5761423d615a78565b90600052602060002090601091828204019190066002029054906101000a900461ffff1661ffff16600e600a8282829054906101000a900462ffffff166142849190615c8d565b825462ffffff9182166101009390930a9283029190920219909116179055506001600160a01b0381166000908152601460205260409020805460ff1916905560118054806142d4576142d4615f3c565b600082815260209020601060001990920191820401805461ffff6002600f8516026101000a02191690559055601280548061431157614311615f3c565b600082815260209020601060001990920191820401805461ffff6002600f8516026101000a02191690559055601380548061434e5761434e615f3c565b6000828152602090819020600019908301810180546001600160a01b03191690559091019091556040516001600160a01b03831681527f14254003b9294c30e1b403adc733441503a0aecf4ff410885229833defef329a910160405180910390a15050565b600d54600090600160d81b900464ffffffffff1682106144115750600d54620186a0600160901b82046001600160481b03908116600160d81b840464ffffffffff169485900302600160481b84048216909402939093010491160190565b50600d54620186a06001600160481b03600160481b83048116939093020491160190565b6001600160a01b0382166000908152600760205260408120805483929061445d908490615a65565b90915550506006805482900390556040518181526000906001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906020015b60405180910390a35050565b80600660008282546144c391906159f8565b90915550506001600160a01b0382166000818152600760209081526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91016144a5565b81611d1057611d1081615377565b6000614537670de0b6b3a764000083615ede565b915060006145536a0c097ce7bc90715b34b9f160241b84615ea2565b6a0c097ce7bc90715b34b9f160241b61456c8186615e82565b6145769190615ede565b6145809190615f0e565b905060006a0c097ce7bc90715b34b9f160241b61459d8380615ede565b6145a79190615f0e565b905081806a0c097ce7bc90715b34b9f160241b6145c48483615ede565b6145ce9190615f0e565b91506145db600383615f0e565b6145e59082615ea2565b90506a0c097ce7bc90715b34b9f160241b6146008484615ede565b61460a9190615f0e565b9150614617600583615f0e565b6146219082615ea2565b90506a0c097ce7bc90715b34b9f160241b61463c8484615ede565b6146469190615f0e565b9150614653600783615f0e565b61465d9082615ea2565b90506a0c097ce7bc90715b34b9f160241b6146788484615ede565b6146829190615f0e565b915061468f600983615f0e565b6146999082615ea2565b90506a0c097ce7bc90715b34b9f160241b6146b48484615ede565b6146be9190615f0e565b91506146cb600b83615f0e565b6146d59082615ea2565b90506a0c097ce7bc90715b34b9f160241b6146f08484615ede565b6146fa9190615f0e565b9150614707600d83615f0e565b6147119082615ea2565b90506a0c097ce7bc90715b34b9f160241b61472c8484615ede565b6147369190615f0e565b9150614743600f83615f0e565b61474d9082615ea2565b9050614092816002615ede565b6000670de0b6b3a764000082121561479a5761479182614782670de0b6b3a764000080615ede565b61478c9190615f0e565b61475a565b611b9890615f52565b60006147c6670de0b6b3a7640000770195e54c5dd42177f53a27172fa9ec630262827000000000615ede565b8312614806576147ee770195e54c5dd42177f53a27172fa9ec63026282700000000084615f0e565b92506148036806f05b59d3b200000082615ea2565b90505b614824670de0b6b3a76400006b1425982cf597cd205cef7380615ede565b8312614858576148406b1425982cf597cd205cef738084615f0e565b92506148556803782dace9d900000082615ea2565b90505b614863606482615ede565b9050614870606484615ede565b92506e01855144814a7ff805980ff008400083126148cd576e01855144814a7ff805980ff00840006148ab68056bc75e2d6310000085615ede565b6148b59190615f0e565b92506148ca68ad78ebc5ac6200000082615ea2565b90505b6b02df0ab5a80a22c61ab5a7008312614922576b02df0ab5a80a22c61ab5a70061490068056bc75e2d6310000085615ede565b61490a9190615f0e565b925061491f6856bc75e2d63100000082615ea2565b90505b693f1fce3da636ea5cf850831261497357693f1fce3da636ea5cf85061495168056bc75e2d6310000085615ede565b61495b9190615f0e565b9250614970682b5e3af16b1880000082615ea2565b90505b690127fa27722cc06cc5e283126149c457690127fa27722cc06cc5e26149a268056bc75e2d6310000085615ede565b6149ac9190615f0e565b92506149c16815af1d78b58c40000082615ea2565b90505b68280e60114edb805d038312614a135768280e60114edb805d036149f168056bc75e2d6310000085615ede565b6149fb9190615f0e565b9250614a10680ad78ebc5ac620000082615ea2565b90505b680ebc5fb417461211108312614a6257680ebc5fb41746121110614a4068056bc75e2d6310000085615ede565b614a4a9190615f0e565b9250614a5f68056bc75e2d6310000082615ea2565b90505b6808f00f760a4b2db55d8312614ab1576808f00f760a4b2db55d614a8f68056bc75e2d6310000085615ede565b614a999190615f0e565b9250614aae6802b5e3af16b188000082615ea2565b90505b6806f5f17757889379378312614b00576806f5f1775788937937614ade68056bc75e2d6310000085615ede565b614ae89190615f0e565b9250614afd68015af1d78b58c4000082615ea2565b90505b6806248f33704b2866038312614b4e576806248f33704b286603614b2d68056bc75e2d6310000085615ede565b614b379190615f0e565b9250614b4b67ad78ebc5ac62000082615ea2565b90505b6805c548670b9510e7ac8312614b9c576805c548670b9510e7ac614b7b68056bc75e2d6310000085615ede565b614b859190615f0e565b9250614b996756bc75e2d631000082615ea2565b90505b6000614bb168056bc75e2d6310000085615ea2565b68056bc75e2d63100000614bc58187615e82565b614bcf9190615ede565b614bd99190615f0e565b9050600068056bc75e2d63100000614bf18380615ede565b614bfb9190615f0e565b9050818068056bc75e2d63100000614c138483615ede565b614c1d9190615f0e565b9150614c2a600383615f0e565b614c349082615ea2565b905068056bc75e2d63100000614c4a8484615ede565b614c549190615f0e565b9150614c61600583615f0e565b614c6b9082615ea2565b905068056bc75e2d63100000614c818484615ede565b614c8b9190615f0e565b9150614c98600783615f0e565b614ca29082615ea2565b905068056bc75e2d63100000614cb88484615ede565b614cc29190615f0e565b9150614ccf600983615f0e565b614cd99082615ea2565b905068056bc75e2d63100000614cef8484615ede565b614cf99190615f0e565b9150614d06600b83615f0e565b614d109082615ea2565b9050614d1d600282615ede565b90506064614d2b8287615ea2565b614d359190615f0e565b979650505050505050565b6000614d6f680238fd42c5cf03ffff198312158015614d68575068070c1cc73b00c800008313155b6009614515565b6000821215614da557614d89614d8483615f52565b614d40565b614d9b670de0b6b3a764000080615ede565b611b989190615f0e565b60006806f05b59d3b20000008312614dec57614dca6806f05b59d3b200000084615e82565b9250770195e54c5dd42177f53a27172fa9ec6302628270000000009050614e29565b6803782dace9d90000008312614e2557614e0f6803782dace9d900000084615e82565b92506b1425982cf597cd205cef73809050614e29565b5060015b614e34606484615ede565b925068056bc75e2d6310000068ad78ebc5ac620000008412614e9557614e6368ad78ebc5ac6200000085615e82565b935068056bc75e2d63100000614e886e01855144814a7ff805980ff008400083615ede565b614e929190615f0e565b90505b6856bc75e2d6310000008412614ee757614eb86856bc75e2d63100000085615e82565b935068056bc75e2d63100000614eda6b02df0ab5a80a22c61ab5a70083615ede565b614ee49190615f0e565b90505b682b5e3af16b188000008412614f3757614f0a682b5e3af16b1880000085615e82565b935068056bc75e2d63100000614f2a693f1fce3da636ea5cf85083615ede565b614f349190615f0e565b90505b6815af1d78b58c4000008412614f8757614f5a6815af1d78b58c40000085615e82565b935068056bc75e2d63100000614f7a690127fa27722cc06cc5e283615ede565b614f849190615f0e565b90505b680ad78ebc5ac62000008412614fd657614faa680ad78ebc5ac620000085615e82565b935068056bc75e2d63100000614fc968280e60114edb805d0383615ede565b614fd39190615f0e565b90505b68056bc75e2d63100000841261502557614ff968056bc75e2d6310000085615e82565b935068056bc75e2d63100000615018680ebc5fb4174612111083615ede565b6150229190615f0e565b90505b6802b5e3af16b18800008412615074576150486802b5e3af16b188000085615e82565b935068056bc75e2d631000006150676808f00f760a4b2db55d83615ede565b6150719190615f0e565b90505b68015af1d78b58c4000084126150c35761509768015af1d78b58c4000085615e82565b935068056bc75e2d631000006150b66806f5f177578893793783615ede565b6150c09190615f0e565b90505b68056bc75e2d63100000846150d88183615ea2565b9150600268056bc75e2d631000006150f08884615ede565b6150fa9190615f0e565b6151049190615f0e565b90506151108183615ea2565b9150600368056bc75e2d631000006151288884615ede565b6151329190615f0e565b61513c9190615f0e565b90506151488183615ea2565b9150600468056bc75e2d631000006151608884615ede565b61516a9190615f0e565b6151749190615f0e565b90506151808183615ea2565b9150600568056bc75e2d631000006151988884615ede565b6151a29190615f0e565b6151ac9190615f0e565b90506151b88183615ea2565b9150600668056bc75e2d631000006151d08884615ede565b6151da9190615f0e565b6151e49190615f0e565b90506151f08183615ea2565b9150600768056bc75e2d631000006152088884615ede565b6152129190615f0e565b61521c9190615f0e565b90506152288183615ea2565b9150600868056bc75e2d631000006152408884615ede565b61524a9190615f0e565b6152549190615f0e565b90506152608183615ea2565b9150600968056bc75e2d631000006152788884615ede565b6152829190615f0e565b61528c9190615f0e565b90506152988183615ea2565b9150600a68056bc75e2d631000006152b08884615ede565b6152ba9190615f0e565b6152c49190615f0e565b90506152d08183615ea2565b9150600b68056bc75e2d631000006152e88884615ede565b6152f29190615f0e565b6152fc9190615f0e565b90506153088183615ea2565b9150600c68056bc75e2d631000006153208884615ede565b61532a9190615f0e565b6153349190615f0e565b90506153408183615ea2565b915060648468056bc75e2d631000006153598587615ede565b6153639190615f0e565b61536d9190615ede565b6140929190615f0e565b6030600a820601600a820491506030600a830601600a830492506030600a8406018060101b8260081b8401016642414c230000000160c81b9250505062461bcd60e51b600052602060045260076024528060445260646000fd5b6000602082840312156153e357600080fd5b81356001600160601b0381168114610fe157600080fd5b600060208083528351808285015260005b818110156154275785810183015185820160400152820161540b565b506000604082860101526040601f19601f8301168501019250505092915050565b60006020828403121561545a57600080fd5b5035919050565b6001600160a01b038116811461159357600080fd5b6000806040838503121561548957600080fd5b823561549481615461565b946020939093013593505050565b801515811461159357600080fd5b600080604083850312156154c357600080fd5b8235915060208301356154d5816154a2565b809150509250929050565b60008060008060008060c087890312156154f957600080fd5b863561550481615461565b9550602087013561551481615461565b95989597505050506040840135936060810135936080820135935060a0909101359150565b60006020828403121561554b57600080fd5b8135610fe181615461565b60006020828403121561556857600080fd5b81356001600160801b0381168114610fe157600080fd5b803560ff81168114611b8857600080fd5b6000602082840312156155a257600080fd5b610fe18261557f565b6000806000606084860312156155c057600080fd5b83356155cb81615461565b925060208401356155db81615461565b929592945050506040919091013590565b600080600080600060a0868803121561560457600080fd5b853561560f816154a2565b9450602086013561561f816154a2565b9350604086013561562f816154a2565b9250606086013561563f816154a2565b9150608086013561564f816154a2565b809150509295509295909350565b6000806040838503121561567057600080fd5b8235915060208301356154d581615461565b60006020828403121561569457600080fd5b81356001600160501b0381168114610fe157600080fd5b600080604083850312156156be57600080fd5b50508035926020909101359150565b80356001600160e81b031981168114611b8857600080fd5b60008060008060008060a087890312156156fe57600080fd5b86359550602087013561571081615461565b9450604087013561572081615461565b9350606087013567ffffffffffffffff8082111561573d57600080fd5b818901915089601f83011261575157600080fd5b81358181111561576057600080fd5b8a602082850101111561577257600080fd5b60208301955080945050505061578a608088016156cd565b90509295509295509295565b803561ffff81168114611b8857600080fd5b6000602082840312156157ba57600080fd5b610fe182615796565b600080600080608085870312156157d957600080fd5b8435935060208501356157eb81615461565b925060408501356157fb81615461565b9150615809606086016156cd565b905092959194509250565b60008060006060848603121561582957600080fd5b833561583481615461565b925060208401359150604084013561584b81615461565b809150509250925092565b60008060006060848603121561586b57600080fd5b833561587681615461565b925061588460208501615796565b915061589260408501615796565b90509250925092565b600080604083850312156158ae57600080fd5b823591506158be60208401615796565b90509250929050565b6000806000606084860312156158dc57600080fd5b8335925060208401356158ee81615461565b9150604084013561584b81615461565b60008060006060848603121561591357600080fd5b833561591e81615461565b925060208401356158ee81615461565b60006080828403121561594057600080fd5b50919050565b600080600080600080600060e0888a03121561596157600080fd5b873561596c81615461565b9650602088013561597c81615461565b955060408801359450606088013593506159986080890161557f565b925060a0880135915060c0880135905092959891949750929550565b600080604083850312156159c757600080fd5b82356159d281615461565b915060208301356154d581615461565b634e487b7160e01b600052601160045260246000fd5b80820180821115611b9857611b986159e2565b6020808252600c908201526b15539055551213d49256915160a21b604082015260600190565b600181811c90821680615a4557607f821691505b60208210810361594057634e487b7160e01b600052602260045260246000fd5b81810381811115611b9857611b986159e2565b634e487b7160e01b600052603260045260246000fd5b600060208284031215615aa057600080fd5b5051919050565b6001600160801b03828116828216039080821115615ac757615ac76159e2565b5092915050565b600181815b80851115615b09578160001904821115615aef57615aef6159e2565b80851615615afc57918102915b93841c9390800290615ad3565b509250929050565b600082615b2057506001611b98565b81615b2d57506000611b98565b8160018114615b435760028114615b4d57615b69565b6001915050611b98565b60ff841115615b5e57615b5e6159e2565b50506001821b611b98565b5060208310610133831016604e8410600b8410161715615b8c575081810a611b98565b615b968383615ace565b8060001904821115615baa57615baa6159e2565b029392505050565b6000610fe160ff841683615b11565b600060208284031215615bd357600080fd5b8151610fe181615461565b8082028115828204841417611b9857611b986159e2565b634e487b7160e01b600052601260045260246000fd5b600082615c1a57615c1a615bf5565b500490565b6001600160a01b03841681526040602082018190528101829052818360608301376000818301606090810191909152601f909201601f1916010192915050565b60008060408385031215615c7257600080fd5b8251615c7d81615461565b6020939093015192949293505050565b62ffffff828116828216039080821115615ac757615ac76159e2565b62ffffff818116838216019080821115615ac757615ac76159e2565b600080600060608486031215615cda57600080fd5b8351615ce5816154a2565b6020850151909350615cf681615461565b80925050604084015190509250925092565b600080835481600182811c915080831680615d2457607f831692505b60208084108203615d4357634e487b7160e01b86526022600452602486fd5b818015615d575760018114615d6c57615d99565b60ff1986168952841515850289019650615d99565b60008a81526020902060005b86811015615d915781548b820152908501908301615d78565b505084890196505b509498975050505050505050565b600081356001600160481b0381168114611b9857600080fd5b6001600160481b03615dd183615da7565b168154816001600160481b0319821617835571ffffffffffffffffff000000000000000000615e0260208601615da7565b60481b16808371ffffffffffffffffffffffffffffffffffff198416171784556001600160481b0360901b615e3960408701615da7565b60901b1664ffffffffff60d81b81858286161784171786556060870135935064ffffffffff84168414615e6b57600080fd5b808460d81b16858417831717865550505050505050565b8181036000831280158383131683831282161715615ac757615ac76159e2565b8082018281126000831280158216821582161715615ec257615ec26159e2565b505092915050565b600082615ed957615ed9615bf5565b500790565b80820260008212600160ff1b84141615615efa57615efa6159e2565b8181058314821517611b9857611b986159e2565b600082615f1d57615f1d615bf5565b600160ff1b821460001984141615615f3757615f376159e2565b500590565b634e487b7160e01b600052603160045260246000fd5b6000600160ff1b8201615f6757615f676159e2565b506000039056fea26469706673582212209780f6277341e8b0493529fdc95bb4bd714f1a96ebea72b6e1cf82e72de3d42c64736f6c63430008110033000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000beb56fbef3387af554a554e7db25830eb7b92e3200000000000000000000000000cb53780ea58503d3059fc02ddd596d0be926cb000000000000000000000000d2a34731586bd10b645f870f4c9dcaf4f9e3823c
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106105665760003560e01c80638456cb59116102ca578063b78891571161018d578063ce96cb77116100f4578063e11a0b83116100ad578063f0f4426011610087578063f0f4426014610e26578063f2fde38b14610e39578063f7b188a514610e4c578063f89d36a514610e5457600080fd5b8063e11a0b8314610df8578063e2dd93a214610e00578063ef8b30f714610e1357600080fd5b8063ce96cb7714610d43578063d505accf14610d56578063d53dc73914610d69578063d8a06f7314610d7d578063d905777e14610da4578063dd62ed3e14610dcd57600080fd5b8063bfcc565711610146578063bfcc565714610cef578063c11002df14610d02578063c63d75b614610872578063c6e6f59214610d15578063cd387b9814610d28578063ce76756f14610d3b57600080fd5b8063b788915714610c6d578063b8bb5c4214610c82578063ba08765214610c3c578063baf5dc4414610c97578063bc861ab714610cc8578063bcb4bbea14610cdb57600080fd5b806395d89b4111610231578063acb70815116101ea578063acb7081514610be4578063ad84f34114610bf7578063b17935f514610c00578063b3d7f6b914610c29578063b460af9414610c3c578063b73c02ff14610c4a57600080fd5b806395d89b4114610b735780639790576a14610b7b578063980a3f7714610b9e5780639bf4964c14610bb15780639f4020d914610bd1578063a9059cbb146105e757600080fd5b80638da5cb5b116102835780638da5cb5b14610af55780638e33f5ee14610b085780638f69a5c514610b3a5780638f770ad014610b4d5780639086c3a114610b6057806394bf804d146109d857600080fd5b80638456cb5914610a555780638618d38d14610a5d5780638710e70c14610a77578063894bacc914610a8a5780638994685f14610a9d5780638c48052314610ab057600080fd5b806336a36ea41161042d5780634e1255f31161039457806362c9b0f01161034d57806372b5e9231161032757806372b5e92314610a065780637bfbb80214610a195780637c3a00fd14610a2c5780637ecebe0014610a3557600080fd5b806362c9b0f0146109c55780636e553f65146109d857806370a08231146109e657600080fd5b80634e1255f314610937578063542b5fd31461094a5780635b6a14951461095f5780635ef904071461098a57806361d027b3146109a0578063626d6f5e146109ba57600080fd5b80634046ebae116103e65780634046ebae1461088757806340573f6e146108ae57806344d9dca6146108d3578063452a9320146108fe5780634cdad506146109115780634da1f9a81461092457600080fd5b806336a36ea4146107d357806338bfd64d146107f957806338d52e0f1461080e5780633c4750df146108355780633f7ee87314610848578063402d267d1461087257600080fd5b80631bd43293116104d15780632db6c63a1161048a5780632db6c63a146107385780632f3ffb9f146107585780632fcb4f041461076c578063306caf961461077f578063313ce567146107925780633644e515146107cb57600080fd5b80631bd43293146106bd5780631dd19cb4146106d05780631e865815146106d85780631e9dbce6146106eb57806323b872dd146106ff57806326c259621461070d57600080fd5b80630a28a477116105235780630a28a477146105fa578063165bf8c51461060d57806318160ddd14610620578063182bfd20146106295780631919e78b1461063c578063194d7494146106aa57600080fd5b806301e1d1141461056b57806302befd241461058657806302d37a2f146105aa57806306fdde03146105bf57806307a2d13a146105d4578063095ea7b3146105e7575b600080fd5b610573610e5d565b6040519081526020015b60405180910390f35b60015461059a90600160b81b900460ff1681565b604051901515815260200161057d565b6105bd6105b83660046153d1565b610e94565b005b6105c7610f2d565b60405161057d91906153fa565b6105736105e2366004615448565b610fbb565b61059a6105f5366004615476565b610fe8565b610573610608366004615448565b611003565b6105bd61061b3660046154b0565b611023565b61057360065481565b6105bd6106373660046154e0565b6110a7565b600d54610673906001600160481b0380821691600160481b8104821691600160901b82041690600160d81b900464ffffffffff1684565b604080516001600160481b0395861681529385166020850152919093169082015264ffffffffff909116606082015260800161057d565b6105bd6106b8366004615539565b61135a565b6105bd6106cb366004615556565b611596565b6105bd61160e565b6105bd6106e6366004615590565b61179d565b60015461059a90600160a01b900460ff1681565b61059a6105f53660046155ab565b61072061071b366004615448565b611817565b6040516001600160a01b03909116815260200161057d565b610573610746366004615539565b60166020526000908152604090205481565b60015461059a90600160a81b900460ff1681565b6105bd61077a366004615539565b611841565b6105bd61078d3660046155ec565b6118c7565b6107b97f000000000000000000000000000000000000000000000000000000000000000681565b60405160ff909116815260200161057d565b610573611a6a565b6107e66107e1366004615448565b611ac0565b60405161ffff909116815260200161057d565b600e546107e690600160681b900461ffff1681565b6107207f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4881565b610573610843366004615539565b611af8565b600e5461085e90600160281b900462ffffff1681565b60405162ffffff909116815260200161057d565b610573610880366004615539565b5060001990565b6107207f000000000000000000000000d2a34731586bd10b645f870f4c9dcaf4f9e3823c81565b600e546108be9063ffffffff1681565b60405163ffffffff909116815260200161057d565b600b546108e6906001600160801b031681565b6040516001600160801b03909116815260200161057d565b600154610720906001600160a01b031681565b61057361091f366004615448565b611b8d565b6105bd61093236600461565d565b611b9e565b6105bd610945366004615682565b611d14565b6010546107e690600160501b900461ffff1681565b601054610972906001600160501b031681565b6040516001600160501b03909116815260200161057d565b600e5461085e90600160501b900462ffffff1681565b60105461072090600160601b90046001600160a01b031681565b6105736301e1338081565b6105bd6109d336600461565d565b611d8f565b6105736105f536600461565d565b6105736109f4366004615539565b60076020526000908152604090205481565b6105bd610a143660046156ab565b611ee4565b6105bd610a273660046156e5565b61215a565b610573600c5481565b610573610a43366004615539565b60096020526000908152604090205481565b6105bd612536565b600e546108e690600160781b90046001600160801b031681565b6105bd610a853660046157a8565b612654565b610573610a98366004615539565b612720565b6105bd610aab3660046157c3565b61272a565b610ac3610abe366004615448565b612b1b565b60405161057d949392919093151584526001600160a01b03928316602085015291166040830152606082015260800190565b600054610720906001600160a01b031681565b600f54610b2290600160801b90046001600160601b031681565b6040516001600160601b03909116815260200161057d565b6105bd610b483660046157a8565b612b9e565b600f546108e6906001600160801b031681565b6105bd610b6e366004615814565b612c71565b6105c7612db8565b61059a610b89366004615539565b60146020526000908152604090205460ff1681565b6105bd610bac366004615856565b612dc5565b610573610bbf366004615539565b60156020526000908152604090205481565b6105bd610bdf36600461589b565b613050565b6105bd610bf236600461565d565b61320d565b61057360025481565b610720610c0e366004615539565b6017602052600090815260409020546001600160a01b031681565b610573610c37366004615448565b613303565b6105736105f53660046158c7565b61059a610c58366004615448565b60036020526000908152604090205460ff1681565b600e546107e690600160401b900461ffff1681565b600e546107b990640100000000900460ff1681565b610573610ca53660046158fe565b601860209081526000938452604080852082529284528284209052825290205481565b6105bd610cd636600461592e565b613322565b60015461059a90600160b01b900460ff1681565b6105bd610cfd36600461589b565b613355565b610573610d10366004615539565b6134d1565b610573610d23366004615448565b6134dc565b6107e6610d36366004615448565b6134fc565b6105bd61350c565b610573610d51366004615539565b613534565b6105bd610d64366004615946565b613556565b60015461059a90600160c01b900460ff1681565b6107207f00000000000000000000000000cb53780ea58503d3059fc02ddd596d0be926cb81565b610573610db2366004615539565b6001600160a01b031660009081526007602052604090205490565b610573610ddb3660046159b4565b600860209081526000928352604080842090915290825290205481565b61057361356f565b6105bd610e0e366004615556565b6135d1565b610573610e21366004615448565b613649565b6105bd610e34366004615539565b613654565b6105bd610e47366004615539565b6136a6565b6105bd61371b565b610573600a5481565b600e546000904263ffffffff908116911614610e8d57610e7b61356f565b600a54610e8891906159f8565b905090565b50600a5490565b6000546001600160a01b03163314610ec75760405162461bcd60e51b8152600401610ebe90615a0b565b60405180910390fd5b600f80546bffffffffffffffffffffffff60801b1916600160801b6001600160601b038416908102919091179091556040519081527fce76ed33b01ab134c41431ef53932d4130aaf7a443840d0630b94a7474fe19dc906020015b60405180910390a150565b60048054610f3a90615a31565b80601f0160208091040260200160405190810160405280929190818152602001828054610f6690615a31565b8015610fb35780601f10610f8857610100808354040283529160200191610fb3565b820191906000526020600020905b815481529060010190602001808311610f9657829003601f168201915b505050505081565b6006546000908015610fdf57610fda610fd2610e5d565b849083613832565b610fe1565b825b9392505050565b600060405163ced4f63360e01b815260040160405180910390fd5b6006546000908015610fdf57610fda8161101b610e5d565b859190613858565b6000546001600160a01b0316331461104d5760405162461bcd60e51b8152600401610ebe90615a0b565b6000828152600360205260409020805460ff1916821515179055817f6bd62b850d20e8a0251cb2759fd0ebad03703967c804dabab97f9238a0e40e258260405161109b911515815260200190565b60405180910390a25050565b7f000000000000000000000000d2a34731586bd10b645f870f4c9dcaf4f9e3823c6001600160a01b031633146111155760405162461bcd60e51b815260206004820152601360248201527226281d1027b7363c903634b8bab4b230ba37b960691b6044820152606401610ebe565b61111d613876565b6001600160a01b0380871660009081526017602090815260408083205490931682526016905290812080548592906111569084906159f8565b909155505083156111c857600e54611194908590611185908690600160781b90046001600160801b03166159f8565b61118f9190615a65565b6138bb565b600e600f6101000a8154816001600160801b0302191690836001600160801b031602179055506111c3846138d1565b61126a565b6111d182613a5d565b600e5461120b90829084906111f7908790600160781b90046001600160801b03166159f8565b61120191906159f8565b61118f91906159f8565b600e80546001600160801b0392909216600160781b02600160781b600160f81b0319909216919091179055801561126a576001600160a01b038516600090815260166020526040812080548392906112649084906159f8565b90915550505b6010805461ffff60501b198116600160501b9182900461ffff908116600019018116830291909117928390559104161580156112a7575060135415155b1561133257601380546112bc90600190615a65565b815481106112cc576112cc615a78565b6000918252602082200154604051633dd217f760e21b815260048101929092526001600160a01b03169063f7485fdc90602401600060405180830381600087803b15801561131957600080fd5b505af115801561132d573d6000803e3d6000fd5b505050505b600a54600e546113529190600160781b90046001600160801b0316613b49565b505050505050565b600154600160c01b900460ff16156113855760405163bbc5234f60e01b815260040160405180910390fd5b61138d613876565b600061139882613534565b9050806000036113ea5760405162461bcd60e51b815260206004820152601c60248201527f4c505f4c563a204e6f742061205661756c7420776974682064656274000000006044820152606401610ebe565b6001600160a01b038281166000818152601760205260409081902080546001600160a01b0319163317905560105490516378d6c03f60e01b81526004810192909252602482018490526001600160501b031660448201527f000000000000000000000000d2a34731586bd10b645f870f4c9dcaf4f9e3823c909116906378d6c03f90606401600060405180830381600087803b15801561148957600080fd5b505af115801561149d573d6000803e3d6000fd5b5050601054600160501b900461ffff166000039150611540905057601380546114c890600190615a65565b815481106114d8576114d8615a78565b600091825260209091200154604051633dd217f760e21b8152600160048201526001600160a01b039091169063f7485fdc90602401600060405180830381600087803b15801561152757600080fd5b505af115801561153b573d6000803e3d6000fd5b505050505b60108054600161ffff600160501b808404821692909201160261ffff60501b19909116179055611571818380613bbb565b5050600a54600e546115939190600160781b90046001600160801b0316613b49565b50565b6000546001600160a01b031633146115c05760405162461bcd60e51b8152600401610ebe90615a0b565b600b80546001600160801b0319166001600160801b0383169081179091556040519081527ff60cdb66d1290884d4b7cdeee8f7b4d52f8b62b9ff1d89ffc4678d00bc1e3a1490602001610f22565b611616613876565b601054600160501b900461ffff161561166a5760405162461bcd60e51b81526020600482015260166024820152754c505f533a2041756374696f6e73204f6e676f696e6760501b6044820152606401610ebe565b600e54600a546040516370a0823160e01b8152306004820152600092600160781b90046001600160801b031691907f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486001600160a01b0316906370a0823190602401602060405180830381865afa1580156116e9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061170d9190615a8e565b61171791906159f8565b6117219190615a65565b905061172c816138bb565b600e80546001600160801b03600160781b808304821690940181168402600160781b600160f81b03199092169190911782556010546001600160a01b03600160601b9091041660009081526016602052604090208054909401909355600a54905461179b939192900416613b49565b565b6000546001600160a01b031633146117c75760405162461bcd60e51b8152600401610ebe90615a0b565b600e805464ff00000000191664010000000060ff8416908102919091179091556040519081527f62815047fdec5b7ea69997c870fa83e53a213d8d485f2489b58c049eb76cfd1490602001610f22565b6013818154811061182757600080fd5b6000918252602090912001546001600160a01b0316905081565b6000546001600160a01b0316331461186b5760405162461bcd60e51b8152600401610ebe90615a0b565b6001546040516001600160a01b038084169216907fa14fc14d8620a708a896fd11392a235647d99385500a295f0d7da2a258b2e96790600090a3600180546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b031633146118f15760405162461bcd60e51b8152600401610ebe90615a0b565b600154600160a01b900460ff1680156119075750845b60018054911515600160a01b0260ff60a01b199092169190911790819055600160a81b900460ff1680156119385750835b60018054911515600160a81b0260ff60a81b199092169190911790819055600160b01b900460ff1680156119695750825b60018054911515600160b01b0260ff60b01b199092169190911790819055600160b81b900460ff16801561199a5750815b60018054911515600160b81b0260ff60b81b199092169190911790819055600160c01b900460ff1680156119cb5750805b6001805460ff60c01b1916600160c01b921515830217908190556040805160ff600160a01b8404811615158252600160a81b8404811615156020830152600160b01b84048116151592820192909252600160b81b83048216151560608201529290910416151560808201527f8502e0dfa7512c68fe07e3fd09dba9a9545c1e68fb13e18348da704c2fa7275e9060a00160405180910390a15050505050565b60007f00000000000000000000000000000000000000000000000000000000000000014614611a9b57610e88613c7f565b507fb026f7d2ee25084f34e4d50fad78bcd3d965960a0fe3fe6fb559d060cb136bf390565b60118181548110611ad057600080fd5b9060005260206000209060109182820401919006600202915054906101000a900461ffff1681565b600e546000904263ffffffff908116911614611b6d576001600160a01b038216600090815260156020526040812054600e54611b4a9190600160281b900462ffffff16611b4361356f565b9190613832565b6001600160a01b038416600090815260166020526040902054019150611b889050565b506001600160a01b0381166000908152601660205260409020545b919050565b6000611b9882610fbb565b92915050565b600154600160b81b900460ff1615611bc95760405163bbc5234f60e01b815260040160405180910390fd5b3360009081526014602052604090205460ff16611c1b5760405162461bcd60e51b815260206004820152601060248201526f4c503a204f6e6c79207472616e63686560801b6044820152606401610ebe565b611c23613876565b600f546001600160801b031615611c7957600f54600e546001600160801b0391821691611c5a918591600160781b909104166159f8565b1115611c7957604051638fd0b1ed60e01b815260040160405180910390fd5b611cae6001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4816823085613d19565b336000908152601660205260409020805483019055611ccc826138bb565b600e80546001600160801b03600160781b808304821690940181168402600160781b600160f81b03199092169190911791829055600a54611d109390920416613b49565b5050565b6000546001600160a01b03163314611d3e5760405162461bcd60e51b8152600401610ebe90615a0b565b6010805469ffffffffffffffffffff19166001600160501b0383169081179091556040519081527fb459d4513fe6c441f14d1f873f0ac9e675919afdb60c6d63f158dd00fc294ecf90602001610f22565b600154600160a81b900460ff1615611dba5760405163bbc5234f60e01b815260040160405180910390fd5b611dc2613876565b33600090815260166020526040902054821115611e215760405162461bcd60e51b815260206004820152601f60248201527f4c505f57464c503a20416d6f756e7420657863656564732062616c616e6365006044820152606401610ebe565b33600090815260166020526040902080548390039055611e40826138bb565b600e8054600f90611e62908490600160781b90046001600160801b0316615aa7565b92506101000a8154816001600160801b0302191690836001600160801b03160217905550611ec481837f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486001600160a01b0316613da39092919063ffffffff16565b600a54600e54611d109190600160781b90046001600160801b0316613b49565b600154600160b81b900460ff1615611f0f5760405163bbc5234f60e01b815260040160405180910390fd5b611f17613876565b60008111611f5d5760405162461bcd60e51b815260206004820152601360248201527204c505f4454543a20416d6f756e74206973203606c1b6044820152606401610ebe565b600f546001600160801b031615611fb357600f54600e546001600160801b0391821691611f94918491600160781b909104166159f8565b1115611fb357604051638fd0b1ed60e01b815260040160405180910390fd5b600060138381548110611fc857611fc8615a78565b6000918252602090912001546001600160a01b0316905061200a7f0000000000000000000000000000000000000000000000000000000000000006600a615bb2565b816001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612048573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061206c9190615a8e565b10156120ba5760405162461bcd60e51b815260206004820152601b60248201527f4c505f4454543a20496e73756666696369656e742073686172657300000000006044820152606401610ebe565b6120ef6001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4816333085613d19565b6001600160a01b0381166000908152601660205260409020805483019055612116826138bb565b600e8054600160781b600160f81b03198116600160781b918290046001600160801b0390811694909401841682021791829055600a54611d10945092910416613b49565b600154600160b01b900460ff16156121855760405163bbc5234f60e01b815260040160405180910390fd5b61218d613876565b604051632724fe0960e01b81526001600160a01b0386811660048301526000917f00000000000000000000000000cb53780ea58503d3059fc02ddd596d0be926cb90911690632724fe0990602401602060405180830381865afa1580156121f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061221c9190615bc1565b90506001600160a01b03811661226b5760405162461bcd60e51b8152602060048201526014602482015273131417d11055d30e88139bdd0818481d985d5b1d60621b6044820152606401610ebe565b600e546000906127109061228a90640100000000900460ff168a615bde565b6122949190615c0b565b61229e90896159f8565b90506001600160a01b0382163314612326576001600160a01b038088166000908152601860209081526040808320938616835292815282822033835290522054600019146123265760405162461bcd60e51b8152602060048201526015602482015274131417d11055d30e8815539055551213d492569151605a1b6044820152606401610ebe565b6123308188613e1b565b5061233c8882036138bb565b600e80546001600160801b03600160781b808304821690940116909202600160781b600160f81b03199092169190911790556010546001600160a01b03600160601b9091048116600090815260166020526040902080548a84030190556123c6907f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4816878a613da3565b600080886001600160a01b0316634d401a368989896040518463ffffffff1660e01b81526004016123f993929190615c1f565b60408051808303816000875af1158015612417573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061243b9190615c5f565b90925090506001600160a01b03821630148015612466575060008181526003602052604090205460ff165b6124a65760405162461bcd60e51b8152602060048201526011602482015270131417d11055d30e8814995d995c9d1959607a1b6044820152606401610ebe565b6001600160e81b03198516336001600160a01b038b167f921c81c17e72f815c88a3e0fa28e7e709d56f0c5832e17b4bcc606dc9ee1a6118b8e6124e9818a615a65565b604080516001600160a01b03909416845260208401929092529082015260600160405180910390a45050600a54600e546113529350909150600160781b90046001600160801b0316613b49565b6001546001600160a01b031633146125905760405162461bcd60e51b815260206004820152601760248201527f477561726469616e3a204f6e6c7920677561726469616e0000000000000000006044820152606401610ebe565b6002546125a090622a30006159f8565b42116125e25760405162461bcd60e51b8152602060048201526011602482015270475f503a2043616e6e6f7420706175736560781b6044820152606401610ebe565b6001805464ffffffffff60a01b191664010101010160a01b1781554260025560408051828152602081018390529081018290526060810182905260808101919091527f8502e0dfa7512c68fe07e3fd09dba9a9545c1e68fb13e18348da704c2fa7275e9060a0015b60405180910390a1565b6000546001600160a01b0316331461267e5760405162461bcd60e51b8152600401610ebe90615a0b565b600e5461ffff828116916126a691600160681b82041690600160501b900462ffffff16615c8d565b6126b09190615ca9565b600e805464ffffffffff60501b1916600160501b62ffffff939093169290920261ffff60681b191691909117600160681b61ffff8416908102919091179091556040519081527f37ff452135135f1d2c10b27bbd9d50b762f72d6184b09337bc9d38d093169c0390602001610f22565b6000611b6d613876565b600154600160b01b900460ff16156127555760405163bbc5234f60e01b815260040160405180910390fd5b61275d613876565b604051632724fe0960e01b81526001600160a01b0384811660048301526000917f00000000000000000000000000cb53780ea58503d3059fc02ddd596d0be926cb90911690632724fe0990602401602060405180830381865afa1580156127c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127ec9190615bc1565b90506001600160a01b0381166128385760405162461bcd60e51b8152602060048201526011602482015270131417d08e88139bdd0818481d985d5b1d607a1b6044820152606401610ebe565b600e546000906127109061285790640100000000900460ff1688615bde565b6128619190615c0b565b61286b90876159f8565b90506001600160a01b03821633146128ef576001600160a01b03808616600090815260186020908152604080832093861683529281528282203383529052205460001981146128ed576128be8282615a65565b6001600160a01b0380881660009081526018602090815260408083209388168352928152828220338352905220555b505b6128f98186613e1b565b506129058682036138bb565b600e80546001600160801b03600160781b808304821690940116909202600160781b600160f81b03199092169190911790556010546001600160a01b03600160601b909104811660009081526016602052604081208054898503019055908190819088166317e62b67826129788b613534565b6040516001600160e01b031960e085901b16815260048101929092526024820152604401606060405180830381865afa1580156129b9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129dd9190615cc5565b9250925092508280156129f857506001600160a01b03821630145b8015612a12575060008181526003602052604090205460ff165b612a4f5760405162461bcd60e51b815260206004820152600e60248201526d131417d08e8814995d995c9d195960921b6044820152606401610ebe565b612a836001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4816888b613da3565b6001600160e81b03198616336001600160a01b038a167f921c81c17e72f815c88a3e0fa28e7e709d56f0c5832e17b4bcc606dc9ee1a6118a8d612ac6818b615a65565b604080516001600160a01b03909416845260208401929092529082015260600160405180910390a45050600a54600e54612b159450909250600160781b90046001600160801b03169050613b49565b50505050565b60008181526003602052604081205481908190819060ff1615612b97575050600f54600192507f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4891507f000000000000000000000000d2a34731586bd10b645f870f4c9dcaf4f9e3823c90600160801b90046001600160601b03165b9193509193565b6000546001600160a01b03163314612bc85760405162461bcd60e51b8152600401610ebe90615a0b565b600e5461ffff82811691612bf091600160401b82041690600160281b900462ffffff16615c8d565b612bfa9190615ca9565b600e805469ffffffffff00000000001916600160281b62ffffff939093169290920269ffff0000000000000000191691909117600160401b61ffff8416908102919091179091556040519081527f553cb4d921add3331757ed1c44f851dcfab622fbc4975007ed008dce680ffe4790602001610f22565b604051632724fe0960e01b81526001600160a01b03828116600483015233917f00000000000000000000000000cb53780ea58503d3059fc02ddd596d0be926cb90911690632724fe0990602401602060405180830381865afa158015612cdb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cff9190615bc1565b6001600160a01b031614612d4b5760405162461bcd60e51b8152602060048201526013602482015272131417d0508e8815539055551213d492569151606a1b6044820152606401610ebe565b6001600160a01b0381811660008181526018602090815260408083203380855290835281842095891680855295835292819020879055518681529192917f9c3c3fddd897f6c3dce14f62fcc742f199fb00b47c0664b980cbdea1be127411910160405180910390a4505050565b60058054610f3a90615a31565b6000546001600160a01b03163314612def5760405162461bcd60e51b8152600401610ebe90615a0b565b6001600160a01b03831660009081526014602052604090205460ff1615612e505760405162461bcd60e51b815260206004820152601560248201527454525f41443a20416c72656164792065786973747360581b6044820152606401610ebe565b8161ffff16600e60058282829054906101000a900462ffffff16612e749190615ca9565b825462ffffff91821661010093840a90810290830219909116179092556011805460018101909155601081047f31ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c6801805461ffff8089166002600f9095169490940290940a838102908502199091161790556001600160a01b038716600090815260156020526040902055600e8054918516935091600a91612f1e918591600160501b900416615ca9565b825461010092830a62ffffff818102199092169290911602179091556012805460018181019092557fbb8a6a4669ba250d26cd7a459eca9d215f8307e33aebe50379bc5a3617ec344460108204018054600f90921660020290930a61ffff8181021990921691861602179091556013805480830182557f66de8ffda797e3de9c05e8fc57b3bf0ec28a930d40b0d285d93c06501cf6a0900180546001600160a01b0319166001600160a01b0388169081179091556000908152601460205260409020805460ff19168317905554612ff59250615a65565b60ff16836001600160a01b03167f5f77a2c0fccc0d2bdab612b4afae9f6108ce73d48f2ea671605aa7191aa60b58848460405161304392919061ffff92831681529116602082015260400190565b60405180910390a3505050565b6000546001600160a01b0316331461307a5760405162461bcd60e51b8152600401610ebe90615a0b565b60135482106130cb5760405162461bcd60e51b815260206004820152601c60248201527f54525f5349573a204e6f6e204578697374696e67205472616e636865000000006044820152606401610ebe565b8061ffff16601183815481106130e3576130e3615a78565b90600052602060002090601091828204019190066002029054906101000a900461ffff1661ffff16600e60059054906101000a900462ffffff166131279190615c8d565b6131319190615ca9565b600e60056101000a81548162ffffff021916908362ffffff160217905550806011838154811061316357613163615a78565b90600052602060002090601091828204019190066002026101000a81548161ffff021916908361ffff1602179055508061ffff1660156000601385815481106131ae576131ae615a78565b6000918252602080832091909101546001600160a01b03168352828101939093526040918201902092909255905161ffff8316815283917f7283d16027b080a3c9be9ae5695b23b19ef3e5066059566674e4680bacf3c8ca910161109b565b600154600160a01b900460ff16156132385760405163bbc5234f60e01b815260040160405180910390fd5b613240613876565b600061324b82613534565b9050600083821161325c578161325e565b835b90506132956001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4816333084613d19565b6132a0818485613bbb565b5060405181815233906001600160a01b038516907f05f2eeda0e08e4b437f487c8d7d29b14537d15e3488170dc3de5dbdf8dac46849060200160405180910390a35050600a54600e54611d109190600160781b90046001600160801b0316613b49565b6006546000908015610fdf57610fda61331a610e5d565b849083613858565b6000546001600160a01b0316331461334c5760405162461bcd60e51b8152600401610ebe90615a0b565b61159381613f15565b6000546001600160a01b0316331461337f5760405162461bcd60e51b8152600401610ebe90615a0b565b60135482106133d05760405162461bcd60e51b815260206004820152601c60248201527f54525f534c573a204e6f6e204578697374696e67205472616e636865000000006044820152606401610ebe565b8061ffff16601283815481106133e8576133e8615a78565b90600052602060002090601091828204019190066002029054906101000a900461ffff1661ffff16600e600a9054906101000a900462ffffff1661342c9190615c8d565b6134369190615ca9565b600e600a6101000a81548162ffffff021916908362ffffff160217905550806012838154811061346857613468615a78565b90600052602060002090601091828204019190066002026101000a81548161ffff021916908361ffff160217905550817fa0bb5ed3a1177ecbc7a7ee676d73ea48b239c9261b6e5b6d781c263e71f0b9018260405161109b919061ffff91909116815260200190565b6000611b9882613534565b6006546000908015610fdf57610fda816134f4610e5d565b859190613832565b60128181548110611ad057600080fd5b613514613876565b600a54600e5461179b9190600160781b90046001600160801b0316613b49565b6001600160a01b038116600090815260076020526040812054611b9890610fbb565b60405163ced4f63360e01b815260040160405180910390fd5b600c54600e54600091670de0b6b3a7640000908101916301e1338063ffffffff909116420382020490806135a38484613f27565b03600a5402816135b5576135b5615bf5565b0492506135c1836138bb565b6001600160801b03169250505090565b6000546001600160a01b031633146135fb5760405162461bcd60e51b8152600401610ebe90615a0b565b600f80546001600160801b0319166001600160801b0383169081179091556040519081527fb01769936feb4d3129c98c6f606578713d8b445ff96e0a744154ab58efb15e5090602001610f22565b6000611b98826134dc565b6000546001600160a01b0316331461367e5760405162461bcd60e51b8152600401610ebe90615a0b565b601080546001600160a01b03909216600160601b026001600160601b03909216919091179055565b6000546001600160a01b031633146136d05760405162461bcd60e51b8152600401610ebe90615a0b565b600080546001600160a01b0319166001600160a01b0383169081178255604051909133917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a350565b60025461372b9062278d006159f8565b42116137705760405162461bcd60e51b8152602060048201526014602482015273475f55503a2043616e6e6f7420756e506175736560601b6044820152606401610ebe565b600154600160a01b900460ff16806137915750600154600160a81b900460ff165b806137a55750600154600160b01b900460ff165b806137b95750600154600160b81b900460ff165b806137cd5750600154600160c01b900460ff165b1561179b576001805464ffffffffff60a01b19169055604080516000808252602082018190529181018290526060810182905260808101919091527f8502e0dfa7512c68fe07e3fd09dba9a9545c1e68fb13e18348da704c2fa7275e9060a00161264a565b600082600019048411830215820261384957600080fd5b50910281810615159190040190565b600082600019048411830215820261386f57600080fd5b5091020490565b600e544263ffffffff90811691161461179b57600061389361356f565b600e805463ffffffff19164263ffffffff16179055600a80548201905590506115938161409c565b6000600160801b82106138cd57600080fd5b5090565b60135460009081905b8015612b155780600190039050601381815481106138fa576138fa615a78565b60009182526020808320909101546001600160a01b03168083526016909152604090912054909350915081841015613950576001600160a01b038316600090815260166020526040902080548590039055612b15565b6001600160a01b03831660009081526016602052604081205561397381846141b4565b8184039350826001600160a01b031663f83d08ba6040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156139b357600080fd5b505af11580156139c7573d6000803e3d6000fd5b5050505080600014613a585760136139e0600183615a65565b815481106139f0576139f0615a78565b600091825260209091200154604051633dd217f760e21b8152600160048201526001600160a01b039091169063f7485fdc90602401600060405180830381600087803b158015613a3f57600080fd5b505af1158015613a53573d6000803e3d6000fd5b505050505b6138da565b80600080805b601354811015613b195760128181548110613a8057613a80615a78565b60009182526020909120601082040154600f9091166002026101000a900461ffff1691508115613b1157600e54613ac69086908490600160501b900462ffffff16613858565b9250826016600060138481548110613ae057613ae0615a78565b60009182526020808320909101546001600160a01b0316835282019290925260400190208054909101905592829003925b600101613a63565b50506010546001600160a01b03600160601b90910416600090815260166020526040902080549092019091555050565b60008115613b6c5781613b5f84620186a0615bde565b613b699190615c0b565b90505b7fe4cc9064635aa3e9263498b6ffb48bd2ad68b96a0e14efdbebc7d78590c682e0613b96826143b3565b600c8190556040516001600160501b03909116815260200160405180910390a1505050565b6000613bc684611003565b905080600003613c0c5760405162461bcd60e51b815260206004820152601160248201527044545f573a205a45524f5f53484152455360781b6044820152606401610ebe565b613c168282614435565b83600a6000828254613c289190615a65565b909155505060408051858152602081018390526001600160a01b03808516929086169133917ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db910160405180910390a49392505050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6004604051613cb19190615d08565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b60006040516323b872dd60e01b81528460048201528360248201528260448201526020600060648360008a5af13d15601f3d1160016000511416171691505080613d9c5760405162461bcd60e51b81526020600482015260146024820152731514905394d1915497d19493d357d1905253115160621b6044820152606401610ebe565b5050505050565b600060405163a9059cbb60e01b8152836004820152826024820152602060006044836000895af13d15601f3d1160016000511416171691505080612b155760405162461bcd60e51b815260206004820152600f60248201526e1514905394d1915497d19052531151608a1b6044820152606401610ebe565b6000613e2683613649565b600b549091506001600160801b031615613ea857600b546001600160801b031683613e5084613534565b613e5a91906159f8565b1115613ea85760405162461bcd60e51b815260206004820152601960248201527f44545f443a20424f52524f575f4341505f4558434545444544000000000000006044820152606401610ebe565b613eb282826144b1565b82600a6000828254613ec491906159f8565b909155505060408051848152602081018390526001600160a01b0384169133917fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7910160405180910390a392915050565b80600d613f228282615dc0565b505050565b600081600003613f405750670de0b6b3a7640000611b98565b82600003613f5057506000611b98565b613f61600160ff1b84106006614515565b82613f85613f7c68056bc75e2d63100000600160fe1b615c0b565b84106007614515565b82600082613fa367016345785d8a0000670de0b6b3a7640000615e82565b128015613fc85750613fc5670de0b6b3a764000067016345785d8a0000615ea2565b83125b15614031576000613fd884614523565b9050670de0b6b3a764000083613fee8284615eca565b613ff89190615ede565b6140029190615f0e565b83614015670de0b6b3a764000084615f0e565b61401f9190615ede565b6140299190615ea2565b915050614048565b8161403b8461475a565b6140459190615ede565b90505b61405a670de0b6b3a764000082615f0e565b905061408981680238fd42c5cf03ffff1913158015614082575068070c1cc73b00c800008213155b6008614515565b61409281614d40565b9695505050505050565b806000805b60135481101561414b576140f9601182815481106140c1576140c1615a78565b60009182526020909120601082040154600e548792600f166002026101000a90910461ffff1690600160281b900462ffffff16613858565b915081601660006013848154811061411357614113615a78565b60009182526020808320909101546001600160a01b0316835282019290925260400190208054909101905591819003916001016140a1565b50614155836138bb565b600e80546001600160801b03600160781b808304821690940116909202600160781b600160f81b0319909216919091179055506010546001600160a01b03600160601b9091041660009081526016602052604090208054909101905550565b601182815481106141c7576141c7615a78565b90600052602060002090601091828204019190066002029054906101000a900461ffff1661ffff16600e60058282829054906101000a900462ffffff1661420e9190615c8d565b92506101000a81548162ffffff021916908362ffffff1602179055506012828154811061423d5761423d615a78565b90600052602060002090601091828204019190066002029054906101000a900461ffff1661ffff16600e600a8282829054906101000a900462ffffff166142849190615c8d565b825462ffffff9182166101009390930a9283029190920219909116179055506001600160a01b0381166000908152601460205260409020805460ff1916905560118054806142d4576142d4615f3c565b600082815260209020601060001990920191820401805461ffff6002600f8516026101000a02191690559055601280548061431157614311615f3c565b600082815260209020601060001990920191820401805461ffff6002600f8516026101000a02191690559055601380548061434e5761434e615f3c565b6000828152602090819020600019908301810180546001600160a01b03191690559091019091556040516001600160a01b03831681527f14254003b9294c30e1b403adc733441503a0aecf4ff410885229833defef329a910160405180910390a15050565b600d54600090600160d81b900464ffffffffff1682106144115750600d54620186a0600160901b82046001600160481b03908116600160d81b840464ffffffffff169485900302600160481b84048216909402939093010491160190565b50600d54620186a06001600160481b03600160481b83048116939093020491160190565b6001600160a01b0382166000908152600760205260408120805483929061445d908490615a65565b90915550506006805482900390556040518181526000906001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906020015b60405180910390a35050565b80600660008282546144c391906159f8565b90915550506001600160a01b0382166000818152600760209081526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91016144a5565b81611d1057611d1081615377565b6000614537670de0b6b3a764000083615ede565b915060006145536a0c097ce7bc90715b34b9f160241b84615ea2565b6a0c097ce7bc90715b34b9f160241b61456c8186615e82565b6145769190615ede565b6145809190615f0e565b905060006a0c097ce7bc90715b34b9f160241b61459d8380615ede565b6145a79190615f0e565b905081806a0c097ce7bc90715b34b9f160241b6145c48483615ede565b6145ce9190615f0e565b91506145db600383615f0e565b6145e59082615ea2565b90506a0c097ce7bc90715b34b9f160241b6146008484615ede565b61460a9190615f0e565b9150614617600583615f0e565b6146219082615ea2565b90506a0c097ce7bc90715b34b9f160241b61463c8484615ede565b6146469190615f0e565b9150614653600783615f0e565b61465d9082615ea2565b90506a0c097ce7bc90715b34b9f160241b6146788484615ede565b6146829190615f0e565b915061468f600983615f0e565b6146999082615ea2565b90506a0c097ce7bc90715b34b9f160241b6146b48484615ede565b6146be9190615f0e565b91506146cb600b83615f0e565b6146d59082615ea2565b90506a0c097ce7bc90715b34b9f160241b6146f08484615ede565b6146fa9190615f0e565b9150614707600d83615f0e565b6147119082615ea2565b90506a0c097ce7bc90715b34b9f160241b61472c8484615ede565b6147369190615f0e565b9150614743600f83615f0e565b61474d9082615ea2565b9050614092816002615ede565b6000670de0b6b3a764000082121561479a5761479182614782670de0b6b3a764000080615ede565b61478c9190615f0e565b61475a565b611b9890615f52565b60006147c6670de0b6b3a7640000770195e54c5dd42177f53a27172fa9ec630262827000000000615ede565b8312614806576147ee770195e54c5dd42177f53a27172fa9ec63026282700000000084615f0e565b92506148036806f05b59d3b200000082615ea2565b90505b614824670de0b6b3a76400006b1425982cf597cd205cef7380615ede565b8312614858576148406b1425982cf597cd205cef738084615f0e565b92506148556803782dace9d900000082615ea2565b90505b614863606482615ede565b9050614870606484615ede565b92506e01855144814a7ff805980ff008400083126148cd576e01855144814a7ff805980ff00840006148ab68056bc75e2d6310000085615ede565b6148b59190615f0e565b92506148ca68ad78ebc5ac6200000082615ea2565b90505b6b02df0ab5a80a22c61ab5a7008312614922576b02df0ab5a80a22c61ab5a70061490068056bc75e2d6310000085615ede565b61490a9190615f0e565b925061491f6856bc75e2d63100000082615ea2565b90505b693f1fce3da636ea5cf850831261497357693f1fce3da636ea5cf85061495168056bc75e2d6310000085615ede565b61495b9190615f0e565b9250614970682b5e3af16b1880000082615ea2565b90505b690127fa27722cc06cc5e283126149c457690127fa27722cc06cc5e26149a268056bc75e2d6310000085615ede565b6149ac9190615f0e565b92506149c16815af1d78b58c40000082615ea2565b90505b68280e60114edb805d038312614a135768280e60114edb805d036149f168056bc75e2d6310000085615ede565b6149fb9190615f0e565b9250614a10680ad78ebc5ac620000082615ea2565b90505b680ebc5fb417461211108312614a6257680ebc5fb41746121110614a4068056bc75e2d6310000085615ede565b614a4a9190615f0e565b9250614a5f68056bc75e2d6310000082615ea2565b90505b6808f00f760a4b2db55d8312614ab1576808f00f760a4b2db55d614a8f68056bc75e2d6310000085615ede565b614a999190615f0e565b9250614aae6802b5e3af16b188000082615ea2565b90505b6806f5f17757889379378312614b00576806f5f1775788937937614ade68056bc75e2d6310000085615ede565b614ae89190615f0e565b9250614afd68015af1d78b58c4000082615ea2565b90505b6806248f33704b2866038312614b4e576806248f33704b286603614b2d68056bc75e2d6310000085615ede565b614b379190615f0e565b9250614b4b67ad78ebc5ac62000082615ea2565b90505b6805c548670b9510e7ac8312614b9c576805c548670b9510e7ac614b7b68056bc75e2d6310000085615ede565b614b859190615f0e565b9250614b996756bc75e2d631000082615ea2565b90505b6000614bb168056bc75e2d6310000085615ea2565b68056bc75e2d63100000614bc58187615e82565b614bcf9190615ede565b614bd99190615f0e565b9050600068056bc75e2d63100000614bf18380615ede565b614bfb9190615f0e565b9050818068056bc75e2d63100000614c138483615ede565b614c1d9190615f0e565b9150614c2a600383615f0e565b614c349082615ea2565b905068056bc75e2d63100000614c4a8484615ede565b614c549190615f0e565b9150614c61600583615f0e565b614c6b9082615ea2565b905068056bc75e2d63100000614c818484615ede565b614c8b9190615f0e565b9150614c98600783615f0e565b614ca29082615ea2565b905068056bc75e2d63100000614cb88484615ede565b614cc29190615f0e565b9150614ccf600983615f0e565b614cd99082615ea2565b905068056bc75e2d63100000614cef8484615ede565b614cf99190615f0e565b9150614d06600b83615f0e565b614d109082615ea2565b9050614d1d600282615ede565b90506064614d2b8287615ea2565b614d359190615f0e565b979650505050505050565b6000614d6f680238fd42c5cf03ffff198312158015614d68575068070c1cc73b00c800008313155b6009614515565b6000821215614da557614d89614d8483615f52565b614d40565b614d9b670de0b6b3a764000080615ede565b611b989190615f0e565b60006806f05b59d3b20000008312614dec57614dca6806f05b59d3b200000084615e82565b9250770195e54c5dd42177f53a27172fa9ec6302628270000000009050614e29565b6803782dace9d90000008312614e2557614e0f6803782dace9d900000084615e82565b92506b1425982cf597cd205cef73809050614e29565b5060015b614e34606484615ede565b925068056bc75e2d6310000068ad78ebc5ac620000008412614e9557614e6368ad78ebc5ac6200000085615e82565b935068056bc75e2d63100000614e886e01855144814a7ff805980ff008400083615ede565b614e929190615f0e565b90505b6856bc75e2d6310000008412614ee757614eb86856bc75e2d63100000085615e82565b935068056bc75e2d63100000614eda6b02df0ab5a80a22c61ab5a70083615ede565b614ee49190615f0e565b90505b682b5e3af16b188000008412614f3757614f0a682b5e3af16b1880000085615e82565b935068056bc75e2d63100000614f2a693f1fce3da636ea5cf85083615ede565b614f349190615f0e565b90505b6815af1d78b58c4000008412614f8757614f5a6815af1d78b58c40000085615e82565b935068056bc75e2d63100000614f7a690127fa27722cc06cc5e283615ede565b614f849190615f0e565b90505b680ad78ebc5ac62000008412614fd657614faa680ad78ebc5ac620000085615e82565b935068056bc75e2d63100000614fc968280e60114edb805d0383615ede565b614fd39190615f0e565b90505b68056bc75e2d63100000841261502557614ff968056bc75e2d6310000085615e82565b935068056bc75e2d63100000615018680ebc5fb4174612111083615ede565b6150229190615f0e565b90505b6802b5e3af16b18800008412615074576150486802b5e3af16b188000085615e82565b935068056bc75e2d631000006150676808f00f760a4b2db55d83615ede565b6150719190615f0e565b90505b68015af1d78b58c4000084126150c35761509768015af1d78b58c4000085615e82565b935068056bc75e2d631000006150b66806f5f177578893793783615ede565b6150c09190615f0e565b90505b68056bc75e2d63100000846150d88183615ea2565b9150600268056bc75e2d631000006150f08884615ede565b6150fa9190615f0e565b6151049190615f0e565b90506151108183615ea2565b9150600368056bc75e2d631000006151288884615ede565b6151329190615f0e565b61513c9190615f0e565b90506151488183615ea2565b9150600468056bc75e2d631000006151608884615ede565b61516a9190615f0e565b6151749190615f0e565b90506151808183615ea2565b9150600568056bc75e2d631000006151988884615ede565b6151a29190615f0e565b6151ac9190615f0e565b90506151b88183615ea2565b9150600668056bc75e2d631000006151d08884615ede565b6151da9190615f0e565b6151e49190615f0e565b90506151f08183615ea2565b9150600768056bc75e2d631000006152088884615ede565b6152129190615f0e565b61521c9190615f0e565b90506152288183615ea2565b9150600868056bc75e2d631000006152408884615ede565b61524a9190615f0e565b6152549190615f0e565b90506152608183615ea2565b9150600968056bc75e2d631000006152788884615ede565b6152829190615f0e565b61528c9190615f0e565b90506152988183615ea2565b9150600a68056bc75e2d631000006152b08884615ede565b6152ba9190615f0e565b6152c49190615f0e565b90506152d08183615ea2565b9150600b68056bc75e2d631000006152e88884615ede565b6152f29190615f0e565b6152fc9190615f0e565b90506153088183615ea2565b9150600c68056bc75e2d631000006153208884615ede565b61532a9190615f0e565b6153349190615f0e565b90506153408183615ea2565b915060648468056bc75e2d631000006153598587615ede565b6153639190615f0e565b61536d9190615ede565b6140929190615f0e565b6030600a820601600a820491506030600a830601600a830492506030600a8406018060101b8260081b8401016642414c230000000160c81b9250505062461bcd60e51b600052602060045260076024528060445260646000fd5b6000602082840312156153e357600080fd5b81356001600160601b0381168114610fe157600080fd5b600060208083528351808285015260005b818110156154275785810183015185820160400152820161540b565b506000604082860101526040601f19601f8301168501019250505092915050565b60006020828403121561545a57600080fd5b5035919050565b6001600160a01b038116811461159357600080fd5b6000806040838503121561548957600080fd5b823561549481615461565b946020939093013593505050565b801515811461159357600080fd5b600080604083850312156154c357600080fd5b8235915060208301356154d5816154a2565b809150509250929050565b60008060008060008060c087890312156154f957600080fd5b863561550481615461565b9550602087013561551481615461565b95989597505050506040840135936060810135936080820135935060a0909101359150565b60006020828403121561554b57600080fd5b8135610fe181615461565b60006020828403121561556857600080fd5b81356001600160801b0381168114610fe157600080fd5b803560ff81168114611b8857600080fd5b6000602082840312156155a257600080fd5b610fe18261557f565b6000806000606084860312156155c057600080fd5b83356155cb81615461565b925060208401356155db81615461565b929592945050506040919091013590565b600080600080600060a0868803121561560457600080fd5b853561560f816154a2565b9450602086013561561f816154a2565b9350604086013561562f816154a2565b9250606086013561563f816154a2565b9150608086013561564f816154a2565b809150509295509295909350565b6000806040838503121561567057600080fd5b8235915060208301356154d581615461565b60006020828403121561569457600080fd5b81356001600160501b0381168114610fe157600080fd5b600080604083850312156156be57600080fd5b50508035926020909101359150565b80356001600160e81b031981168114611b8857600080fd5b60008060008060008060a087890312156156fe57600080fd5b86359550602087013561571081615461565b9450604087013561572081615461565b9350606087013567ffffffffffffffff8082111561573d57600080fd5b818901915089601f83011261575157600080fd5b81358181111561576057600080fd5b8a602082850101111561577257600080fd5b60208301955080945050505061578a608088016156cd565b90509295509295509295565b803561ffff81168114611b8857600080fd5b6000602082840312156157ba57600080fd5b610fe182615796565b600080600080608085870312156157d957600080fd5b8435935060208501356157eb81615461565b925060408501356157fb81615461565b9150615809606086016156cd565b905092959194509250565b60008060006060848603121561582957600080fd5b833561583481615461565b925060208401359150604084013561584b81615461565b809150509250925092565b60008060006060848603121561586b57600080fd5b833561587681615461565b925061588460208501615796565b915061589260408501615796565b90509250925092565b600080604083850312156158ae57600080fd5b823591506158be60208401615796565b90509250929050565b6000806000606084860312156158dc57600080fd5b8335925060208401356158ee81615461565b9150604084013561584b81615461565b60008060006060848603121561591357600080fd5b833561591e81615461565b925060208401356158ee81615461565b60006080828403121561594057600080fd5b50919050565b600080600080600080600060e0888a03121561596157600080fd5b873561596c81615461565b9650602088013561597c81615461565b955060408801359450606088013593506159986080890161557f565b925060a0880135915060c0880135905092959891949750929550565b600080604083850312156159c757600080fd5b82356159d281615461565b915060208301356154d581615461565b634e487b7160e01b600052601160045260246000fd5b80820180821115611b9857611b986159e2565b6020808252600c908201526b15539055551213d49256915160a21b604082015260600190565b600181811c90821680615a4557607f821691505b60208210810361594057634e487b7160e01b600052602260045260246000fd5b81810381811115611b9857611b986159e2565b634e487b7160e01b600052603260045260246000fd5b600060208284031215615aa057600080fd5b5051919050565b6001600160801b03828116828216039080821115615ac757615ac76159e2565b5092915050565b600181815b80851115615b09578160001904821115615aef57615aef6159e2565b80851615615afc57918102915b93841c9390800290615ad3565b509250929050565b600082615b2057506001611b98565b81615b2d57506000611b98565b8160018114615b435760028114615b4d57615b69565b6001915050611b98565b60ff841115615b5e57615b5e6159e2565b50506001821b611b98565b5060208310610133831016604e8410600b8410161715615b8c575081810a611b98565b615b968383615ace565b8060001904821115615baa57615baa6159e2565b029392505050565b6000610fe160ff841683615b11565b600060208284031215615bd357600080fd5b8151610fe181615461565b8082028115828204841417611b9857611b986159e2565b634e487b7160e01b600052601260045260246000fd5b600082615c1a57615c1a615bf5565b500490565b6001600160a01b03841681526040602082018190528101829052818360608301376000818301606090810191909152601f909201601f1916010192915050565b60008060408385031215615c7257600080fd5b8251615c7d81615461565b6020939093015192949293505050565b62ffffff828116828216039080821115615ac757615ac76159e2565b62ffffff818116838216019080821115615ac757615ac76159e2565b600080600060608486031215615cda57600080fd5b8351615ce5816154a2565b6020850151909350615cf681615461565b80925050604084015190509250925092565b600080835481600182811c915080831680615d2457607f831692505b60208084108203615d4357634e487b7160e01b86526022600452602486fd5b818015615d575760018114615d6c57615d99565b60ff1986168952841515850289019650615d99565b60008a81526020902060005b86811015615d915781548b820152908501908301615d78565b505084890196505b509498975050505050505050565b600081356001600160481b0381168114611b9857600080fd5b6001600160481b03615dd183615da7565b168154816001600160481b0319821617835571ffffffffffffffffff000000000000000000615e0260208601615da7565b60481b16808371ffffffffffffffffffffffffffffffffffff198416171784556001600160481b0360901b615e3960408701615da7565b60901b1664ffffffffff60d81b81858286161784171786556060870135935064ffffffffff84168414615e6b57600080fd5b808460d81b16858417831717865550505050505050565b8181036000831280158383131683831282161715615ac757615ac76159e2565b8082018281126000831280158216821582161715615ec257615ec26159e2565b505092915050565b600082615ed957615ed9615bf5565b500790565b80820260008212600160ff1b84141615615efa57615efa6159e2565b8181058314821517611b9857611b986159e2565b600082615f1d57615f1d615bf5565b600160ff1b821460001984141615615f3757615f376159e2565b500590565b634e487b7160e01b600052603160045260246000fd5b6000600160ff1b8201615f6757615f676159e2565b506000039056fea26469706673582212209780f6277341e8b0493529fdc95bb4bd714f1a96ebea72b6e1cf82e72de3d42c64736f6c63430008110033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000beb56fbef3387af554a554e7db25830eb7b92e3200000000000000000000000000cb53780ea58503d3059fc02ddd596d0be926cb000000000000000000000000d2a34731586bd10b645f870f4c9dcaf4f9e3823c
-----Decoded View---------------
Arg [0] : asset_ (address): 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48
Arg [1] : treasury_ (address): 0xBEB56fbEf3387af554A554E7DB25830eB7b92e32
Arg [2] : vaultFactory_ (address): 0x00CB53780Ea58503D3059FC02dDd596D0Be926cB
Arg [3] : liquidator_ (address): 0xD2A34731586bD10B645f870f4C9DcAF4F9e3823C
-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48
Arg [1] : 000000000000000000000000beb56fbef3387af554a554e7db25830eb7b92e32
Arg [2] : 00000000000000000000000000cb53780ea58503d3059fc02ddd596d0be926cb
Arg [3] : 000000000000000000000000d2a34731586bd10b645f870f4c9dcaf4f9e3823c
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|---|---|---|---|---|
ETH | 100.00% | $0.999379 | 1,161.1866 | $1,160.47 |
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.