Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
TranchingLogic
Compiler Version
v0.6.12+commit.27d51765
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity 0.6.12; pragma experimental ABIEncoderV2; import "../../interfaces/IV2CreditLine.sol"; import "../../interfaces/ITranchedPool.sol"; import "../../interfaces/IPoolTokens.sol"; import "../../external/FixedPoint.sol"; import "@openzeppelin/contracts-ethereum-package/contracts/math/Math.sol"; import "@openzeppelin/contracts-ethereum-package/contracts/math/SafeMath.sol"; /** * @title TranchingLogic * @notice Library for handling the payments waterfall * @author Goldfinch */ library TranchingLogic { using SafeMath for uint256; using FixedPoint for FixedPoint.Unsigned; using FixedPoint for uint256; event SharePriceUpdated( address indexed pool, uint256 indexed tranche, uint256 principalSharePrice, int256 principalDelta, uint256 interestSharePrice, int256 interestDelta ); uint256 public constant FP_SCALING_FACTOR = 1e18; uint256 public constant ONE_HUNDRED = 100; // Need this because we cannot call .div on a literal 100 function usdcToSharePrice(uint256 amount, uint256 totalShares) public pure returns (uint256) { return totalShares == 0 ? 0 : amount.mul(FP_SCALING_FACTOR).div(totalShares); } function sharePriceToUsdc(uint256 sharePrice, uint256 totalShares) public pure returns (uint256) { return sharePrice.mul(totalShares).div(FP_SCALING_FACTOR); } function redeemableInterestAndPrincipal( ITranchedPool.TrancheInfo storage trancheInfo, IPoolTokens.TokenInfo memory tokenInfo ) public view returns (uint256 interestRedeemable, uint256 principalRedeemable) { // This supports withdrawing before or after locking because principal share price starts at 1 // and is set to 0 on lock. Interest share price is always 0 until interest payments come back, when it increases uint256 maxPrincipalRedeemable = sharePriceToUsdc(trancheInfo.principalSharePrice, tokenInfo.principalAmount); // The principalAmount is used as the totalShares because we want the interestSharePrice to be expressed as a // percent of total loan value e.g. if the interest is 10% APR, the interestSharePrice should approach a max of 0.1. uint256 maxInterestRedeemable = sharePriceToUsdc(trancheInfo.interestSharePrice, tokenInfo.principalAmount); interestRedeemable = maxInterestRedeemable.sub(tokenInfo.interestRedeemed); principalRedeemable = maxPrincipalRedeemable.sub(tokenInfo.principalRedeemed); return (interestRedeemable, principalRedeemable); } function calculateExpectedSharePrice( ITranchedPool.TrancheInfo memory tranche, uint256 amount, ITranchedPool.PoolSlice memory slice ) public pure returns (uint256) { uint256 sharePrice = usdcToSharePrice(amount, tranche.principalDeposited); return scaleByPercentOwnership(tranche, sharePrice, slice); } function scaleForSlice( ITranchedPool.PoolSlice memory slice, uint256 amount, uint256 totalDeployed ) public pure returns (uint256) { return scaleByFraction(amount, slice.principalDeployed, totalDeployed); } // We need to create this struct so we don't run into a stack too deep error due to too many variables function getSliceInfo( ITranchedPool.PoolSlice memory slice, IV2CreditLine creditLine, uint256 totalDeployed, uint256 reserveFeePercent ) public view returns (ITranchedPool.SliceInfo memory) { (uint256 interestAccrued, uint256 principalAccrued) = getTotalInterestAndPrincipal( slice, creditLine, totalDeployed ); return ITranchedPool.SliceInfo({ reserveFeePercent: reserveFeePercent, interestAccrued: interestAccrued, principalAccrued: principalAccrued }); } function getTotalInterestAndPrincipal( ITranchedPool.PoolSlice memory slice, IV2CreditLine creditLine, uint256 totalDeployed ) public view returns (uint256 interestAccrued, uint256 principalAccrued) { principalAccrued = creditLine.principalOwed(); // In addition to principal actually owed, we need to account for early principal payments // If the borrower pays back 5K early on a 10K loan, the actual principal accrued should be // 5K (balance- deployed) + 0 (principal owed) principalAccrued = totalDeployed.sub(creditLine.balance()).add(principalAccrued); // Now we need to scale that correctly for the slice we're interested in principalAccrued = scaleForSlice(slice, principalAccrued, totalDeployed); // Finally, we need to account for partial drawdowns. e.g. If 20K was deposited, and only 10K was drawn down, // Then principal accrued should start at 10K (total deposited - principal deployed), not 0. This is because // share price starts at 1, and is decremented by what was drawn down. uint256 totalDeposited = slice.seniorTranche.principalDeposited.add(slice.juniorTranche.principalDeposited); principalAccrued = totalDeposited.sub(slice.principalDeployed).add(principalAccrued); return (slice.totalInterestAccrued, principalAccrued); } function scaleByFraction( uint256 amount, uint256 fraction, uint256 total ) public pure returns (uint256) { FixedPoint.Unsigned memory totalAsFixedPoint = FixedPoint.fromUnscaledUint(total); FixedPoint.Unsigned memory fractionAsFixedPoint = FixedPoint.fromUnscaledUint(fraction); return fractionAsFixedPoint.div(totalAsFixedPoint).mul(amount).div(FP_SCALING_FACTOR).rawValue; } function applyToAllSeniorTranches( ITranchedPool.PoolSlice[] storage poolSlices, uint256 interest, uint256 principal, uint256 reserveFeePercent, uint256 totalDeployed, IV2CreditLine creditLine, uint256 juniorFeePercent ) public returns (ITranchedPool.ApplyResult memory) { ITranchedPool.ApplyResult memory seniorApplyResult; for (uint256 i = 0; i < poolSlices.length; i++) { ITranchedPool.SliceInfo memory sliceInfo = getSliceInfo( poolSlices[i], creditLine, totalDeployed, reserveFeePercent ); // Since slices cannot be created when the loan is late, all interest collected can be assumed to split // pro-rata across the slices. So we scale the interest and principal to the slice ITranchedPool.ApplyResult memory applyResult = applyToSeniorTranche( poolSlices[i], scaleForSlice(poolSlices[i], interest, totalDeployed), scaleForSlice(poolSlices[i], principal, totalDeployed), juniorFeePercent, sliceInfo ); emitSharePriceUpdatedEvent(poolSlices[i].seniorTranche, applyResult); seniorApplyResult.interestRemaining = seniorApplyResult.interestRemaining.add(applyResult.interestRemaining); seniorApplyResult.principalRemaining = seniorApplyResult.principalRemaining.add(applyResult.principalRemaining); seniorApplyResult.reserveDeduction = seniorApplyResult.reserveDeduction.add(applyResult.reserveDeduction); } return seniorApplyResult; } function applyToAllJuniorTranches( ITranchedPool.PoolSlice[] storage poolSlices, uint256 interest, uint256 principal, uint256 reserveFeePercent, uint256 totalDeployed, IV2CreditLine creditLine ) public returns (uint256 totalReserveAmount) { for (uint256 i = 0; i < poolSlices.length; i++) { ITranchedPool.SliceInfo memory sliceInfo = getSliceInfo( poolSlices[i], creditLine, totalDeployed, reserveFeePercent ); // Any remaining interest and principal is then shared pro-rata with the junior slices ITranchedPool.ApplyResult memory applyResult = applyToJuniorTranche( poolSlices[i], scaleForSlice(poolSlices[i], interest, totalDeployed), scaleForSlice(poolSlices[i], principal, totalDeployed), sliceInfo ); emitSharePriceUpdatedEvent(poolSlices[i].juniorTranche, applyResult); totalReserveAmount = totalReserveAmount.add(applyResult.reserveDeduction); } return totalReserveAmount; } function emitSharePriceUpdatedEvent( ITranchedPool.TrancheInfo memory tranche, ITranchedPool.ApplyResult memory applyResult ) internal { emit SharePriceUpdated( address(this), tranche.id, tranche.principalSharePrice, int256(tranche.principalSharePrice.sub(applyResult.oldPrincipalSharePrice)), tranche.interestSharePrice, int256(tranche.interestSharePrice.sub(applyResult.oldInterestSharePrice)) ); } function applyToSeniorTranche( ITranchedPool.PoolSlice storage slice, uint256 interestRemaining, uint256 principalRemaining, uint256 juniorFeePercent, ITranchedPool.SliceInfo memory sliceInfo ) public returns (ITranchedPool.ApplyResult memory) { // First determine the expected share price for the senior tranche. This is the gross amount the senior // tranche should receive. uint256 expectedInterestSharePrice = calculateExpectedSharePrice( slice.seniorTranche, sliceInfo.interestAccrued, slice ); uint256 expectedPrincipalSharePrice = calculateExpectedSharePrice( slice.seniorTranche, sliceInfo.principalAccrued, slice ); // Deduct the junior fee and the protocol reserve uint256 desiredNetInterestSharePrice = scaleByFraction( expectedInterestSharePrice, ONE_HUNDRED.sub(juniorFeePercent.add(sliceInfo.reserveFeePercent)), ONE_HUNDRED ); // Collect protocol fee interest received (we've subtracted this from the senior portion above) uint256 reserveDeduction = scaleByFraction(interestRemaining, sliceInfo.reserveFeePercent, ONE_HUNDRED); interestRemaining = interestRemaining.sub(reserveDeduction); uint256 oldInterestSharePrice = slice.seniorTranche.interestSharePrice; uint256 oldPrincipalSharePrice = slice.seniorTranche.principalSharePrice; // Apply the interest remaining so we get up to the netInterestSharePrice (interestRemaining, principalRemaining) = applyBySharePrice( slice.seniorTranche, interestRemaining, principalRemaining, desiredNetInterestSharePrice, expectedPrincipalSharePrice ); return ITranchedPool.ApplyResult({ interestRemaining: interestRemaining, principalRemaining: principalRemaining, reserveDeduction: reserveDeduction, oldInterestSharePrice: oldInterestSharePrice, oldPrincipalSharePrice: oldPrincipalSharePrice }); } function applyToJuniorTranche( ITranchedPool.PoolSlice storage slice, uint256 interestRemaining, uint256 principalRemaining, ITranchedPool.SliceInfo memory sliceInfo ) public returns (ITranchedPool.ApplyResult memory) { // Then fill up the junior tranche with all the interest remaining, upto the principal share price uint256 expectedInterestSharePrice = slice.juniorTranche.interestSharePrice.add( usdcToSharePrice(interestRemaining, slice.juniorTranche.principalDeposited) ); uint256 expectedPrincipalSharePrice = calculateExpectedSharePrice( slice.juniorTranche, sliceInfo.principalAccrued, slice ); uint256 oldInterestSharePrice = slice.juniorTranche.interestSharePrice; uint256 oldPrincipalSharePrice = slice.juniorTranche.principalSharePrice; (interestRemaining, principalRemaining) = applyBySharePrice( slice.juniorTranche, interestRemaining, principalRemaining, expectedInterestSharePrice, expectedPrincipalSharePrice ); // All remaining interest and principal is applied towards the junior tranche as interest interestRemaining = interestRemaining.add(principalRemaining); // Since any principal remaining is treated as interest (there is "extra" interest to be distributed) // we need to make sure to collect the protocol fee on the additional interest (we only deducted the // fee on the original interest portion) uint256 reserveDeduction = scaleByFraction(principalRemaining, sliceInfo.reserveFeePercent, ONE_HUNDRED); interestRemaining = interestRemaining.sub(reserveDeduction); principalRemaining = 0; (interestRemaining, principalRemaining) = applyByAmount( slice.juniorTranche, interestRemaining.add(principalRemaining), 0, interestRemaining.add(principalRemaining), 0 ); return ITranchedPool.ApplyResult({ interestRemaining: interestRemaining, principalRemaining: principalRemaining, reserveDeduction: reserveDeduction, oldInterestSharePrice: oldInterestSharePrice, oldPrincipalSharePrice: oldPrincipalSharePrice }); } function applyBySharePrice( ITranchedPool.TrancheInfo storage tranche, uint256 interestRemaining, uint256 principalRemaining, uint256 desiredInterestSharePrice, uint256 desiredPrincipalSharePrice ) public returns (uint256, uint256) { uint256 desiredInterestAmount = desiredAmountFromSharePrice( desiredInterestSharePrice, tranche.interestSharePrice, tranche.principalDeposited ); uint256 desiredPrincipalAmount = desiredAmountFromSharePrice( desiredPrincipalSharePrice, tranche.principalSharePrice, tranche.principalDeposited ); return applyByAmount(tranche, interestRemaining, principalRemaining, desiredInterestAmount, desiredPrincipalAmount); } function applyByAmount( ITranchedPool.TrancheInfo storage tranche, uint256 interestRemaining, uint256 principalRemaining, uint256 desiredInterestAmount, uint256 desiredPrincipalAmount ) public returns (uint256, uint256) { uint256 totalShares = tranche.principalDeposited; uint256 newSharePrice; (interestRemaining, newSharePrice) = applyToSharePrice( interestRemaining, tranche.interestSharePrice, desiredInterestAmount, totalShares ); tranche.interestSharePrice = newSharePrice; (principalRemaining, newSharePrice) = applyToSharePrice( principalRemaining, tranche.principalSharePrice, desiredPrincipalAmount, totalShares ); tranche.principalSharePrice = newSharePrice; return (interestRemaining, principalRemaining); } function migrateAccountingVariables(address originalClAddr, address newClAddr) public { IV2CreditLine originalCl = IV2CreditLine(originalClAddr); IV2CreditLine newCl = IV2CreditLine(newClAddr); // Copy over all accounting variables newCl.setBalance(originalCl.balance()); newCl.setLimit(originalCl.limit()); newCl.setInterestOwed(originalCl.interestOwed()); newCl.setPrincipalOwed(originalCl.principalOwed()); newCl.setTermEndTime(originalCl.termEndTime()); newCl.setNextDueTime(originalCl.nextDueTime()); newCl.setInterestAccruedAsOf(originalCl.interestAccruedAsOf()); newCl.setLastFullPaymentTime(originalCl.lastFullPaymentTime()); newCl.setTotalInterestAccrued(originalCl.totalInterestAccrued()); } function closeCreditLine(address originalCl) public { // Close out old CL IV2CreditLine oldCreditLine = IV2CreditLine(originalCl); oldCreditLine.setBalance(0); oldCreditLine.setLimit(0); oldCreditLine.setMaxLimit(0); } function desiredAmountFromSharePrice( uint256 desiredSharePrice, uint256 actualSharePrice, uint256 totalShares ) public pure returns (uint256) { // If the desired share price is lower, then ignore it, and leave it unchanged if (desiredSharePrice < actualSharePrice) { desiredSharePrice = actualSharePrice; } uint256 sharePriceDifference = desiredSharePrice.sub(actualSharePrice); return sharePriceToUsdc(sharePriceDifference, totalShares); } function applyToSharePrice( uint256 amountRemaining, uint256 currentSharePrice, uint256 desiredAmount, uint256 totalShares ) public pure returns (uint256, uint256) { // If no money left to apply, or don't need any changes, return the original amounts if (amountRemaining == 0 || desiredAmount == 0) { return (amountRemaining, currentSharePrice); } if (amountRemaining < desiredAmount) { // We don't have enough money to adjust share price to the desired level. So just use whatever amount is left desiredAmount = amountRemaining; } uint256 sharePriceDifference = usdcToSharePrice(desiredAmount, totalShares); return (amountRemaining.sub(desiredAmount), currentSharePrice.add(sharePriceDifference)); } function scaleByPercentOwnership( ITranchedPool.TrancheInfo memory tranche, uint256 amount, ITranchedPool.PoolSlice memory slice ) public pure returns (uint256) { uint256 totalDeposited = slice.juniorTranche.principalDeposited.add(slice.seniorTranche.principalDeposited); return scaleByFraction(amount, tranche.principalDeposited, totalDeposited); } }
pragma solidity ^0.6.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
pragma solidity ^0.6.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a >= b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow, so we distribute return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2); } }
pragma solidity ^0.6.0; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { return sub(a, b, "SafeMath: subtraction overflow"); } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); uint256 c = a - b; return c; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers. Reverts on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { return div(a, b, "SafeMath: division by zero"); } /** * @dev Returns the integer division of two unsigned integers. Reverts with custom message on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { // Solidity only automatically asserts when dividing by 0 require(b > 0, errorMessage); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { return mod(a, b, "SafeMath: modulo by zero"); } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts with custom message when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } }
pragma solidity ^0.6.0; /** * @title SignedSafeMath * @dev Signed math operations with safety checks that revert on error. */ library SignedSafeMath { int256 constant private _INT256_MIN = -2**255; /** * @dev Multiplies two signed integers, reverts on overflow. */ function mul(int256 a, int256 b) internal pure returns (int256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) { return 0; } require(!(a == -1 && b == _INT256_MIN), "SignedSafeMath: multiplication overflow"); int256 c = a * b; require(c / a == b, "SignedSafeMath: multiplication overflow"); return c; } /** * @dev Integer division of two signed integers truncating the quotient, reverts on division by zero. */ function div(int256 a, int256 b) internal pure returns (int256) { require(b != 0, "SignedSafeMath: division by zero"); require(!(b == -1 && a == _INT256_MIN), "SignedSafeMath: division overflow"); int256 c = a / b; return c; } /** * @dev Subtracts two signed integers, reverts on overflow. */ function sub(int256 a, int256 b) internal pure returns (int256) { int256 c = a - b; require((b >= 0 && c <= a) || (b < 0 && c > a), "SignedSafeMath: subtraction overflow"); return c; } /** * @dev Adds two signed integers, reverts on overflow. */ function add(int256 a, int256 b) internal pure returns (int256) { int256 c = a + b; require((b >= 0 && c >= a) || (b < 0 && c < a), "SignedSafeMath: addition overflow"); return c; } }
pragma solidity ^0.6.2; import "../../introspection/IERC165.sol"; /** * @dev Required interface of an ERC721 compliant contract. */ interface IERC721 is IERC165 { event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of NFTs in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the NFT specified by `tokenId`. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Transfers a specific NFT (`tokenId`) from one account (`from`) to * another (`to`). * * * * Requirements: * - `from`, `to` cannot be zero. * - `tokenId` must be owned by `from`. * - If the caller is not `from`, it must be have been allowed to move this * NFT by either {approve} or {setApprovalForAll}. */ function safeTransferFrom(address from, address to, uint256 tokenId) external; /** * @dev Transfers a specific NFT (`tokenId`) from one account (`from`) to * another (`to`). * * Requirements: * - If the caller is not `from`, it must be approved to move this NFT by * either {approve} or {setApprovalForAll}. */ function transferFrom(address from, address to, uint256 tokenId) external; function approve(address to, uint256 tokenId) external; function getApproved(uint256 tokenId) external view returns (address operator); function setApprovalForAll(address operator, bool _approved) external; function isApprovedForAll(address owner, address operator) external view returns (bool); function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external; }
// SPDX-License-Identifier: AGPL-3.0-only // solhint-disable // Imported from https://github.com/UMAprotocol/protocol/blob/4d1c8cc47a4df5e79f978cb05647a7432e111a3d/packages/core/contracts/common/implementation/FixedPoint.sol pragma solidity 0.6.12; pragma experimental ABIEncoderV2; import "@openzeppelin/contracts-ethereum-package/contracts/math/SafeMath.sol"; import "@openzeppelin/contracts-ethereum-package/contracts/math/SignedSafeMath.sol"; /** * @title Library for fixed point arithmetic on uints */ library FixedPoint { using SafeMath for uint256; using SignedSafeMath for int256; // Supports 18 decimals. E.g., 1e18 represents "1", 5e17 represents "0.5". // For unsigned values: // This can represent a value up to (2^256 - 1)/10^18 = ~10^59. 10^59 will be stored internally as uint256 10^77. uint256 private constant FP_SCALING_FACTOR = 10**18; // --------------------------------------- UNSIGNED ----------------------------------------------------------------------------- struct Unsigned { uint256 rawValue; } /** * @notice Constructs an `Unsigned` from an unscaled uint, e.g., `b=5` gets stored internally as `5**18`. * @param a uint to convert into a FixedPoint. * @return the converted FixedPoint. */ function fromUnscaledUint(uint256 a) internal pure returns (Unsigned memory) { return Unsigned(a.mul(FP_SCALING_FACTOR)); } /** * @notice Whether `a` is equal to `b`. * @param a a FixedPoint. * @param b a uint256. * @return True if equal, or False. */ function isEqual(Unsigned memory a, uint256 b) internal pure returns (bool) { return a.rawValue == fromUnscaledUint(b).rawValue; } /** * @notice Whether `a` is equal to `b`. * @param a a FixedPoint. * @param b a FixedPoint. * @return True if equal, or False. */ function isEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) { return a.rawValue == b.rawValue; } /** * @notice Whether `a` is greater than `b`. * @param a a FixedPoint. * @param b a FixedPoint. * @return True if `a > b`, or False. */ function isGreaterThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) { return a.rawValue > b.rawValue; } /** * @notice Whether `a` is greater than `b`. * @param a a FixedPoint. * @param b a uint256. * @return True if `a > b`, or False. */ function isGreaterThan(Unsigned memory a, uint256 b) internal pure returns (bool) { return a.rawValue > fromUnscaledUint(b).rawValue; } /** * @notice Whether `a` is greater than `b`. * @param a a uint256. * @param b a FixedPoint. * @return True if `a > b`, or False. */ function isGreaterThan(uint256 a, Unsigned memory b) internal pure returns (bool) { return fromUnscaledUint(a).rawValue > b.rawValue; } /** * @notice Whether `a` is greater than or equal to `b`. * @param a a FixedPoint. * @param b a FixedPoint. * @return True if `a >= b`, or False. */ function isGreaterThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) { return a.rawValue >= b.rawValue; } /** * @notice Whether `a` is greater than or equal to `b`. * @param a a FixedPoint. * @param b a uint256. * @return True if `a >= b`, or False. */ function isGreaterThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) { return a.rawValue >= fromUnscaledUint(b).rawValue; } /** * @notice Whether `a` is greater than or equal to `b`. * @param a a uint256. * @param b a FixedPoint. * @return True if `a >= b`, or False. */ function isGreaterThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) { return fromUnscaledUint(a).rawValue >= b.rawValue; } /** * @notice Whether `a` is less than `b`. * @param a a FixedPoint. * @param b a FixedPoint. * @return True if `a < b`, or False. */ function isLessThan(Unsigned memory a, Unsigned memory b) internal pure returns (bool) { return a.rawValue < b.rawValue; } /** * @notice Whether `a` is less than `b`. * @param a a FixedPoint. * @param b a uint256. * @return True if `a < b`, or False. */ function isLessThan(Unsigned memory a, uint256 b) internal pure returns (bool) { return a.rawValue < fromUnscaledUint(b).rawValue; } /** * @notice Whether `a` is less than `b`. * @param a a uint256. * @param b a FixedPoint. * @return True if `a < b`, or False. */ function isLessThan(uint256 a, Unsigned memory b) internal pure returns (bool) { return fromUnscaledUint(a).rawValue < b.rawValue; } /** * @notice Whether `a` is less than or equal to `b`. * @param a a FixedPoint. * @param b a FixedPoint. * @return True if `a <= b`, or False. */ function isLessThanOrEqual(Unsigned memory a, Unsigned memory b) internal pure returns (bool) { return a.rawValue <= b.rawValue; } /** * @notice Whether `a` is less than or equal to `b`. * @param a a FixedPoint. * @param b a uint256. * @return True if `a <= b`, or False. */ function isLessThanOrEqual(Unsigned memory a, uint256 b) internal pure returns (bool) { return a.rawValue <= fromUnscaledUint(b).rawValue; } /** * @notice Whether `a` is less than or equal to `b`. * @param a a uint256. * @param b a FixedPoint. * @return True if `a <= b`, or False. */ function isLessThanOrEqual(uint256 a, Unsigned memory b) internal pure returns (bool) { return fromUnscaledUint(a).rawValue <= b.rawValue; } /** * @notice The minimum of `a` and `b`. * @param a a FixedPoint. * @param b a FixedPoint. * @return the minimum of `a` and `b`. */ function min(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) { return a.rawValue < b.rawValue ? a : b; } /** * @notice The maximum of `a` and `b`. * @param a a FixedPoint. * @param b a FixedPoint. * @return the maximum of `a` and `b`. */ function max(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) { return a.rawValue > b.rawValue ? a : b; } /** * @notice Adds two `Unsigned`s, reverting on overflow. * @param a a FixedPoint. * @param b a FixedPoint. * @return the sum of `a` and `b`. */ function add(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) { return Unsigned(a.rawValue.add(b.rawValue)); } /** * @notice Adds an `Unsigned` to an unscaled uint, reverting on overflow. * @param a a FixedPoint. * @param b a uint256. * @return the sum of `a` and `b`. */ function add(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) { return add(a, fromUnscaledUint(b)); } /** * @notice Subtracts two `Unsigned`s, reverting on overflow. * @param a a FixedPoint. * @param b a FixedPoint. * @return the difference of `a` and `b`. */ function sub(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) { return Unsigned(a.rawValue.sub(b.rawValue)); } /** * @notice Subtracts an unscaled uint256 from an `Unsigned`, reverting on overflow. * @param a a FixedPoint. * @param b a uint256. * @return the difference of `a` and `b`. */ function sub(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) { return sub(a, fromUnscaledUint(b)); } /** * @notice Subtracts an `Unsigned` from an unscaled uint256, reverting on overflow. * @param a a uint256. * @param b a FixedPoint. * @return the difference of `a` and `b`. */ function sub(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) { return sub(fromUnscaledUint(a), b); } /** * @notice Multiplies two `Unsigned`s, reverting on overflow. * @dev This will "floor" the product. * @param a a FixedPoint. * @param b a FixedPoint. * @return the product of `a` and `b`. */ function mul(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) { // There are two caveats with this computation: // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is // stored internally as a uint256 ~10^59. // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which // would round to 3, but this computation produces the result 2. // No need to use SafeMath because FP_SCALING_FACTOR != 0. return Unsigned(a.rawValue.mul(b.rawValue) / FP_SCALING_FACTOR); } /** * @notice Multiplies an `Unsigned` and an unscaled uint256, reverting on overflow. * @dev This will "floor" the product. * @param a a FixedPoint. * @param b a uint256. * @return the product of `a` and `b`. */ function mul(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) { return Unsigned(a.rawValue.mul(b)); } /** * @notice Multiplies two `Unsigned`s and "ceil's" the product, reverting on overflow. * @param a a FixedPoint. * @param b a FixedPoint. * @return the product of `a` and `b`. */ function mulCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) { uint256 mulRaw = a.rawValue.mul(b.rawValue); uint256 mulFloor = mulRaw / FP_SCALING_FACTOR; uint256 mod = mulRaw.mod(FP_SCALING_FACTOR); if (mod != 0) { return Unsigned(mulFloor.add(1)); } else { return Unsigned(mulFloor); } } /** * @notice Multiplies an `Unsigned` and an unscaled uint256 and "ceil's" the product, reverting on overflow. * @param a a FixedPoint. * @param b a FixedPoint. * @return the product of `a` and `b`. */ function mulCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) { // Since b is an int, there is no risk of truncation and we can just mul it normally return Unsigned(a.rawValue.mul(b)); } /** * @notice Divides one `Unsigned` by an `Unsigned`, reverting on overflow or division by 0. * @dev This will "floor" the quotient. * @param a a FixedPoint numerator. * @param b a FixedPoint denominator. * @return the quotient of `a` divided by `b`. */ function div(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) { // There are two caveats with this computation: // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows. // 10^41 is stored internally as a uint256 10^59. // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666. return Unsigned(a.rawValue.mul(FP_SCALING_FACTOR).div(b.rawValue)); } /** * @notice Divides one `Unsigned` by an unscaled uint256, reverting on overflow or division by 0. * @dev This will "floor" the quotient. * @param a a FixedPoint numerator. * @param b a uint256 denominator. * @return the quotient of `a` divided by `b`. */ function div(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) { return Unsigned(a.rawValue.div(b)); } /** * @notice Divides one unscaled uint256 by an `Unsigned`, reverting on overflow or division by 0. * @dev This will "floor" the quotient. * @param a a uint256 numerator. * @param b a FixedPoint denominator. * @return the quotient of `a` divided by `b`. */ function div(uint256 a, Unsigned memory b) internal pure returns (Unsigned memory) { return div(fromUnscaledUint(a), b); } /** * @notice Divides one `Unsigned` by an `Unsigned` and "ceil's" the quotient, reverting on overflow or division by 0. * @param a a FixedPoint numerator. * @param b a FixedPoint denominator. * @return the quotient of `a` divided by `b`. */ function divCeil(Unsigned memory a, Unsigned memory b) internal pure returns (Unsigned memory) { uint256 aScaled = a.rawValue.mul(FP_SCALING_FACTOR); uint256 divFloor = aScaled.div(b.rawValue); uint256 mod = aScaled.mod(b.rawValue); if (mod != 0) { return Unsigned(divFloor.add(1)); } else { return Unsigned(divFloor); } } /** * @notice Divides one `Unsigned` by an unscaled uint256 and "ceil's" the quotient, reverting on overflow or division by 0. * @param a a FixedPoint numerator. * @param b a uint256 denominator. * @return the quotient of `a` divided by `b`. */ function divCeil(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory) { // Because it is possible that a quotient gets truncated, we can't just call "Unsigned(a.rawValue.div(b))" // similarly to mulCeil with a uint256 as the second parameter. Therefore we need to convert b into an Unsigned. // This creates the possibility of overflow if b is very large. return divCeil(a, fromUnscaledUint(b)); } /** * @notice Raises an `Unsigned` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`. * @dev This will "floor" the result. * @param a a FixedPoint numerator. * @param b a uint256 denominator. * @return output is `a` to the power of `b`. */ function pow(Unsigned memory a, uint256 b) internal pure returns (Unsigned memory output) { output = fromUnscaledUint(1); for (uint256 i = 0; i < b; i = i.add(1)) { output = mul(output, a); } } // ------------------------------------------------- SIGNED ------------------------------------------------------------- // Supports 18 decimals. E.g., 1e18 represents "1", 5e17 represents "0.5". // For signed values: // This can represent a value up (or down) to +-(2^255 - 1)/10^18 = ~10^58. 10^58 will be stored internally as int256 10^76. int256 private constant SFP_SCALING_FACTOR = 10**18; struct Signed { int256 rawValue; } function fromSigned(Signed memory a) internal pure returns (Unsigned memory) { require(a.rawValue >= 0, "Negative value provided"); return Unsigned(uint256(a.rawValue)); } function fromUnsigned(Unsigned memory a) internal pure returns (Signed memory) { require(a.rawValue <= uint256(type(int256).max), "Unsigned too large"); return Signed(int256(a.rawValue)); } /** * @notice Constructs a `Signed` from an unscaled int, e.g., `b=5` gets stored internally as `5**18`. * @param a int to convert into a FixedPoint.Signed. * @return the converted FixedPoint.Signed. */ function fromUnscaledInt(int256 a) internal pure returns (Signed memory) { return Signed(a.mul(SFP_SCALING_FACTOR)); } /** * @notice Whether `a` is equal to `b`. * @param a a FixedPoint.Signed. * @param b a int256. * @return True if equal, or False. */ function isEqual(Signed memory a, int256 b) internal pure returns (bool) { return a.rawValue == fromUnscaledInt(b).rawValue; } /** * @notice Whether `a` is equal to `b`. * @param a a FixedPoint.Signed. * @param b a FixedPoint.Signed. * @return True if equal, or False. */ function isEqual(Signed memory a, Signed memory b) internal pure returns (bool) { return a.rawValue == b.rawValue; } /** * @notice Whether `a` is greater than `b`. * @param a a FixedPoint.Signed. * @param b a FixedPoint.Signed. * @return True if `a > b`, or False. */ function isGreaterThan(Signed memory a, Signed memory b) internal pure returns (bool) { return a.rawValue > b.rawValue; } /** * @notice Whether `a` is greater than `b`. * @param a a FixedPoint.Signed. * @param b an int256. * @return True if `a > b`, or False. */ function isGreaterThan(Signed memory a, int256 b) internal pure returns (bool) { return a.rawValue > fromUnscaledInt(b).rawValue; } /** * @notice Whether `a` is greater than `b`. * @param a an int256. * @param b a FixedPoint.Signed. * @return True if `a > b`, or False. */ function isGreaterThan(int256 a, Signed memory b) internal pure returns (bool) { return fromUnscaledInt(a).rawValue > b.rawValue; } /** * @notice Whether `a` is greater than or equal to `b`. * @param a a FixedPoint.Signed. * @param b a FixedPoint.Signed. * @return True if `a >= b`, or False. */ function isGreaterThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) { return a.rawValue >= b.rawValue; } /** * @notice Whether `a` is greater than or equal to `b`. * @param a a FixedPoint.Signed. * @param b an int256. * @return True if `a >= b`, or False. */ function isGreaterThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) { return a.rawValue >= fromUnscaledInt(b).rawValue; } /** * @notice Whether `a` is greater than or equal to `b`. * @param a an int256. * @param b a FixedPoint.Signed. * @return True if `a >= b`, or False. */ function isGreaterThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) { return fromUnscaledInt(a).rawValue >= b.rawValue; } /** * @notice Whether `a` is less than `b`. * @param a a FixedPoint.Signed. * @param b a FixedPoint.Signed. * @return True if `a < b`, or False. */ function isLessThan(Signed memory a, Signed memory b) internal pure returns (bool) { return a.rawValue < b.rawValue; } /** * @notice Whether `a` is less than `b`. * @param a a FixedPoint.Signed. * @param b an int256. * @return True if `a < b`, or False. */ function isLessThan(Signed memory a, int256 b) internal pure returns (bool) { return a.rawValue < fromUnscaledInt(b).rawValue; } /** * @notice Whether `a` is less than `b`. * @param a an int256. * @param b a FixedPoint.Signed. * @return True if `a < b`, or False. */ function isLessThan(int256 a, Signed memory b) internal pure returns (bool) { return fromUnscaledInt(a).rawValue < b.rawValue; } /** * @notice Whether `a` is less than or equal to `b`. * @param a a FixedPoint.Signed. * @param b a FixedPoint.Signed. * @return True if `a <= b`, or False. */ function isLessThanOrEqual(Signed memory a, Signed memory b) internal pure returns (bool) { return a.rawValue <= b.rawValue; } /** * @notice Whether `a` is less than or equal to `b`. * @param a a FixedPoint.Signed. * @param b an int256. * @return True if `a <= b`, or False. */ function isLessThanOrEqual(Signed memory a, int256 b) internal pure returns (bool) { return a.rawValue <= fromUnscaledInt(b).rawValue; } /** * @notice Whether `a` is less than or equal to `b`. * @param a an int256. * @param b a FixedPoint.Signed. * @return True if `a <= b`, or False. */ function isLessThanOrEqual(int256 a, Signed memory b) internal pure returns (bool) { return fromUnscaledInt(a).rawValue <= b.rawValue; } /** * @notice The minimum of `a` and `b`. * @param a a FixedPoint.Signed. * @param b a FixedPoint.Signed. * @return the minimum of `a` and `b`. */ function min(Signed memory a, Signed memory b) internal pure returns (Signed memory) { return a.rawValue < b.rawValue ? a : b; } /** * @notice The maximum of `a` and `b`. * @param a a FixedPoint.Signed. * @param b a FixedPoint.Signed. * @return the maximum of `a` and `b`. */ function max(Signed memory a, Signed memory b) internal pure returns (Signed memory) { return a.rawValue > b.rawValue ? a : b; } /** * @notice Adds two `Signed`s, reverting on overflow. * @param a a FixedPoint.Signed. * @param b a FixedPoint.Signed. * @return the sum of `a` and `b`. */ function add(Signed memory a, Signed memory b) internal pure returns (Signed memory) { return Signed(a.rawValue.add(b.rawValue)); } /** * @notice Adds an `Signed` to an unscaled int, reverting on overflow. * @param a a FixedPoint.Signed. * @param b an int256. * @return the sum of `a` and `b`. */ function add(Signed memory a, int256 b) internal pure returns (Signed memory) { return add(a, fromUnscaledInt(b)); } /** * @notice Subtracts two `Signed`s, reverting on overflow. * @param a a FixedPoint.Signed. * @param b a FixedPoint.Signed. * @return the difference of `a` and `b`. */ function sub(Signed memory a, Signed memory b) internal pure returns (Signed memory) { return Signed(a.rawValue.sub(b.rawValue)); } /** * @notice Subtracts an unscaled int256 from an `Signed`, reverting on overflow. * @param a a FixedPoint.Signed. * @param b an int256. * @return the difference of `a` and `b`. */ function sub(Signed memory a, int256 b) internal pure returns (Signed memory) { return sub(a, fromUnscaledInt(b)); } /** * @notice Subtracts an `Signed` from an unscaled int256, reverting on overflow. * @param a an int256. * @param b a FixedPoint.Signed. * @return the difference of `a` and `b`. */ function sub(int256 a, Signed memory b) internal pure returns (Signed memory) { return sub(fromUnscaledInt(a), b); } /** * @notice Multiplies two `Signed`s, reverting on overflow. * @dev This will "floor" the product. * @param a a FixedPoint.Signed. * @param b a FixedPoint.Signed. * @return the product of `a` and `b`. */ function mul(Signed memory a, Signed memory b) internal pure returns (Signed memory) { // There are two caveats with this computation: // 1. Max output for the represented number is ~10^41, otherwise an intermediate value overflows. 10^41 is // stored internally as an int256 ~10^59. // 2. Results that can't be represented exactly are truncated not rounded. E.g., 1.4 * 2e-18 = 2.8e-18, which // would round to 3, but this computation produces the result 2. // No need to use SafeMath because SFP_SCALING_FACTOR != 0. return Signed(a.rawValue.mul(b.rawValue) / SFP_SCALING_FACTOR); } /** * @notice Multiplies an `Signed` and an unscaled int256, reverting on overflow. * @dev This will "floor" the product. * @param a a FixedPoint.Signed. * @param b an int256. * @return the product of `a` and `b`. */ function mul(Signed memory a, int256 b) internal pure returns (Signed memory) { return Signed(a.rawValue.mul(b)); } /** * @notice Multiplies two `Signed`s and "ceil's" the product, reverting on overflow. * @param a a FixedPoint.Signed. * @param b a FixedPoint.Signed. * @return the product of `a` and `b`. */ function mulAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) { int256 mulRaw = a.rawValue.mul(b.rawValue); int256 mulTowardsZero = mulRaw / SFP_SCALING_FACTOR; // Manual mod because SignedSafeMath doesn't support it. int256 mod = mulRaw % SFP_SCALING_FACTOR; if (mod != 0) { bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0); int256 valueToAdd = isResultPositive ? int256(1) : int256(-1); return Signed(mulTowardsZero.add(valueToAdd)); } else { return Signed(mulTowardsZero); } } /** * @notice Multiplies an `Signed` and an unscaled int256 and "ceil's" the product, reverting on overflow. * @param a a FixedPoint.Signed. * @param b a FixedPoint.Signed. * @return the product of `a` and `b`. */ function mulAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) { // Since b is an int, there is no risk of truncation and we can just mul it normally return Signed(a.rawValue.mul(b)); } /** * @notice Divides one `Signed` by an `Signed`, reverting on overflow or division by 0. * @dev This will "floor" the quotient. * @param a a FixedPoint numerator. * @param b a FixedPoint denominator. * @return the quotient of `a` divided by `b`. */ function div(Signed memory a, Signed memory b) internal pure returns (Signed memory) { // There are two caveats with this computation: // 1. Max value for the number dividend `a` represents is ~10^41, otherwise an intermediate value overflows. // 10^41 is stored internally as an int256 10^59. // 2. Results that can't be represented exactly are truncated not rounded. E.g., 2 / 3 = 0.6 repeating, which // would round to 0.666666666666666667, but this computation produces the result 0.666666666666666666. return Signed(a.rawValue.mul(SFP_SCALING_FACTOR).div(b.rawValue)); } /** * @notice Divides one `Signed` by an unscaled int256, reverting on overflow or division by 0. * @dev This will "floor" the quotient. * @param a a FixedPoint numerator. * @param b an int256 denominator. * @return the quotient of `a` divided by `b`. */ function div(Signed memory a, int256 b) internal pure returns (Signed memory) { return Signed(a.rawValue.div(b)); } /** * @notice Divides one unscaled int256 by an `Signed`, reverting on overflow or division by 0. * @dev This will "floor" the quotient. * @param a an int256 numerator. * @param b a FixedPoint denominator. * @return the quotient of `a` divided by `b`. */ function div(int256 a, Signed memory b) internal pure returns (Signed memory) { return div(fromUnscaledInt(a), b); } /** * @notice Divides one `Signed` by an `Signed` and "ceil's" the quotient, reverting on overflow or division by 0. * @param a a FixedPoint numerator. * @param b a FixedPoint denominator. * @return the quotient of `a` divided by `b`. */ function divAwayFromZero(Signed memory a, Signed memory b) internal pure returns (Signed memory) { int256 aScaled = a.rawValue.mul(SFP_SCALING_FACTOR); int256 divTowardsZero = aScaled.div(b.rawValue); // Manual mod because SignedSafeMath doesn't support it. int256 mod = aScaled % b.rawValue; if (mod != 0) { bool isResultPositive = isLessThan(a, 0) == isLessThan(b, 0); int256 valueToAdd = isResultPositive ? int256(1) : int256(-1); return Signed(divTowardsZero.add(valueToAdd)); } else { return Signed(divTowardsZero); } } /** * @notice Divides one `Signed` by an unscaled int256 and "ceil's" the quotient, reverting on overflow or division by 0. * @param a a FixedPoint numerator. * @param b an int256 denominator. * @return the quotient of `a` divided by `b`. */ function divAwayFromZero(Signed memory a, int256 b) internal pure returns (Signed memory) { // Because it is possible that a quotient gets truncated, we can't just call "Signed(a.rawValue.div(b))" // similarly to mulCeil with an int256 as the second parameter. Therefore we need to convert b into an Signed. // This creates the possibility of overflow if b is very large. return divAwayFromZero(a, fromUnscaledInt(b)); } /** * @notice Raises an `Signed` to the power of an unscaled uint256, reverting on overflow. E.g., `b=2` squares `a`. * @dev This will "floor" the result. * @param a a FixedPoint.Signed. * @param b a uint256 (negative exponents are not allowed). * @return output is `a` to the power of `b`. */ function pow(Signed memory a, uint256 b) internal pure returns (Signed memory output) { output = fromUnscaledInt(1); for (uint256 i = 0; i < b; i = i.add(1)) { output = mul(output, a); } } }
// SPDX-License-Identifier: MIT pragma solidity 0.6.12; pragma experimental ABIEncoderV2; interface ICreditLine { function borrower() external view returns (address); function limit() external view returns (uint256); function maxLimit() external view returns (uint256); function interestApr() external view returns (uint256); function paymentPeriodInDays() external view returns (uint256); function principalGracePeriodInDays() external view returns (uint256); function termInDays() external view returns (uint256); function lateFeeApr() external view returns (uint256); function isLate() external view returns (bool); function withinPrincipalGracePeriod() external view returns (bool); // Accounting variables function balance() external view returns (uint256); function interestOwed() external view returns (uint256); function principalOwed() external view returns (uint256); function termEndTime() external view returns (uint256); function nextDueTime() external view returns (uint256); function interestAccruedAsOf() external view returns (uint256); function lastFullPaymentTime() external view returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity 0.6.12; pragma experimental ABIEncoderV2; import "@openzeppelin/contracts-ethereum-package/contracts/token/ERC721/IERC721.sol"; interface IPoolTokens is IERC721 { event TokenMinted( address indexed owner, address indexed pool, uint256 indexed tokenId, uint256 amount, uint256 tranche ); event TokenRedeemed( address indexed owner, address indexed pool, uint256 indexed tokenId, uint256 principalRedeemed, uint256 interestRedeemed, uint256 tranche ); event TokenBurned(address indexed owner, address indexed pool, uint256 indexed tokenId); struct TokenInfo { address pool; uint256 tranche; uint256 principalAmount; uint256 principalRedeemed; uint256 interestRedeemed; } struct MintParams { uint256 principalAmount; uint256 tranche; } function mint(MintParams calldata params, address to) external returns (uint256); function redeem( uint256 tokenId, uint256 principalRedeemed, uint256 interestRedeemed ) external; function withdrawPrincipal(uint256 tokenId, uint256 principalAmount) external; function burn(uint256 tokenId) external; function onPoolCreated(address newPool) external; function getTokenInfo(uint256 tokenId) external view returns (TokenInfo memory); function validPool(address sender) external view returns (bool); function isApprovedOrOwner(address spender, uint256 tokenId) external view returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity 0.6.12; pragma experimental ABIEncoderV2; import "./IV2CreditLine.sol"; abstract contract ITranchedPool { IV2CreditLine public creditLine; uint256 public createdAt; enum Tranches { Reserved, Senior, Junior } struct TrancheInfo { uint256 id; uint256 principalDeposited; uint256 principalSharePrice; uint256 interestSharePrice; uint256 lockedUntil; } struct PoolSlice { TrancheInfo seniorTranche; TrancheInfo juniorTranche; uint256 totalInterestAccrued; uint256 principalDeployed; } struct SliceInfo { uint256 reserveFeePercent; uint256 interestAccrued; uint256 principalAccrued; } struct ApplyResult { uint256 interestRemaining; uint256 principalRemaining; uint256 reserveDeduction; uint256 oldInterestSharePrice; uint256 oldPrincipalSharePrice; } function initialize( address _config, address _borrower, uint256 _juniorFeePercent, uint256 _limit, uint256 _interestApr, uint256 _paymentPeriodInDays, uint256 _termInDays, uint256 _lateFeeApr, uint256 _principalGracePeriodInDays, uint256 _fundableAt, uint256[] calldata _allowedUIDTypes ) public virtual; function getTranche(uint256 tranche) external view virtual returns (TrancheInfo memory); function pay(uint256 amount) external virtual; function lockJuniorCapital() external virtual; function lockPool() external virtual; function initializeNextSlice(uint256 _fundableAt) external virtual; function totalJuniorDeposits() external view virtual returns (uint256); function drawdown(uint256 amount) external virtual; function setFundableAt(uint256 timestamp) external virtual; function deposit(uint256 tranche, uint256 amount) external virtual returns (uint256 tokenId); function assess() external virtual; function depositWithPermit( uint256 tranche, uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external virtual returns (uint256 tokenId); function availableToWithdraw(uint256 tokenId) external view virtual returns (uint256 interestRedeemable, uint256 principalRedeemable); function withdraw(uint256 tokenId, uint256 amount) external virtual returns (uint256 interestWithdrawn, uint256 principalWithdrawn); function withdrawMax(uint256 tokenId) external virtual returns (uint256 interestWithdrawn, uint256 principalWithdrawn); function withdrawMultiple(uint256[] calldata tokenIds, uint256[] calldata amounts) external virtual; function numSlices() external view virtual returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity 0.6.12; pragma experimental ABIEncoderV2; import "./ICreditLine.sol"; abstract contract IV2CreditLine is ICreditLine { function principal() external view virtual returns (uint256); function totalInterestAccrued() external view virtual returns (uint256); function termStartTime() external view virtual returns (uint256); function setLimit(uint256 newAmount) external virtual; function setMaxLimit(uint256 newAmount) external virtual; function setBalance(uint256 newBalance) external virtual; function setPrincipal(uint256 _principal) external virtual; function setTotalInterestAccrued(uint256 _interestAccrued) external virtual; function drawdown(uint256 amount) external virtual; function assess() external virtual returns ( uint256, uint256, uint256 ); function initialize( address _config, address owner, address _borrower, uint256 _limit, uint256 _interestApr, uint256 _paymentPeriodInDays, uint256 _termInDays, uint256 _lateFeeApr, uint256 _principalGracePeriodInDays ) public virtual; function setTermEndTime(uint256 newTermEndTime) external virtual; function setNextDueTime(uint256 newNextDueTime) external virtual; function setInterestOwed(uint256 newInterestOwed) external virtual; function setPrincipalOwed(uint256 newPrincipalOwed) external virtual; function setInterestAccruedAsOf(uint256 newInterestAccruedAsOf) external virtual; function setWritedownAmount(uint256 newWritedownAmount) external virtual; function setLastFullPaymentTime(uint256 newLastFullPaymentTime) external virtual; function setLateFeeApr(uint256 newLateFeeApr) external virtual; function updateGoldfinchConfig() external virtual; }
{ "evmVersion": "istanbul", "libraries": {}, "metadata": { "bytecodeHash": "ipfs", "useLiteralContent": true }, "optimizer": { "enabled": true, "runs": 100 }, "remappings": [], "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pool","type":"address"},{"indexed":true,"internalType":"uint256","name":"tranche","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"principalSharePrice","type":"uint256"},{"indexed":false,"internalType":"int256","name":"principalDelta","type":"int256"},{"indexed":false,"internalType":"uint256","name":"interestSharePrice","type":"uint256"},{"indexed":false,"internalType":"int256","name":"interestDelta","type":"int256"}],"name":"SharePriceUpdated","type":"event"},{"inputs":[],"name":"FP_SCALING_FACTOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ONE_HUNDRED","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountRemaining","type":"uint256"},{"internalType":"uint256","name":"currentSharePrice","type":"uint256"},{"internalType":"uint256","name":"desiredAmount","type":"uint256"},{"internalType":"uint256","name":"totalShares","type":"uint256"}],"name":"applyToSharePrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"principalDeposited","type":"uint256"},{"internalType":"uint256","name":"principalSharePrice","type":"uint256"},{"internalType":"uint256","name":"interestSharePrice","type":"uint256"},{"internalType":"uint256","name":"lockedUntil","type":"uint256"}],"internalType":"struct ITranchedPool.TrancheInfo","name":"tranche","type":"tuple"},{"internalType":"uint256","name":"amount","type":"uint256"},{"components":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"principalDeposited","type":"uint256"},{"internalType":"uint256","name":"principalSharePrice","type":"uint256"},{"internalType":"uint256","name":"interestSharePrice","type":"uint256"},{"internalType":"uint256","name":"lockedUntil","type":"uint256"}],"internalType":"struct ITranchedPool.TrancheInfo","name":"seniorTranche","type":"tuple"},{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"principalDeposited","type":"uint256"},{"internalType":"uint256","name":"principalSharePrice","type":"uint256"},{"internalType":"uint256","name":"interestSharePrice","type":"uint256"},{"internalType":"uint256","name":"lockedUntil","type":"uint256"}],"internalType":"struct ITranchedPool.TrancheInfo","name":"juniorTranche","type":"tuple"},{"internalType":"uint256","name":"totalInterestAccrued","type":"uint256"},{"internalType":"uint256","name":"principalDeployed","type":"uint256"}],"internalType":"struct ITranchedPool.PoolSlice","name":"slice","type":"tuple"}],"name":"calculateExpectedSharePrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"desiredSharePrice","type":"uint256"},{"internalType":"uint256","name":"actualSharePrice","type":"uint256"},{"internalType":"uint256","name":"totalShares","type":"uint256"}],"name":"desiredAmountFromSharePrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"principalDeposited","type":"uint256"},{"internalType":"uint256","name":"principalSharePrice","type":"uint256"},{"internalType":"uint256","name":"interestSharePrice","type":"uint256"},{"internalType":"uint256","name":"lockedUntil","type":"uint256"}],"internalType":"struct ITranchedPool.TrancheInfo","name":"seniorTranche","type":"tuple"},{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"principalDeposited","type":"uint256"},{"internalType":"uint256","name":"principalSharePrice","type":"uint256"},{"internalType":"uint256","name":"interestSharePrice","type":"uint256"},{"internalType":"uint256","name":"lockedUntil","type":"uint256"}],"internalType":"struct ITranchedPool.TrancheInfo","name":"juniorTranche","type":"tuple"},{"internalType":"uint256","name":"totalInterestAccrued","type":"uint256"},{"internalType":"uint256","name":"principalDeployed","type":"uint256"}],"internalType":"struct ITranchedPool.PoolSlice","name":"slice","type":"tuple"},{"internalType":"contract IV2CreditLine","name":"creditLine","type":"IV2CreditLine"},{"internalType":"uint256","name":"totalDeployed","type":"uint256"},{"internalType":"uint256","name":"reserveFeePercent","type":"uint256"}],"name":"getSliceInfo","outputs":[{"components":[{"internalType":"uint256","name":"reserveFeePercent","type":"uint256"},{"internalType":"uint256","name":"interestAccrued","type":"uint256"},{"internalType":"uint256","name":"principalAccrued","type":"uint256"}],"internalType":"struct ITranchedPool.SliceInfo","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"principalDeposited","type":"uint256"},{"internalType":"uint256","name":"principalSharePrice","type":"uint256"},{"internalType":"uint256","name":"interestSharePrice","type":"uint256"},{"internalType":"uint256","name":"lockedUntil","type":"uint256"}],"internalType":"struct ITranchedPool.TrancheInfo","name":"seniorTranche","type":"tuple"},{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"principalDeposited","type":"uint256"},{"internalType":"uint256","name":"principalSharePrice","type":"uint256"},{"internalType":"uint256","name":"interestSharePrice","type":"uint256"},{"internalType":"uint256","name":"lockedUntil","type":"uint256"}],"internalType":"struct ITranchedPool.TrancheInfo","name":"juniorTranche","type":"tuple"},{"internalType":"uint256","name":"totalInterestAccrued","type":"uint256"},{"internalType":"uint256","name":"principalDeployed","type":"uint256"}],"internalType":"struct ITranchedPool.PoolSlice","name":"slice","type":"tuple"},{"internalType":"contract IV2CreditLine","name":"creditLine","type":"IV2CreditLine"},{"internalType":"uint256","name":"totalDeployed","type":"uint256"}],"name":"getTotalInterestAndPrincipal","outputs":[{"internalType":"uint256","name":"interestAccrued","type":"uint256"},{"internalType":"uint256","name":"principalAccrued","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"fraction","type":"uint256"},{"internalType":"uint256","name":"total","type":"uint256"}],"name":"scaleByFraction","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"principalDeposited","type":"uint256"},{"internalType":"uint256","name":"principalSharePrice","type":"uint256"},{"internalType":"uint256","name":"interestSharePrice","type":"uint256"},{"internalType":"uint256","name":"lockedUntil","type":"uint256"}],"internalType":"struct ITranchedPool.TrancheInfo","name":"tranche","type":"tuple"},{"internalType":"uint256","name":"amount","type":"uint256"},{"components":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"principalDeposited","type":"uint256"},{"internalType":"uint256","name":"principalSharePrice","type":"uint256"},{"internalType":"uint256","name":"interestSharePrice","type":"uint256"},{"internalType":"uint256","name":"lockedUntil","type":"uint256"}],"internalType":"struct ITranchedPool.TrancheInfo","name":"seniorTranche","type":"tuple"},{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"principalDeposited","type":"uint256"},{"internalType":"uint256","name":"principalSharePrice","type":"uint256"},{"internalType":"uint256","name":"interestSharePrice","type":"uint256"},{"internalType":"uint256","name":"lockedUntil","type":"uint256"}],"internalType":"struct ITranchedPool.TrancheInfo","name":"juniorTranche","type":"tuple"},{"internalType":"uint256","name":"totalInterestAccrued","type":"uint256"},{"internalType":"uint256","name":"principalDeployed","type":"uint256"}],"internalType":"struct ITranchedPool.PoolSlice","name":"slice","type":"tuple"}],"name":"scaleByPercentOwnership","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"principalDeposited","type":"uint256"},{"internalType":"uint256","name":"principalSharePrice","type":"uint256"},{"internalType":"uint256","name":"interestSharePrice","type":"uint256"},{"internalType":"uint256","name":"lockedUntil","type":"uint256"}],"internalType":"struct ITranchedPool.TrancheInfo","name":"seniorTranche","type":"tuple"},{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"principalDeposited","type":"uint256"},{"internalType":"uint256","name":"principalSharePrice","type":"uint256"},{"internalType":"uint256","name":"interestSharePrice","type":"uint256"},{"internalType":"uint256","name":"lockedUntil","type":"uint256"}],"internalType":"struct ITranchedPool.TrancheInfo","name":"juniorTranche","type":"tuple"},{"internalType":"uint256","name":"totalInterestAccrued","type":"uint256"},{"internalType":"uint256","name":"principalDeployed","type":"uint256"}],"internalType":"struct ITranchedPool.PoolSlice","name":"slice","type":"tuple"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"totalDeployed","type":"uint256"}],"name":"scaleForSlice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"sharePrice","type":"uint256"},{"internalType":"uint256","name":"totalShares","type":"uint256"}],"name":"sharePriceToUsdc","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"totalShares","type":"uint256"}],"name":"usdcToSharePrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"}]
Contract Creation Code
612474610026600b82828239805160001a60731461001957fe5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106101415760003560e01c80638c48a764116100c2578063bfaa8cca11610086578063bfaa8cca146102e6578063cde88845146102ee578063cee38ee414610301578063d8eb673e14610314578063f7fc24b214610334578063ff0825bc1461034757610141565b80638c48a764146102605780638e3875b6146102805780639d82cfd2146102a0578063a59387cd146102b3578063af5f5753146102d357610141565b80635df6b2ed116101095780635df6b2ed146101e557806368dcfdc0146101f85780636dd0a9b51461020057806384810cb01461022057806385bd324d1461023357610141565b80630174b449146101465780630a9f9a141461016f57806321a0aa7d146101915780632e76cb89146101a457806330785368146101c5575b600080fd5b61015961015436600461222a565b610367565b60405161016691906122a7565b60405180910390f35b81801561017b57600080fd5b5061018f61018a366004611ed3565b61038e565b005b61015961019f36600461224b565b6104b1565b6101b76101b2366004612276565b6104e0565b6040516101669291906123f1565b8180156101d157600080fd5b506101596101e0366004611f27565b61053a565b6101b76101f3366004611fda565b610876565b6101596109d1565b81801561020c57600080fd5b506101b761021b3660046121d8565b6109dd565b61015961022e366004612064565b610a2f565b81801561023f57600080fd5b5061025361024e366004611f7b565b610a48565b604051610166919061237b565b81801561026c57600080fd5b506101b761027b3660046121d8565b610dc3565b61029361028e36600461201c565b610e11565b60405161016691906123b5565b6101596102ae366004612122565b610e4b565b8180156102bf57600080fd5b506102536102ce3660046120d9565b610e69565b6101596102e1366004612122565b6110e1565b610159611118565b6101596102fc36600461222a565b61111d565b61015961030f36600461224b565b611149565b81801561032057600080fd5b5061025361032f36600461209a565b6111a2565b6101b7610342366004612160565b611373565b81801561035357600080fd5b5061018f610362366004611eef565b6113dd565b6000610385670de0b6b3a764000061037f8585611b2b565b90611b6e565b90505b92915050565b604051637d8b34e560e11b815281906001600160a01b0382169063fb1669ca906103bd906000906004016122a7565b600060405180830381600087803b1580156103d757600080fd5b505af11580156103eb573d6000803e3d6000fd5b50506040516327ea6f2b60e01b81526001600160a01b03841692506327ea6f2b915061041c906000906004016122a7565b600060405180830381600087803b15801561043657600080fd5b505af115801561044a573d6000803e3d6000fd5b5050604051632fe2f3b960e21b81526001600160a01b038416925063bf8bcee4915061047b906000906004016122a7565b600060405180830381600087803b15801561049557600080fd5b505af11580156104a9573d6000803e3d6000fd5b505050505050565b6000828410156104bf578293505b60006104cb8585611bb0565b90506104d78184610367565b95945050505050565b6000808515806104ee575083155b156104fd575084905083610531565b83861015610509578593505b6000610515858561111d565b90506105218786611bb0565b61052b8783611bf2565b92509250505b94509492505050565b6000805b875481101561086b5761054f611d8e565b61061f89838154811061055e57fe5b90600052602060002090600c0201604051806080016040529081600082016040518060a0016040529081600082015481526020016001820154815260200160028201548152602001600382015481526020016004820154815250508152602001600582016040518060a0016040529081600082015481526020016001820154815260200160028201548152602001600382015481526020016004820154815250508152602001600a8201548152602001600b82015481525050858789610e11565b9050610629611daf565b6107ea8a848154811061063857fe5b90600052602060002090600c02016107158c868154811061065557fe5b90600052602060002090600c0201604051806080016040529081600082016040518060a0016040529081600082015481526020016001820154815260200160028201548152602001600382015481526020016004820154815250508152602001600582016040518060a0016040529081600082015481526020016001820154815260200160028201548152602001600382015481526020016004820154815250508152602001600a8201548152602001600b820154815250508c8a610a2f565b6107e48d878154811061072457fe5b90600052602060002090600c0201604051806080016040529081600082016040518060a0016040529081600082015481526020016001820154815260200160028201548152602001600382015481526020016004820154815250508152602001600582016040518060a0016040529081600082015481526020016001820154815260200160028201548152602001600382015481526020016004820154815250508152602001600a8201548152602001600b820154815250508c8b610a2f565b856111a2565b905061084f8a84815481106107fb57fe5b90600052602060002090600c02016005016040518060a00160405290816000820154815260200160018201548152602001600282015481526020016003820154815260200160048201548152505082611c17565b604081015161085f908590611bf2565b9350505060010161053e565b509695505050505050565b600080836001600160a01b031663193501146040518163ffffffff1660e01b815260040160206040518083038186803b1580156108b257600080fd5b505afa1580156108c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108ea9190612212565b90506109718161096b866001600160a01b031663b69ef8a86040518163ffffffff1660e01b815260040160206040518083038186803b15801561092c57600080fd5b505afa158015610940573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109649190612212565b8690611bb0565b90611bf2565b905061097e858285610a2f565b905060006109a5866020015160200151876000015160200151611bf290919063ffffffff16565b90506109c28261096b886060015184611bb090919063ffffffff16565b60409096015196945050505050565b670de0b6b3a764000081565b60008060008760010154905060006109fb888a6003015488856104e0565b60038b0181905560028b01549199509150610a1990889087856104e0565b60029a909a019990995550959795505050505050565b6000610a4083856060015184611149565b949350505050565b610a50611daf565b610a58611daf565b60005b8954811015610db657610a6c611d8e565b610b3c8b8381548110610a7b57fe5b90600052602060002090600c0201604051806080016040529081600082016040518060a0016040529081600082015481526020016001820154815260200160028201548152602001600382015481526020016004820154815250508152602001600582016040518060a0016040529081600082015481526020016001820154815260200160028201548152602001600382015481526020016004820154815250508152602001600a8201548152602001600b8201548152505087898b610e11565b9050610b46611daf565b610d088c8481548110610b5557fe5b90600052602060002090600c0201610c328e8681548110610b7257fe5b90600052602060002090600c0201604051806080016040529081600082016040518060a0016040529081600082015481526020016001820154815260200160028201548152602001600382015481526020016004820154815250508152602001600582016040518060a0016040529081600082015481526020016001820154815260200160028201548152602001600382015481526020016004820154815250508152602001600a8201548152602001600b820154815250508e8c610a2f565b610d018f8781548110610c4157fe5b90600052602060002090600c0201604051806080016040529081600082016040518060a0016040529081600082015481526020016001820154815260200160028201548152602001600382015481526020016004820154815250508152602001600582016040518060a0016040529081600082015481526020016001820154815260200160028201548152602001600382015481526020016004820154815250508152602001600a8201548152602001600b820154815250508e8d610a2f565b8986610e69565b9050610d6d8c8481548110610d1957fe5b90600052602060002090600c02016000016040518060a00160405290816000820154815260200160018201548152602001600282015481526020016003820154815260200160048201548152505082611c17565b80518451610d7a91611bf2565b845260208082015190850151610d8f91611bf2565b602085015260408082015190850151610da791611bf2565b60408501525050600101610a5b565b5098975050505050505050565b6000806000610ddb8589600301548a600101546104b1565b90506000610df2858a600201548b600101546104b1565b9050610e0189898985856109dd565b9350935050509550959350505050565b610e19611d8e565b600080610e27878787610876565b60408051606081018252878152602081019390935282015292505050949350505050565b600080610e5c84866020015161111d565b90506104d78582856110e1565b610e71611daf565b6040805160a08082018352885480835260018a0154602080850182905260028c015485870181905260038d0154606080880182905260048f01546080808a018290528c8601518b5161012081018d52808301998a52808b019890985260c088019590955260e08701939093526101008601529484528751958601885260058e0154865260068e01548684015260078e01548689015260088e01548686015260098e01549086015290820193909352600a8b015494810194909452600b8a015490840152600092610f42929190610e4b565b90506000611040886000016040518060a00160405290816000820154815260200160018201548152602001600282015481526020016003820154815260200160048201548152505085604001518a604051806080016040529081600082016040518060a0016040529081600082015481526020016001820154815260200160028201548152602001600382015481526020016004820154815250508152602001600582016040518060a0016040529081600082015481526020016001820154815260200160028201548152602001600382015481526020016004820154815250508152602001600a8201548152602001600b82015481525050610e4b565b905060006110718361106a61106288600001518a611bf290919063ffffffff16565b606490611bb0565b6064611149565b905060006110858987600001516064611149565b90506110918982611bb0565b60038b015460028c0154919a50906110ac8c8c8c8789610dc3565b6040805160a0810182529283526020830191909152810193909352606083019190915260808201529998505050505050505050565b600080611107836000015160200151846020015160200151611bf290919063ffffffff16565b90506104d784866020015183611149565b606481565b600081156111405761113b8261037f85670de0b6b3a7640000611b2b565b610385565b50600092915050565b6000611153611dde565b61115c83611c83565b9050611166611dde565b61116f85611c83565b9050611197670de0b6b3a76400006111918861118b8587611cb1565b90611ce9565b90611d0a565b519695505050505050565b6111aa611daf565b60006111cb6111c086886005016001015461111d565b600888015490611bf2565b905060006112c9876005016040518060a001604052908160008201548152602001600182015481526020016002820154815260200160038201548152602001600482015481525050856040015189604051806080016040529081600082016040518060a0016040529081600082015481526020016001820154815260200160028201548152602001600382015481526020016004820154815250508152602001600582016040518060a0016040529081600082015481526020016001820154815260200160028201548152602001600382015481526020016004820154815250508152602001600a8201548152602001600b82015481525050610e4b565b60088801546007890154919250906112e760058a0189898787610dc3565b90985096506112f68888611bf2565b9750600061130a8888600001516064611149565b90506113168982611bb0565b98506000975061134060058b0161132d8b8b611bf2565b60006113398d8d611bf2565b60006109dd565b6040805160a081018252928352602083019190915281019190915260608101929092526080820152979650505050505050565b600080600061138a85600201548560400151610367565b905060006113a086600301548660400151610367565b90506113b9856080015182611bb090919063ffffffff16565b93506113d2856060015183611bb090919063ffffffff16565b925050509250929050565b60008290506000829050806001600160a01b031663fb1669ca836001600160a01b031663b69ef8a86040518163ffffffff1660e01b815260040160206040518083038186803b15801561142f57600080fd5b505afa158015611443573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114679190612212565b6040518263ffffffff1660e01b815260040161148391906122a7565b600060405180830381600087803b15801561149d57600080fd5b505af11580156114b1573d6000803e3d6000fd5b50505050806001600160a01b03166327ea6f2b836001600160a01b031663a4d66daf6040518163ffffffff1660e01b815260040160206040518083038186803b1580156114fd57600080fd5b505afa158015611511573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115359190612212565b6040518263ffffffff1660e01b815260040161155191906122a7565b600060405180830381600087803b15801561156b57600080fd5b505af115801561157f573d6000803e3d6000fd5b50505050806001600160a01b03166396c8df37836001600160a01b03166321856b366040518163ffffffff1660e01b815260040160206040518083038186803b1580156115cb57600080fd5b505afa1580156115df573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116039190612212565b6040518263ffffffff1660e01b815260040161161f91906122a7565b600060405180830381600087803b15801561163957600080fd5b505af115801561164d573d6000803e3d6000fd5b50505050806001600160a01b031663b3b8a9c7836001600160a01b031663193501146040518163ffffffff1660e01b815260040160206040518083038186803b15801561169957600080fd5b505afa1580156116ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116d19190612212565b6040518263ffffffff1660e01b81526004016116ed91906122a7565b600060405180830381600087803b15801561170757600080fd5b505af115801561171b573d6000803e3d6000fd5b50505050806001600160a01b0316637ae14b09836001600160a01b03166364fb2d956040518163ffffffff1660e01b815260040160206040518083038186803b15801561176757600080fd5b505afa15801561177b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061179f9190612212565b6040518263ffffffff1660e01b81526004016117bb91906122a7565b600060405180830381600087803b1580156117d557600080fd5b505af11580156117e9573d6000803e3d6000fd5b50505050806001600160a01b03166326a40e82836001600160a01b031663d28459776040518163ffffffff1660e01b815260040160206040518083038186803b15801561183557600080fd5b505afa158015611849573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061186d9190612212565b6040518263ffffffff1660e01b815260040161188991906122a7565b600060405180830381600087803b1580156118a357600080fd5b505af11580156118b7573d6000803e3d6000fd5b50505050806001600160a01b031663a6b1ae0d836001600160a01b031663bbafcb406040518163ffffffff1660e01b815260040160206040518083038186803b15801561190357600080fd5b505afa158015611917573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061193b9190612212565b6040518263ffffffff1660e01b815260040161195791906122a7565b600060405180830381600087803b15801561197157600080fd5b505af1158015611985573d6000803e3d6000fd5b50505050806001600160a01b03166336d91494836001600160a01b031663ce78290d6040518163ffffffff1660e01b815260040160206040518083038186803b1580156119d157600080fd5b505afa1580156119e5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a099190612212565b6040518263ffffffff1660e01b8152600401611a2591906122a7565b600060405180830381600087803b158015611a3f57600080fd5b505af1158015611a53573d6000803e3d6000fd5b50505050806001600160a01b031663033669cf836001600160a01b0316631cd724ac6040518163ffffffff1660e01b815260040160206040518083038186803b158015611a9f57600080fd5b505afa158015611ab3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ad79190612212565b6040518263ffffffff1660e01b8152600401611af391906122a7565b600060405180830381600087803b158015611b0d57600080fd5b505af1158015611b21573d6000803e3d6000fd5b5050505050505050565b600082611b3a57506000610388565b82820282848281611b4757fe5b04146103855760405162461bcd60e51b8152600401611b659061233a565b60405180910390fd5b600061038583836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250611d2b565b600061038583836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250611d62565b6000828201838110156103855760405162461bcd60e51b8152600401611b6590612303565b81516040830151608083015130917f42a55d7508b1c40b53524cf7cc2558b0f6bc7c4f262a3e929b65cd48bec2b68791611c52908290611bb0565b60608088015190870151611c67908290611bb0565b604051611c7794939291906123d6565b60405180910390a35050565b611c8b611dde565b604080516020810190915280611ca984670de0b6b3a7640000611b2b565b905292915050565b611cb9611dde565b6040805160208101909152825184518291611ce09161037f90670de0b6b3a7640000611b2b565b90529392505050565b611cf1611dde565b604080516020810190915283518190611ce09085611b2b565b611d12611dde565b604080516020810190915283518190611ce09085611b6e565b60008183611d4c5760405162461bcd60e51b8152600401611b6591906122b0565b506000838581611d5857fe5b0495945050505050565b60008184841115611d865760405162461bcd60e51b8152600401611b6591906122b0565b505050900390565b60405180606001604052806000815260200160008152602001600081525090565b6040518060a0016040528060008152602001600081526020016000815260200160008152602001600081525090565b6040518060200160405280600081525090565b60006101808284031215611e03578081fd5b611e0d60806123ff565b9050611e198383611e84565b8152611e288360a08401611e84565b60208201526101408201356040820152610160820135606082015292915050565b600060608284031215611e5a578081fd5b611e6460606123ff565b905081358152602082013560208201526040820135604082015292915050565b600060a08284031215611e95578081fd5b611e9f60a06123ff565b9050813581526020820135602082015260408201356040820152606082013560608201526080820135608082015292915050565b600060208284031215611ee4578081fd5b813561038581612426565b60008060408385031215611f01578081fd5b8235611f0c81612426565b91506020830135611f1c81612426565b809150509250929050565b60008060008060008060c08789031215611f3f578182fd5b863595506020870135945060408701359350606087013592506080870135915060a0870135611f6d81612426565b809150509295509295509295565b600080600080600080600060e0888a031215611f95578081fd5b873596506020880135955060408801359450606088013593506080880135925060a0880135611fc381612426565b8092505060c0880135905092959891949750929550565b60008060006101c08486031215611fef578283fd5b611ff98585611df1565b925061018084013561200a81612426565b929592945050506101a0919091013590565b6000806000806101e08587031215612032578384fd5b61203c8686611df1565b935061018085013561204d81612426565b93969395505050506101a0820135916101c0013590565b60008060006101c08486031215612079578081fd5b6120838585611df1565b9561018085013595506101a0909401359392505050565b60008060008060c085870312156120af578182fd5b8435935060208501359250604085013591506120ce8660608701611e49565b905092959194509250565b600080600080600060e086880312156120f0578283fd5b853594506020860135935060408601359250606086013591506121168760808801611e49565b90509295509295909350565b60008060006102408486031215612137578081fd5b6121418585611e84565b925060a084013591506121578560c08601611df1565b90509250925092565b60008082840360c0811215612173578283fd5b8335925060a0601f1982011215612188578182fd5b5061219360a06123ff565b60208401356121a181612426565b8082525060408401356020820152606084013560408201526080840135606082015260a08401356080820152809150509250929050565b600080600080600060a086880312156121ef578283fd5b505083359560208501359550604085013594606081013594506080013592509050565b600060208284031215612223578081fd5b5051919050565b6000806040838503121561223c578182fd5b50508035926020909101359150565b60008060006060848603121561225f578081fd5b505081359360208301359350604090920135919050565b6000806000806080858703121561228b578182fd5b5050823594602084013594506040840135936060013592509050565b90815260200190565b6000602080835283518082850152825b818110156122dc578581018301518582016040015282016122c0565b818111156122ed5783604083870101525b50601f01601f1916929092016040019392505050565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b600060a082019050825182526020830151602083015260408301516040830152606083015160608301526080830151608083015292915050565b81518152602080830151908201526040918201519181019190915260600190565b93845260208401929092526040830152606082015260800190565b918252602082015260400190565b60405181810167ffffffffffffffff8111828210171561241e57600080fd5b604052919050565b6001600160a01b038116811461243b57600080fd5b5056fea26469706673582212201e8f11b622618543f96d2ae542c01b297404f284ce26224e73a61069281f236e64736f6c634300060c0033
Deployed Bytecode
0x739bce1f08012dd6e72756cd015e50068f90963d2230146080604052600436106101415760003560e01c80638c48a764116100c2578063bfaa8cca11610086578063bfaa8cca146102e6578063cde88845146102ee578063cee38ee414610301578063d8eb673e14610314578063f7fc24b214610334578063ff0825bc1461034757610141565b80638c48a764146102605780638e3875b6146102805780639d82cfd2146102a0578063a59387cd146102b3578063af5f5753146102d357610141565b80635df6b2ed116101095780635df6b2ed146101e557806368dcfdc0146101f85780636dd0a9b51461020057806384810cb01461022057806385bd324d1461023357610141565b80630174b449146101465780630a9f9a141461016f57806321a0aa7d146101915780632e76cb89146101a457806330785368146101c5575b600080fd5b61015961015436600461222a565b610367565b60405161016691906122a7565b60405180910390f35b81801561017b57600080fd5b5061018f61018a366004611ed3565b61038e565b005b61015961019f36600461224b565b6104b1565b6101b76101b2366004612276565b6104e0565b6040516101669291906123f1565b8180156101d157600080fd5b506101596101e0366004611f27565b61053a565b6101b76101f3366004611fda565b610876565b6101596109d1565b81801561020c57600080fd5b506101b761021b3660046121d8565b6109dd565b61015961022e366004612064565b610a2f565b81801561023f57600080fd5b5061025361024e366004611f7b565b610a48565b604051610166919061237b565b81801561026c57600080fd5b506101b761027b3660046121d8565b610dc3565b61029361028e36600461201c565b610e11565b60405161016691906123b5565b6101596102ae366004612122565b610e4b565b8180156102bf57600080fd5b506102536102ce3660046120d9565b610e69565b6101596102e1366004612122565b6110e1565b610159611118565b6101596102fc36600461222a565b61111d565b61015961030f36600461224b565b611149565b81801561032057600080fd5b5061025361032f36600461209a565b6111a2565b6101b7610342366004612160565b611373565b81801561035357600080fd5b5061018f610362366004611eef565b6113dd565b6000610385670de0b6b3a764000061037f8585611b2b565b90611b6e565b90505b92915050565b604051637d8b34e560e11b815281906001600160a01b0382169063fb1669ca906103bd906000906004016122a7565b600060405180830381600087803b1580156103d757600080fd5b505af11580156103eb573d6000803e3d6000fd5b50506040516327ea6f2b60e01b81526001600160a01b03841692506327ea6f2b915061041c906000906004016122a7565b600060405180830381600087803b15801561043657600080fd5b505af115801561044a573d6000803e3d6000fd5b5050604051632fe2f3b960e21b81526001600160a01b038416925063bf8bcee4915061047b906000906004016122a7565b600060405180830381600087803b15801561049557600080fd5b505af11580156104a9573d6000803e3d6000fd5b505050505050565b6000828410156104bf578293505b60006104cb8585611bb0565b90506104d78184610367565b95945050505050565b6000808515806104ee575083155b156104fd575084905083610531565b83861015610509578593505b6000610515858561111d565b90506105218786611bb0565b61052b8783611bf2565b92509250505b94509492505050565b6000805b875481101561086b5761054f611d8e565b61061f89838154811061055e57fe5b90600052602060002090600c0201604051806080016040529081600082016040518060a0016040529081600082015481526020016001820154815260200160028201548152602001600382015481526020016004820154815250508152602001600582016040518060a0016040529081600082015481526020016001820154815260200160028201548152602001600382015481526020016004820154815250508152602001600a8201548152602001600b82015481525050858789610e11565b9050610629611daf565b6107ea8a848154811061063857fe5b90600052602060002090600c02016107158c868154811061065557fe5b90600052602060002090600c0201604051806080016040529081600082016040518060a0016040529081600082015481526020016001820154815260200160028201548152602001600382015481526020016004820154815250508152602001600582016040518060a0016040529081600082015481526020016001820154815260200160028201548152602001600382015481526020016004820154815250508152602001600a8201548152602001600b820154815250508c8a610a2f565b6107e48d878154811061072457fe5b90600052602060002090600c0201604051806080016040529081600082016040518060a0016040529081600082015481526020016001820154815260200160028201548152602001600382015481526020016004820154815250508152602001600582016040518060a0016040529081600082015481526020016001820154815260200160028201548152602001600382015481526020016004820154815250508152602001600a8201548152602001600b820154815250508c8b610a2f565b856111a2565b905061084f8a84815481106107fb57fe5b90600052602060002090600c02016005016040518060a00160405290816000820154815260200160018201548152602001600282015481526020016003820154815260200160048201548152505082611c17565b604081015161085f908590611bf2565b9350505060010161053e565b509695505050505050565b600080836001600160a01b031663193501146040518163ffffffff1660e01b815260040160206040518083038186803b1580156108b257600080fd5b505afa1580156108c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108ea9190612212565b90506109718161096b866001600160a01b031663b69ef8a86040518163ffffffff1660e01b815260040160206040518083038186803b15801561092c57600080fd5b505afa158015610940573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109649190612212565b8690611bb0565b90611bf2565b905061097e858285610a2f565b905060006109a5866020015160200151876000015160200151611bf290919063ffffffff16565b90506109c28261096b886060015184611bb090919063ffffffff16565b60409096015196945050505050565b670de0b6b3a764000081565b60008060008760010154905060006109fb888a6003015488856104e0565b60038b0181905560028b01549199509150610a1990889087856104e0565b60029a909a019990995550959795505050505050565b6000610a4083856060015184611149565b949350505050565b610a50611daf565b610a58611daf565b60005b8954811015610db657610a6c611d8e565b610b3c8b8381548110610a7b57fe5b90600052602060002090600c0201604051806080016040529081600082016040518060a0016040529081600082015481526020016001820154815260200160028201548152602001600382015481526020016004820154815250508152602001600582016040518060a0016040529081600082015481526020016001820154815260200160028201548152602001600382015481526020016004820154815250508152602001600a8201548152602001600b8201548152505087898b610e11565b9050610b46611daf565b610d088c8481548110610b5557fe5b90600052602060002090600c0201610c328e8681548110610b7257fe5b90600052602060002090600c0201604051806080016040529081600082016040518060a0016040529081600082015481526020016001820154815260200160028201548152602001600382015481526020016004820154815250508152602001600582016040518060a0016040529081600082015481526020016001820154815260200160028201548152602001600382015481526020016004820154815250508152602001600a8201548152602001600b820154815250508e8c610a2f565b610d018f8781548110610c4157fe5b90600052602060002090600c0201604051806080016040529081600082016040518060a0016040529081600082015481526020016001820154815260200160028201548152602001600382015481526020016004820154815250508152602001600582016040518060a0016040529081600082015481526020016001820154815260200160028201548152602001600382015481526020016004820154815250508152602001600a8201548152602001600b820154815250508e8d610a2f565b8986610e69565b9050610d6d8c8481548110610d1957fe5b90600052602060002090600c02016000016040518060a00160405290816000820154815260200160018201548152602001600282015481526020016003820154815260200160048201548152505082611c17565b80518451610d7a91611bf2565b845260208082015190850151610d8f91611bf2565b602085015260408082015190850151610da791611bf2565b60408501525050600101610a5b565b5098975050505050505050565b6000806000610ddb8589600301548a600101546104b1565b90506000610df2858a600201548b600101546104b1565b9050610e0189898985856109dd565b9350935050509550959350505050565b610e19611d8e565b600080610e27878787610876565b60408051606081018252878152602081019390935282015292505050949350505050565b600080610e5c84866020015161111d565b90506104d78582856110e1565b610e71611daf565b6040805160a08082018352885480835260018a0154602080850182905260028c015485870181905260038d0154606080880182905260048f01546080808a018290528c8601518b5161012081018d52808301998a52808b019890985260c088019590955260e08701939093526101008601529484528751958601885260058e0154865260068e01548684015260078e01548689015260088e01548686015260098e01549086015290820193909352600a8b015494810194909452600b8a015490840152600092610f42929190610e4b565b90506000611040886000016040518060a00160405290816000820154815260200160018201548152602001600282015481526020016003820154815260200160048201548152505085604001518a604051806080016040529081600082016040518060a0016040529081600082015481526020016001820154815260200160028201548152602001600382015481526020016004820154815250508152602001600582016040518060a0016040529081600082015481526020016001820154815260200160028201548152602001600382015481526020016004820154815250508152602001600a8201548152602001600b82015481525050610e4b565b905060006110718361106a61106288600001518a611bf290919063ffffffff16565b606490611bb0565b6064611149565b905060006110858987600001516064611149565b90506110918982611bb0565b60038b015460028c0154919a50906110ac8c8c8c8789610dc3565b6040805160a0810182529283526020830191909152810193909352606083019190915260808201529998505050505050505050565b600080611107836000015160200151846020015160200151611bf290919063ffffffff16565b90506104d784866020015183611149565b606481565b600081156111405761113b8261037f85670de0b6b3a7640000611b2b565b610385565b50600092915050565b6000611153611dde565b61115c83611c83565b9050611166611dde565b61116f85611c83565b9050611197670de0b6b3a76400006111918861118b8587611cb1565b90611ce9565b90611d0a565b519695505050505050565b6111aa611daf565b60006111cb6111c086886005016001015461111d565b600888015490611bf2565b905060006112c9876005016040518060a001604052908160008201548152602001600182015481526020016002820154815260200160038201548152602001600482015481525050856040015189604051806080016040529081600082016040518060a0016040529081600082015481526020016001820154815260200160028201548152602001600382015481526020016004820154815250508152602001600582016040518060a0016040529081600082015481526020016001820154815260200160028201548152602001600382015481526020016004820154815250508152602001600a8201548152602001600b82015481525050610e4b565b60088801546007890154919250906112e760058a0189898787610dc3565b90985096506112f68888611bf2565b9750600061130a8888600001516064611149565b90506113168982611bb0565b98506000975061134060058b0161132d8b8b611bf2565b60006113398d8d611bf2565b60006109dd565b6040805160a081018252928352602083019190915281019190915260608101929092526080820152979650505050505050565b600080600061138a85600201548560400151610367565b905060006113a086600301548660400151610367565b90506113b9856080015182611bb090919063ffffffff16565b93506113d2856060015183611bb090919063ffffffff16565b925050509250929050565b60008290506000829050806001600160a01b031663fb1669ca836001600160a01b031663b69ef8a86040518163ffffffff1660e01b815260040160206040518083038186803b15801561142f57600080fd5b505afa158015611443573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114679190612212565b6040518263ffffffff1660e01b815260040161148391906122a7565b600060405180830381600087803b15801561149d57600080fd5b505af11580156114b1573d6000803e3d6000fd5b50505050806001600160a01b03166327ea6f2b836001600160a01b031663a4d66daf6040518163ffffffff1660e01b815260040160206040518083038186803b1580156114fd57600080fd5b505afa158015611511573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115359190612212565b6040518263ffffffff1660e01b815260040161155191906122a7565b600060405180830381600087803b15801561156b57600080fd5b505af115801561157f573d6000803e3d6000fd5b50505050806001600160a01b03166396c8df37836001600160a01b03166321856b366040518163ffffffff1660e01b815260040160206040518083038186803b1580156115cb57600080fd5b505afa1580156115df573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116039190612212565b6040518263ffffffff1660e01b815260040161161f91906122a7565b600060405180830381600087803b15801561163957600080fd5b505af115801561164d573d6000803e3d6000fd5b50505050806001600160a01b031663b3b8a9c7836001600160a01b031663193501146040518163ffffffff1660e01b815260040160206040518083038186803b15801561169957600080fd5b505afa1580156116ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116d19190612212565b6040518263ffffffff1660e01b81526004016116ed91906122a7565b600060405180830381600087803b15801561170757600080fd5b505af115801561171b573d6000803e3d6000fd5b50505050806001600160a01b0316637ae14b09836001600160a01b03166364fb2d956040518163ffffffff1660e01b815260040160206040518083038186803b15801561176757600080fd5b505afa15801561177b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061179f9190612212565b6040518263ffffffff1660e01b81526004016117bb91906122a7565b600060405180830381600087803b1580156117d557600080fd5b505af11580156117e9573d6000803e3d6000fd5b50505050806001600160a01b03166326a40e82836001600160a01b031663d28459776040518163ffffffff1660e01b815260040160206040518083038186803b15801561183557600080fd5b505afa158015611849573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061186d9190612212565b6040518263ffffffff1660e01b815260040161188991906122a7565b600060405180830381600087803b1580156118a357600080fd5b505af11580156118b7573d6000803e3d6000fd5b50505050806001600160a01b031663a6b1ae0d836001600160a01b031663bbafcb406040518163ffffffff1660e01b815260040160206040518083038186803b15801561190357600080fd5b505afa158015611917573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061193b9190612212565b6040518263ffffffff1660e01b815260040161195791906122a7565b600060405180830381600087803b15801561197157600080fd5b505af1158015611985573d6000803e3d6000fd5b50505050806001600160a01b03166336d91494836001600160a01b031663ce78290d6040518163ffffffff1660e01b815260040160206040518083038186803b1580156119d157600080fd5b505afa1580156119e5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a099190612212565b6040518263ffffffff1660e01b8152600401611a2591906122a7565b600060405180830381600087803b158015611a3f57600080fd5b505af1158015611a53573d6000803e3d6000fd5b50505050806001600160a01b031663033669cf836001600160a01b0316631cd724ac6040518163ffffffff1660e01b815260040160206040518083038186803b158015611a9f57600080fd5b505afa158015611ab3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ad79190612212565b6040518263ffffffff1660e01b8152600401611af391906122a7565b600060405180830381600087803b158015611b0d57600080fd5b505af1158015611b21573d6000803e3d6000fd5b5050505050505050565b600082611b3a57506000610388565b82820282848281611b4757fe5b04146103855760405162461bcd60e51b8152600401611b659061233a565b60405180910390fd5b600061038583836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250611d2b565b600061038583836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250611d62565b6000828201838110156103855760405162461bcd60e51b8152600401611b6590612303565b81516040830151608083015130917f42a55d7508b1c40b53524cf7cc2558b0f6bc7c4f262a3e929b65cd48bec2b68791611c52908290611bb0565b60608088015190870151611c67908290611bb0565b604051611c7794939291906123d6565b60405180910390a35050565b611c8b611dde565b604080516020810190915280611ca984670de0b6b3a7640000611b2b565b905292915050565b611cb9611dde565b6040805160208101909152825184518291611ce09161037f90670de0b6b3a7640000611b2b565b90529392505050565b611cf1611dde565b604080516020810190915283518190611ce09085611b2b565b611d12611dde565b604080516020810190915283518190611ce09085611b6e565b60008183611d4c5760405162461bcd60e51b8152600401611b6591906122b0565b506000838581611d5857fe5b0495945050505050565b60008184841115611d865760405162461bcd60e51b8152600401611b6591906122b0565b505050900390565b60405180606001604052806000815260200160008152602001600081525090565b6040518060a0016040528060008152602001600081526020016000815260200160008152602001600081525090565b6040518060200160405280600081525090565b60006101808284031215611e03578081fd5b611e0d60806123ff565b9050611e198383611e84565b8152611e288360a08401611e84565b60208201526101408201356040820152610160820135606082015292915050565b600060608284031215611e5a578081fd5b611e6460606123ff565b905081358152602082013560208201526040820135604082015292915050565b600060a08284031215611e95578081fd5b611e9f60a06123ff565b9050813581526020820135602082015260408201356040820152606082013560608201526080820135608082015292915050565b600060208284031215611ee4578081fd5b813561038581612426565b60008060408385031215611f01578081fd5b8235611f0c81612426565b91506020830135611f1c81612426565b809150509250929050565b60008060008060008060c08789031215611f3f578182fd5b863595506020870135945060408701359350606087013592506080870135915060a0870135611f6d81612426565b809150509295509295509295565b600080600080600080600060e0888a031215611f95578081fd5b873596506020880135955060408801359450606088013593506080880135925060a0880135611fc381612426565b8092505060c0880135905092959891949750929550565b60008060006101c08486031215611fef578283fd5b611ff98585611df1565b925061018084013561200a81612426565b929592945050506101a0919091013590565b6000806000806101e08587031215612032578384fd5b61203c8686611df1565b935061018085013561204d81612426565b93969395505050506101a0820135916101c0013590565b60008060006101c08486031215612079578081fd5b6120838585611df1565b9561018085013595506101a0909401359392505050565b60008060008060c085870312156120af578182fd5b8435935060208501359250604085013591506120ce8660608701611e49565b905092959194509250565b600080600080600060e086880312156120f0578283fd5b853594506020860135935060408601359250606086013591506121168760808801611e49565b90509295509295909350565b60008060006102408486031215612137578081fd5b6121418585611e84565b925060a084013591506121578560c08601611df1565b90509250925092565b60008082840360c0811215612173578283fd5b8335925060a0601f1982011215612188578182fd5b5061219360a06123ff565b60208401356121a181612426565b8082525060408401356020820152606084013560408201526080840135606082015260a08401356080820152809150509250929050565b600080600080600060a086880312156121ef578283fd5b505083359560208501359550604085013594606081013594506080013592509050565b600060208284031215612223578081fd5b5051919050565b6000806040838503121561223c578182fd5b50508035926020909101359150565b60008060006060848603121561225f578081fd5b505081359360208301359350604090920135919050565b6000806000806080858703121561228b578182fd5b5050823594602084013594506040840135936060013592509050565b90815260200190565b6000602080835283518082850152825b818110156122dc578581018301518582016040015282016122c0565b818111156122ed5783604083870101525b50601f01601f1916929092016040019392505050565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b600060a082019050825182526020830151602083015260408301516040830152606083015160608301526080830151608083015292915050565b81518152602080830151908201526040918201519181019190915260600190565b93845260208401929092526040830152606082015260800190565b918252602082015260400190565b60405181810167ffffffffffffffff8111828210171561241e57600080fd5b604052919050565b6001600160a01b038116811461243b57600080fd5b5056fea26469706673582212201e8f11b622618543f96d2ae542c01b297404f284ce26224e73a61069281f236e64736f6c634300060c0033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.