Feature Tip: Add private address tag to any address under My Name Tag !
More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 3,775 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Deposit | 20452883 | 153 days ago | IN | 0 ETH | 0.00020636 | ||||
Withdraw | 14422827 | 1020 days ago | IN | 0 ETH | 0.00256101 | ||||
Withdraw | 14300284 | 1039 days ago | IN | 0 ETH | 0.00898921 | ||||
Withdraw | 13308688 | 1194 days ago | IN | 0 ETH | 0.01089523 | ||||
Withdraw | 13291676 | 1197 days ago | IN | 0 ETH | 0.00813474 | ||||
Withdraw | 13275684 | 1199 days ago | IN | 0 ETH | 0.00751046 | ||||
Withdraw | 13274732 | 1199 days ago | IN | 0 ETH | 0.00851364 | ||||
Withdraw | 13273743 | 1200 days ago | IN | 0 ETH | 0.00807814 | ||||
Withdraw | 13273592 | 1200 days ago | IN | 0 ETH | 0.00832392 | ||||
Withdraw | 13273493 | 1200 days ago | IN | 0 ETH | 0.01225424 | ||||
Withdraw | 13273361 | 1200 days ago | IN | 0 ETH | 0.01153431 | ||||
Claim | 13223829 | 1207 days ago | IN | 0 ETH | 0.00527398 | ||||
Withdraw | 13176357 | 1215 days ago | IN | 0 ETH | 0.01479308 | ||||
Withdraw | 13173018 | 1215 days ago | IN | 0 ETH | 0.01777096 | ||||
Withdraw | 13169814 | 1216 days ago | IN | 0 ETH | 0.01705448 | ||||
Withdraw | 13162320 | 1217 days ago | IN | 0 ETH | 0.01956109 | ||||
Claim | 13162119 | 1217 days ago | IN | 0 ETH | 0.0134961 | ||||
Withdraw | 13156398 | 1218 days ago | IN | 0 ETH | 0.02621902 | ||||
Claim | 13120022 | 1223 days ago | IN | 0 ETH | 0.00656936 | ||||
Withdraw | 13117433 | 1224 days ago | IN | 0 ETH | 0.06011406 | ||||
Claim | 13117370 | 1224 days ago | IN | 0 ETH | 0.01301678 | ||||
Withdraw | 13114667 | 1224 days ago | IN | 0 ETH | 0.01010811 | ||||
Claim | 13114647 | 1224 days ago | IN | 0 ETH | 0.01090665 | ||||
Withdraw | 13082872 | 1229 days ago | IN | 0 ETH | 0.0102425 | ||||
Withdraw | 13082830 | 1229 days ago | IN | 0 ETH | 0.0100981 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
StakingDFL
Compiler Version
v0.5.17+commit.d19bba13
Contract Source Code (Solidity)
/** *Submitted for verification at Etherscan.io on 2020-11-20 */ // File: contracts\EIP20Interface.sol pragma solidity ^0.5.8; /** * @title ERC 20 Token Standard Interface * https://eips.ethereum.org/EIPS/eip-20 */ interface EIP20Interface { /** * @notice Get the total number of tokens in circulation * @return The supply of tokens */ function totalSupply() external view returns (uint256); /** * @notice Gets the balance of the specified address * @param owner The address from which the balance will be retrieved * @return The balance */ function balanceOf(address owner) external view returns (uint256 balance); /** * @notice Transfer `amount` tokens from `msg.sender` to `dst` * @param dst The address of the destination account * @param amount The number of tokens to transfer * @return Whether or not the transfer succeeded */ function transfer(address dst, uint256 amount) external returns (bool success); /** * @notice Transfer `amount` tokens from `src` to `dst` * @param src The address of the source account * @param dst The address of the destination account * @param amount The number of tokens to transfer * @return Whether or not the transfer succeeded */ function transferFrom(address src, address dst, uint256 amount) external returns (bool success); /** * @notice Approve `spender` to transfer up to `amount` from `src` * @dev This will overwrite the approval amount for `spender` * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) * @param spender The address of the account which may transfer tokens * @param amount The number of tokens that are approved (-1 means infinite) * @return Whether or not the approval succeeded */ function approve(address spender, uint256 amount) external returns (bool success); /** * @notice Get the current allowance from `owner` for `spender` * @param owner The address of the account which owns the tokens to be spent * @param spender The address of the account which may transfer tokens * @return The number of tokens allowed to be spent (-1 means infinite) */ function allowance(address owner, address spender) external view returns (uint256 remaining); event Transfer(address indexed from, address indexed to, uint256 amount); event Approval(address indexed owner, address indexed spender, uint256 amount); } // File: contracts\EIP20NonStandardInterface.sol pragma solidity ^0.5.8; /** * @title EIP20NonStandardInterface * @dev Version of ERC20 with no return values for `transfer` and `transferFrom` * See https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca */ interface EIP20NonStandardInterface { /** * @notice Get the total number of tokens in circulation * @return The supply of tokens */ function totalSupply() external view returns (uint256); /** * @notice Gets the balance of the specified address * @param owner The address from which the balance will be retrieved * @return The balance */ function balanceOf(address owner) external view returns (uint256 balance); /// /// !!!!!!!!!!!!!! /// !!! NOTICE !!! `transfer` does not return a value, in violation of the ERC-20 specification /// !!!!!!!!!!!!!! /// /** * @notice Transfer `amount` tokens from `msg.sender` to `dst` * @param dst The address of the destination account * @param amount The number of tokens to transfer */ function transfer(address dst, uint256 amount) external; /// /// !!!!!!!!!!!!!! /// !!! NOTICE !!! `transferFrom` does not return a value, in violation of the ERC-20 specification /// !!!!!!!!!!!!!! /// /** * @notice Transfer `amount` tokens from `src` to `dst` * @param src The address of the source account * @param dst The address of the destination account * @param amount The number of tokens to transfer */ function transferFrom(address src, address dst, uint256 amount) external; /** * @notice Approve `spender` to transfer up to `amount` from `src` * @dev This will overwrite the approval amount for `spender` * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) * @param spender The address of the account which may transfer tokens * @param amount The number of tokens that are approved * @return Whether or not the approval succeeded */ function approve(address spender, uint256 amount) external returns (bool success); /** * @notice Get the current allowance from `owner` for `spender` * @param owner The address of the account which owns the tokens to be spent * @param spender The address of the account which may transfer tokens * @return The number of tokens allowed to be spent */ function allowance(address owner, address spender) external view returns (uint256 remaining); event Transfer(address indexed from, address indexed to, uint256 amount); event Approval(address indexed owner, address indexed spender, uint256 amount); } // File: contracts\CarefulMath.sol // File: contracts/CarefulMath.sol pragma solidity ^0.5.8; /** * @title Careful Math * @author Compound * @notice Derived from OpenZeppelin's SafeMath library * https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/math/SafeMath.sol */ contract CarefulMath { /** * @dev Possible error codes that we can return */ enum MathError { NO_ERROR, DIVISION_BY_ZERO, INTEGER_OVERFLOW, INTEGER_UNDERFLOW } /** * @dev Multiplies two numbers, returns an error on overflow. */ function mulUInt(uint a, uint b) internal pure returns (MathError, uint) { if (a == 0) { return (MathError.NO_ERROR, 0); } uint c = a * b; if (c / a != b) { return (MathError.INTEGER_OVERFLOW, 0); } else { return (MathError.NO_ERROR, c); } } /** * @dev Integer division of two numbers, truncating the quotient. */ function divUInt(uint a, uint b) internal pure returns (MathError, uint) { if (b == 0) { return (MathError.DIVISION_BY_ZERO, 0); } return (MathError.NO_ERROR, a / b); } /** * @dev Subtracts two numbers, returns an error on overflow (i.e. if subtrahend is greater than minuend). */ function subUInt(uint a, uint b) internal pure returns (MathError, uint) { if (b <= a) { return (MathError.NO_ERROR, a - b); } else { return (MathError.INTEGER_UNDERFLOW, 0); } } /** * @dev Adds two numbers, returns an error on overflow. */ function addUInt(uint a, uint b) internal pure returns (MathError, uint) { uint c = a + b; if (c >= a) { return (MathError.NO_ERROR, c); } else { return (MathError.INTEGER_OVERFLOW, 0); } } /** * @dev add a and b and then subtract c */ function addThenSubUInt(uint a, uint b, uint c) internal pure returns (MathError, uint) { (MathError err0, uint sum) = addUInt(a, b); if (err0 != MathError.NO_ERROR) { return (err0, 0); } return subUInt(sum, c); } } // File: contracts\Exponential.sol pragma solidity ^0.5.16; /** * @title Exponential module for storing fixed-precision decimals * @author Compound * @notice Exp is a struct which stores decimals with a fixed precision of 18 decimal places. * Thus, if we wanted to store the 5.1, mantissa would store 5.1e18. That is: * `Exp({mantissa: 5100000000000000000})`. */ contract Exponential is CarefulMath { uint constant expScale = 1e18; uint constant doubleScale = 1e36; uint constant halfExpScale = expScale/2; uint constant mantissaOne = expScale; struct Exp { uint mantissa; } struct Double { uint mantissa; } /** * @dev Creates an exponential from numerator and denominator values. * Note: Returns an error if (`num` * 10e18) > MAX_INT, * or if `denom` is zero. */ function getExp(uint num, uint denom) pure internal returns (MathError, Exp memory) { (MathError err0, uint scaledNumerator) = mulUInt(num, expScale); if (err0 != MathError.NO_ERROR) { return (err0, Exp({mantissa: 0})); } (MathError err1, uint rational) = divUInt(scaledNumerator, denom); if (err1 != MathError.NO_ERROR) { return (err1, Exp({mantissa: 0})); } return (MathError.NO_ERROR, Exp({mantissa: rational})); } /** * @dev Adds two exponentials, returning a new exponential. */ function addExp(Exp memory a, Exp memory b) pure internal returns (MathError, Exp memory) { (MathError error, uint result) = addUInt(a.mantissa, b.mantissa); return (error, Exp({mantissa: result})); } /** * @dev Subtracts two exponentials, returning a new exponential. */ function subExp(Exp memory a, Exp memory b) pure internal returns (MathError, Exp memory) { (MathError error, uint result) = subUInt(a.mantissa, b.mantissa); return (error, Exp({mantissa: result})); } /** * @dev Multiply an Exp by a scalar, returning a new Exp. */ function mulScalar(Exp memory a, uint scalar) pure internal returns (MathError, Exp memory) { (MathError err0, uint scaledMantissa) = mulUInt(a.mantissa, scalar); if (err0 != MathError.NO_ERROR) { return (err0, Exp({mantissa: 0})); } return (MathError.NO_ERROR, Exp({mantissa: scaledMantissa})); } /** * @dev Multiply an Exp by a scalar, then truncate to return an unsigned integer. */ function mulScalarTruncate(Exp memory a, uint scalar) pure internal returns (MathError, uint) { (MathError err, Exp memory product) = mulScalar(a, scalar); if (err != MathError.NO_ERROR) { return (err, 0); } return (MathError.NO_ERROR, truncate(product)); } /** * @dev Multiply an Exp by a scalar, truncate, then add an to an unsigned integer, returning an unsigned integer. */ function mulScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (MathError, uint) { (MathError err, Exp memory product) = mulScalar(a, scalar); if (err != MathError.NO_ERROR) { return (err, 0); } return addUInt(truncate(product), addend); } /** * @dev Divide an Exp by a scalar, returning a new Exp. */ function divScalar(Exp memory a, uint scalar) pure internal returns (MathError, Exp memory) { (MathError err0, uint descaledMantissa) = divUInt(a.mantissa, scalar); if (err0 != MathError.NO_ERROR) { return (err0, Exp({mantissa: 0})); } return (MathError.NO_ERROR, Exp({mantissa: descaledMantissa})); } /** * @dev Divide a scalar by an Exp, returning a new Exp. */ function divScalarByExp(uint scalar, Exp memory divisor) pure internal returns (MathError, Exp memory) { /* We are doing this as: getExp(mulUInt(expScale, scalar), divisor.mantissa) How it works: Exp = a / b; Scalar = s; `s / (a / b)` = `b * s / a` and since for an Exp `a = mantissa, b = expScale` */ (MathError err0, uint numerator) = mulUInt(expScale, scalar); if (err0 != MathError.NO_ERROR) { return (err0, Exp({mantissa: 0})); } return getExp(numerator, divisor.mantissa); } /** * @dev Divide a scalar by an Exp, then truncate to return an unsigned integer. */ function divScalarByExpTruncate(uint scalar, Exp memory divisor) pure internal returns (MathError, uint) { (MathError err, Exp memory fraction) = divScalarByExp(scalar, divisor); if (err != MathError.NO_ERROR) { return (err, 0); } return (MathError.NO_ERROR, truncate(fraction)); } /** * @dev Multiplies two exponentials, returning a new exponential. */ function mulExp(Exp memory a, Exp memory b) pure internal returns (MathError, Exp memory) { (MathError err0, uint doubleScaledProduct) = mulUInt(a.mantissa, b.mantissa); if (err0 != MathError.NO_ERROR) { return (err0, Exp({mantissa: 0})); } // We add half the scale before dividing so that we get rounding instead of truncation. // See "Listing 6" and text above it at https://accu.org/index.php/journals/1717 // Without this change, a result like 6.6...e-19 will be truncated to 0 instead of being rounded to 1e-18. (MathError err1, uint doubleScaledProductWithHalfScale) = addUInt(halfExpScale, doubleScaledProduct); if (err1 != MathError.NO_ERROR) { return (err1, Exp({mantissa: 0})); } (MathError err2, uint product) = divUInt(doubleScaledProductWithHalfScale, expScale); // The only error `div` can return is MathError.DIVISION_BY_ZERO but we control `expScale` and it is not zero. assert(err2 == MathError.NO_ERROR); return (MathError.NO_ERROR, Exp({mantissa: product})); } /** * @dev Multiplies two exponentials given their mantissas, returning a new exponential. */ function mulExp(uint a, uint b) pure internal returns (MathError, Exp memory) { return mulExp(Exp({mantissa: a}), Exp({mantissa: b})); } /** * @dev Multiplies three exponentials, returning a new exponential. */ function mulExp3(Exp memory a, Exp memory b, Exp memory c) pure internal returns (MathError, Exp memory) { (MathError err, Exp memory ab) = mulExp(a, b); if (err != MathError.NO_ERROR) { return (err, ab); } return mulExp(ab, c); } /** * @dev Divides two exponentials, returning a new exponential. * (a/scale) / (b/scale) = (a/scale) * (scale/b) = a/b, * which we can scale as an Exp by calling getExp(a.mantissa, b.mantissa) */ function divExp(Exp memory a, Exp memory b) pure internal returns (MathError, Exp memory) { return getExp(a.mantissa, b.mantissa); } /** * @dev Truncates the given exp to a whole number value. * For example, truncate(Exp{mantissa: 15 * expScale}) = 15 */ function truncate(Exp memory exp) pure internal returns (uint) { // Note: We are not using careful math here as we're performing a division that cannot fail return exp.mantissa / expScale; } /** * @dev Checks if first Exp is less than second Exp. */ function lessThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { return left.mantissa < right.mantissa; } /** * @dev Checks if left Exp <= right Exp. */ function lessThanOrEqualExp(Exp memory left, Exp memory right) pure internal returns (bool) { return left.mantissa <= right.mantissa; } /** * @dev Checks if left Exp > right Exp. */ function greaterThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { return left.mantissa > right.mantissa; } /** * @dev returns true if Exp is exactly zero */ function isZeroExp(Exp memory value) pure internal returns (bool) { return value.mantissa == 0; } function safe224(uint n, string memory errorMessage) pure internal returns (uint224) { require(n < 2**224, errorMessage); return uint224(n); } function safe32(uint n, string memory errorMessage) pure internal returns (uint32) { require(n < 2**32, errorMessage); return uint32(n); } function add_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { return Exp({mantissa: add_(a.mantissa, b.mantissa)}); } function add_(Double memory a, Double memory b) pure internal returns (Double memory) { return Double({mantissa: add_(a.mantissa, b.mantissa)}); } function add_(uint a, uint b) pure internal returns (uint) { return add_(a, b, "addition overflow"); } function add_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { uint c = a + b; require(c >= a, errorMessage); return c; } function sub_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { return Exp({mantissa: sub_(a.mantissa, b.mantissa)}); } function sub_(Double memory a, Double memory b) pure internal returns (Double memory) { return Double({mantissa: sub_(a.mantissa, b.mantissa)}); } function sub_(uint a, uint b) pure internal returns (uint) { return sub_(a, b, "subtraction underflow"); } function sub_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { require(b <= a, errorMessage); return a - b; } function mul_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { return Exp({mantissa: mul_(a.mantissa, b.mantissa) / expScale}); } function mul_(Exp memory a, uint b) pure internal returns (Exp memory) { return Exp({mantissa: mul_(a.mantissa, b)}); } function mul_(uint a, Exp memory b) pure internal returns (uint) { return mul_(a, b.mantissa) / expScale; } function mul_(Double memory a, Double memory b) pure internal returns (Double memory) { return Double({mantissa: mul_(a.mantissa, b.mantissa) / doubleScale}); } function mul_(Double memory a, uint b) pure internal returns (Double memory) { return Double({mantissa: mul_(a.mantissa, b)}); } function mul_(uint a, Double memory b) pure internal returns (uint) { return mul_(a, b.mantissa) / doubleScale; } function mul_(uint a, uint b) pure internal returns (uint) { return mul_(a, b, "multiplication overflow"); } function mul_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { if (a == 0 || b == 0) { return 0; } uint c = a * b; require(c / a == b, errorMessage); return c; } function div_(Exp memory a, Exp memory b) pure internal returns (Exp memory) { return Exp({mantissa: div_(mul_(a.mantissa, expScale), b.mantissa)}); } function div_(Exp memory a, uint b) pure internal returns (Exp memory) { return Exp({mantissa: div_(a.mantissa, b)}); } function div_(uint a, Exp memory b) pure internal returns (uint) { return div_(mul_(a, expScale), b.mantissa); } function div_(Double memory a, Double memory b) pure internal returns (Double memory) { return Double({mantissa: div_(mul_(a.mantissa, doubleScale), b.mantissa)}); } function div_(Double memory a, uint b) pure internal returns (Double memory) { return Double({mantissa: div_(a.mantissa, b)}); } function div_(uint a, Double memory b) pure internal returns (uint) { return div_(mul_(a, doubleScale), b.mantissa); } function div_(uint a, uint b) pure internal returns (uint) { return div_(a, b, "divide by zero"); } function div_(uint a, uint b, string memory errorMessage) pure internal returns (uint) { require(b > 0, errorMessage); return a / b; } function fraction(uint a, uint b) pure internal returns (Double memory) { return Double({mantissa: div_(mul_(a, doubleScale), b)}); } } // File: contracts\SafeMath.sol pragma solidity ^0.5.16; // From https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/Math.sol // Subject to the MIT license. /** * @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 addition of two unsigned integers, reverting with custom message on overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * - Addition cannot overflow. */ function add(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, errorMessage); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on underflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot underflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { return sub(a, b, "SafeMath: subtraction underflow"); } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on underflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot underflow. */ 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 multiplication of two unsigned integers, reverting on overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b, string memory errorMessage) 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, errorMessage); 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; } } // File: contracts\ReentrancyGuard.sol pragma solidity ^0.5.16; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ contract ReentrancyGuard { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; constructor () internal { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and make it call a * `private` function that does the actual work. */ modifier nonReentrant() { // On the first call to nonReentrant, _notEntered will be true require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; _; // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } } // File: contracts\ErrorReporter.sol pragma solidity ^0.5.16; contract ErrorReporter { enum Error { NO_ERROR, UNAUTHORIZED, BAD_INPUT, REJECTION, MATH_ERROR, NOT_FRESH, TOKEN_INSUFFICIENT_CASH, TOKEN_TRANSFER_IN_FAILED, TOKEN_TRANSFER_OUT_FAILED, INSUFFICIENT_COLLATERAL } /* * Note: FailureInfo (but not Error) is kept in alphabetical order * This is because FailureInfo grows significantly faster, and * the order of Error has some meaning, while the order of FailureInfo * is entirely arbitrary. */ enum FailureInfo { ADMIN_CHECK, PARTICIPANT_CHECK, ACCRUE_INTEREST_FAILED, ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED, ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED, ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED, ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED, BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, BORROW_CASH_NOT_AVAILABLE, BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, BORROW_REJECTION, BORROW_INSUFFICIENT_COLLATERAL, MINT_REJECTION, MINT_EXCHANGE_CALCULATION_FAILED, MINT_EXCHANGE_RATE_READ_FAILED, MINT_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, MINT_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, REDEEM_EXCHANGE_TOKENS_CALCULATION_FAILED, REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED, REDEEM_EXCHANGE_RATE_READ_FAILED, REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, REDEEM_TRANSFER_OUT_NOT_POSSIBLE, REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, REPAY_BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, REPAY_BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, COLLATERALIZE_REJECTION, REDEEM_COLLATERAL_ACCUMULATED_BORROW_CALCULATION_FAILED, REDEEM_COLLATERAL_NEW_ACCOUNT_COLLATERAL_CALCULATION_FAILED, REDEEM_COLLATERAL_INSUFFICIENT_COLLATERAL, LIQUIDATE_BORROW_REJECTION, LIQUIDATE_BORROW_COLLATERAL_RATE_CALCULATION_FAILED, LIQUIDATE_BORROW_NOT_SATISFIED, SET_RESERVE_FACTOR_BOUNDS_CHECK, SET_LIQUIDATE_FACTOR_BOUNDS_CHECK, TRANSFER_NOT_ALLOWED, TRANSFER_NOT_ENOUGH, TRANSFER_TOO_MUCH } /** * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary * contract-specific code that enables us to report opaque error codes from upgradeable contracts. **/ event Failure(uint error, uint info, uint detail); /** * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator */ function fail(Error err, FailureInfo info) internal returns (uint) { emit Failure(uint(err), uint(info), 0); return uint(err); } /** * @dev use this when reporting an opaque error from an upgradeable collaborator contract */ function failOpaque(Error err, FailureInfo info, uint opaqueError) internal returns (uint) { emit Failure(uint(err), uint(info), opaqueError); return uint(err); } } // File: contracts\InterestRateModel.sol pragma solidity ^0.5.16; /** * @title Compound's InterestRateModel Interface * @author Compound */ contract InterestRateModel { /// @notice Indicator that this is an InterestRateModel contract (for inspection) bool public constant isInterestRateModel = true; /** * @notice Calculates the current borrow interest rate per block * @param cash The total amount of cash the market has * @param borrows The total amount of borrows the market has outstanding * @param reserves The total amnount of reserves the market has * @return The borrow rate per block (as a percentage, and scaled by 1e18) */ function getBorrowRate(uint cash, uint borrows, uint reserves) external view returns (uint); /** * @notice Calculates the current supply interest rate per block * @param cash The total amount of cash the market has * @param borrows The total amount of borrows the market has outstanding * @param reserves The total amnount of reserves the market has * @param reserveFactorMantissa The current reserve factor the market has * @return The supply rate per block (as a percentage, and scaled by 1e18) */ function getSupplyRate(uint cash, uint borrows, uint reserves, uint reserveFactorMantissa) external view returns (uint); } // File: contracts\DFL.sol pragma solidity ^0.5.16; pragma experimental ABIEncoderV2; // forked from Compound/COMP /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ contract Ownable { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor () internal { _owner = msg.sender; emit OwnershipTransferred(address(0), msg.sender); } /** * @dev Returns the address of the current owner. */ function owner() public view returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(_owner == msg.sender, "Ownable: caller is not the owner"); _; } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public onlyOwner { emit OwnershipTransferred(_owner, address(0)); _owner = address(0); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); emit OwnershipTransferred(_owner, newOwner); _owner = newOwner; } } contract DFL is EIP20Interface, Ownable { /// @notice EIP-20 token name for this token string public constant name = "DeFIL"; /// @notice EIP-20 token symbol for this token string public constant symbol = "DFL"; /// @notice EIP-20 token decimals for this token uint8 public constant decimals = 18; /// @notice Total number of tokens in circulation uint96 internal _totalSupply; /// @notice Allowance amounts on behalf of others mapping (address => mapping (address => uint96)) internal allowances; /// @notice Official record of token balances for each account mapping (address => uint96) internal balances; /// @notice A record of each accounts delegate mapping (address => address) public delegates; /// @notice A checkpoint for marking number of votes from a given block struct Checkpoint { uint32 fromBlock; uint96 votes; } /// @notice A record of votes checkpoints for each account, by index mapping (address => mapping (uint32 => Checkpoint)) public checkpoints; /// @notice The number of checkpoints for each account mapping (address => uint32) public numCheckpoints; /// @notice The EIP-712 typehash for the contract's domain bytes32 public constant DOMAIN_TYPEHASH = keccak256("EIP712Domain(string name,uint256 chainId,address verifyingContract)"); /// @notice The EIP-712 typehash for the delegation struct used by the contract bytes32 public constant DELEGATION_TYPEHASH = keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)"); /// @notice A record of states for signing / validating signatures mapping (address => uint) public nonces; /// @notice An event thats emitted when an account changes its delegate event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate); /// @notice An event thats emitted when a delegate account's vote balance changes event DelegateVotesChanged(address indexed delegate, uint previousBalance, uint newBalance); /// @notice The standard EIP-20 transfer event event Transfer(address indexed from, address indexed to, uint256 amount); /// @notice The standard EIP-20 approval event event Approval(address indexed owner, address indexed spender, uint256 amount); /** * @notice Construct a new DFL token */ constructor() public { emit Transfer(address(0), address(this), 0); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * Emits a {Transfer} event with `from` set to the zero address. * @param account The address of the account holding the new funds * @param rawAmount The number of tokens that are minted */ function mint(address account, uint rawAmount) public onlyOwner { require(account != address(0), "DFL:: mint: cannot mint to the zero address"); uint96 amount = safe96(rawAmount, "DFL::mint: amount exceeds 96 bits"); _totalSupply = add96(_totalSupply, amount, "DFL::mint: total supply exceeds"); balances[account] = add96(balances[account], amount, "DFL::mint: mint amount exceeds balance"); _moveDelegates(address(0), delegates[account], amount); emit Transfer(address(0), account, amount); } /** * @notice Get the number of tokens `spender` is approved to spend on behalf of `account` * @param account The address of the account holding the funds * @param spender The address of the account spending the funds * @return The number of tokens approved */ function allowance(address account, address spender) external view returns (uint) { return allowances[account][spender]; } /** * @notice Approve `spender` to transfer up to `amount` from `src` * @dev This will overwrite the approval amount for `spender` * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) * @param spender The address of the account which may transfer tokens * @param rawAmount The number of tokens that are approved (2^256-1 means infinite) * @return Whether or not the approval succeeded */ function approve(address spender, uint rawAmount) external returns (bool) { uint96 amount; if (rawAmount == uint(-1)) { amount = uint96(-1); } else { amount = safe96(rawAmount, "DFL::approve: amount exceeds 96 bits"); } allowances[msg.sender][spender] = amount; emit Approval(msg.sender, spender, amount); return true; } /** * @notice Get the total supply of tokens * @return The total supply of tokens */ function totalSupply() external view returns (uint) { return _totalSupply; } /** * @notice Get the number of tokens held by the `account` * @param account The address of the account to get the balance of * @return The number of tokens held */ function balanceOf(address account) external view returns (uint) { return balances[account]; } /** * @notice Transfer `amount` tokens from `msg.sender` to `dst` * @param dst The address of the destination account * @param rawAmount The number of tokens to transfer * @return Whether or not the transfer succeeded */ function transfer(address dst, uint rawAmount) external returns (bool) { uint96 amount = safe96(rawAmount, "DFL::transfer: amount exceeds 96 bits"); _transferTokens(msg.sender, dst, amount); return true; } /** * @notice Transfer `amount` tokens from `src` to `dst` * @param src The address of the source account * @param dst The address of the destination account * @param rawAmount The number of tokens to transfer * @return Whether or not the transfer succeeded */ function transferFrom(address src, address dst, uint rawAmount) external returns (bool) { address spender = msg.sender; uint96 spenderAllowance = allowances[src][spender]; uint96 amount = safe96(rawAmount, "DFL::approve: amount exceeds 96 bits"); if (spender != src && spenderAllowance != uint96(-1)) { uint96 newAllowance = sub96(spenderAllowance, amount, "DFL::transferFrom: transfer amount exceeds spender allowance"); allowances[src][spender] = newAllowance; emit Approval(src, spender, newAllowance); } _transferTokens(src, dst, amount); return true; } /** * @notice Delegate votes from `msg.sender` to `delegatee` * @param delegatee The address to delegate votes to */ function delegate(address delegatee) public { return _delegate(msg.sender, delegatee); } /** * @notice Delegates votes from signatory to `delegatee` * @param delegatee The address to delegate votes to * @param nonce The contract state required to match the signature * @param expiry The time at which to expire the signature * @param v The recovery byte of the signature * @param r Half of the ECDSA signature pair * @param s Half of the ECDSA signature pair */ function delegateBySig(address delegatee, uint nonce, uint expiry, uint8 v, bytes32 r, bytes32 s) public { bytes32 domainSeparator = keccak256(abi.encode(DOMAIN_TYPEHASH, keccak256(bytes(name)), getChainId(), address(this))); bytes32 structHash = keccak256(abi.encode(DELEGATION_TYPEHASH, delegatee, nonce, expiry)); bytes32 digest = keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash)); address signatory = ecrecover(digest, v, r, s); require(signatory != address(0), "DFL::delegateBySig: invalid signature"); require(nonce == nonces[signatory]++, "DFL::delegateBySig: invalid nonce"); require(block.timestamp <= expiry, "DFL::delegateBySig: signature expired"); return _delegate(signatory, delegatee); } /** * @notice Gets the current votes balance for `account` * @param account The address to get votes balance * @return The number of current votes for `account` */ function getCurrentVotes(address account) external view returns (uint96) { uint32 nCheckpoints = numCheckpoints[account]; return nCheckpoints > 0 ? checkpoints[account][nCheckpoints - 1].votes : 0; } /** * @notice Determine the prior number of votes for an account as of a block number * @dev Block number must be a finalized block or else this function will revert to prevent misinformation. * @param account The address of the account to check * @param blockNumber The block number to get the vote balance at * @return The number of votes the account had as of the given block */ function getPriorVotes(address account, uint blockNumber) public view returns (uint96) { require(blockNumber < block.number, "DFL::getPriorVotes: not yet determined"); uint32 nCheckpoints = numCheckpoints[account]; if (nCheckpoints == 0) { return 0; } // First check most recent balance if (checkpoints[account][nCheckpoints - 1].fromBlock <= blockNumber) { return checkpoints[account][nCheckpoints - 1].votes; } // Next check implicit zero balance if (checkpoints[account][0].fromBlock > blockNumber) { return 0; } uint32 lower = 0; uint32 upper = nCheckpoints - 1; while (upper > lower) { uint32 center = upper - (upper - lower) / 2; // ceil, avoiding overflow Checkpoint memory cp = checkpoints[account][center]; if (cp.fromBlock == blockNumber) { return cp.votes; } else if (cp.fromBlock < blockNumber) { lower = center; } else { upper = center - 1; } } return checkpoints[account][lower].votes; } function _delegate(address delegator, address delegatee) internal { address currentDelegate = delegates[delegator]; uint96 delegatorBalance = balances[delegator]; delegates[delegator] = delegatee; emit DelegateChanged(delegator, currentDelegate, delegatee); _moveDelegates(currentDelegate, delegatee, delegatorBalance); } function _transferTokens(address src, address dst, uint96 amount) internal { require(src != address(0), "DFL::_transferTokens: cannot transfer from the zero address"); require(dst != address(0), "DFL::_transferTokens: cannot transfer to the zero address"); balances[src] = sub96(balances[src], amount, "DFL::_transferTokens: transfer amount exceeds balance"); balances[dst] = add96(balances[dst], amount, "DFL::_transferTokens: transfer amount overflows"); emit Transfer(src, dst, amount); _moveDelegates(delegates[src], delegates[dst], amount); } function _moveDelegates(address srcRep, address dstRep, uint96 amount) internal { if (srcRep != dstRep && amount > 0) { if (srcRep != address(0)) { uint32 srcRepNum = numCheckpoints[srcRep]; uint96 srcRepOld = srcRepNum > 0 ? checkpoints[srcRep][srcRepNum - 1].votes : 0; uint96 srcRepNew = sub96(srcRepOld, amount, "DFL::_moveVotes: vote amount underflows"); _writeCheckpoint(srcRep, srcRepNum, srcRepOld, srcRepNew); } if (dstRep != address(0)) { uint32 dstRepNum = numCheckpoints[dstRep]; uint96 dstRepOld = dstRepNum > 0 ? checkpoints[dstRep][dstRepNum - 1].votes : 0; uint96 dstRepNew = add96(dstRepOld, amount, "DFL::_moveVotes: vote amount overflows"); _writeCheckpoint(dstRep, dstRepNum, dstRepOld, dstRepNew); } } } function _writeCheckpoint(address delegatee, uint32 nCheckpoints, uint96 oldVotes, uint96 newVotes) internal { uint32 blockNumber = safe32(block.number, "DFL::_writeCheckpoint: block number exceeds 32 bits"); if (nCheckpoints > 0 && checkpoints[delegatee][nCheckpoints - 1].fromBlock == blockNumber) { checkpoints[delegatee][nCheckpoints - 1].votes = newVotes; } else { checkpoints[delegatee][nCheckpoints] = Checkpoint(blockNumber, newVotes); numCheckpoints[delegatee] = nCheckpoints + 1; } emit DelegateVotesChanged(delegatee, oldVotes, newVotes); } function safe32(uint n, string memory errorMessage) internal pure returns (uint32) { require(n < 2**32, errorMessage); return uint32(n); } function safe96(uint n, string memory errorMessage) internal pure returns (uint96) { require(n < 2**96, errorMessage); return uint96(n); } function add96(uint96 a, uint96 b, string memory errorMessage) internal pure returns (uint96) { uint96 c = a + b; require(c >= a, errorMessage); return c; } function sub96(uint96 a, uint96 b, string memory errorMessage) internal pure returns (uint96) { require(b <= a, errorMessage); return a - b; } function getChainId() internal pure returns (uint) { uint256 chainId; assembly { chainId := chainid() } return chainId; } } // File: contracts\DeFIL.sol pragma solidity ^0.5.16; // Forked from Compound/CToken contract DeFIL is ReentrancyGuard, EIP20Interface, Exponential, ErrorReporter { /** * @notice EIP-20 token name for this token */ string public constant name = "Certificate of eFIL"; /** * @notice EIP-20 token symbol for this token */ string public constant symbol = "ceFIL"; /** * @notice EIP-20 token decimals for this token */ uint8 public constant decimals = 18; /** * @notice Maximum fraction of interest that can be set aside for reserves */ uint internal constant reserveFactorMaxMantissa = 1e18; /** * @notice Address of eFIL token */ address public eFILAddress; /** * @notice Address of mFIL token */ address public mFILAddress; /** * @notice The address who owns the reserves */ address public reservesOwner; /** * @notice Administrator for this contract */ address public admin; /** * @notice Pending administrator for this contract */ address public pendingAdmin; /** * @notice Model which tells what the current interest rate should be */ InterestRateModel public interestRateModel; /** * @notice Initial exchange rate used when minting the first CTokens (used when totalSupply = 0) */ uint internal constant initialExchangeRateMantissa = 0.002e18; // 1 eFIL = 500 ceFIL /** * @notice Fraction of interest currently set aside for reserves */ uint public reserveFactorMantissa; /** * @notice Block number that interest was last accrued at */ uint public accrualBlockNumber; /** * @notice Accumulator of the total earned interest rate since the opening */ uint public borrowIndex; /** * @notice Total amount of outstanding borrows of the underlying */ uint public totalBorrows; /** * @notice Total amount of reserves of the underlying held */ uint public totalReserves; /** * @notice Total number of tokens in circulation */ uint public totalSupply; // Is mint allowed. bool public mintAllowed; // Is borrow allowed. bool public borrowAllowed; /** * @notice Official record of token balances for each account */ mapping (address => uint) internal accountTokens; /** * @notice Approved token transfer amounts on behalf of others */ mapping (address => mapping (address => uint)) internal transferAllowances; /** * @notice Container for borrow balance information * @member principal Total balance (with accrued interest), after applying the most recent balance-changing action * @member interestIndex Global borrowIndex as of the most recent balance-changing action */ struct BorrowSnapshot { uint principal; uint interestIndex; } /** * @notice Mapping of account addresses to outstanding borrow balances */ mapping(address => BorrowSnapshot) internal accountBorrows; // Total collaterals uint public totalCollaterals; // Mapping of account to outstanding collateral balances mapping (address => uint) internal accountCollaterals; // Multiplier used to decide when liquidate borrow is allowed uint public liquidateFactorMantissa; // No liquidateFactorMantissa may bellows this value uint internal constant liquidateFactorMinMantissa = 1e18; // 100% /*** For DFL ***/ /** * @notice Address of DFL token */ DFL public dflToken; // By using the special 'min speed=0.00017e18' and 'start speed=86.805721e18' // We will got 99999999.8568 DFLs in the end. // The havle period in block number uint internal constant halvePeriod = 576000; // 100 days // Minimum speed uint internal constant minSpeed = 0.00017e18; // 1e18 / 5760 // Current speed (per block) uint public currentSpeed = 86.805721e18; // 500000e18 / 5760; // start with 500,000 per day // The block number when next havle will happens uint public nextHalveBlockNumber; // The address of uniswap incentive contract for receiving DFL address public uniswapAddress; // The address of miner league for receiving DFL address public minerLeagueAddress; // The address of operator for receiving DFL address public operatorAddress; // The address of technical support for receiving DFL address public technicalAddress; // The address for undistributed DFL address public undistributedAddress; // The percentage of DFL distributes to uniswap incentive uint public uniswapPercentage; // The percentage of DFL distributes to miner league uint public minerLeaguePercentage; // The percentage of DFL distributes to operator uint public operatorPercentage; // The percentage of DFL distributes to technical support, unupdatable uint internal constant technicalPercentage = 0.02e18; // 2% // The threshold above which the flywheel transfers DFL uint internal constant dflClaimThreshold = 0.1e18; // 0.1 DFL // Block number that DFL was last accrued at uint public dflAccrualBlockNumber; // The last updated index of DFL for suppliers uint public dflSupplyIndex; // The initial dfl supply index uint internal constant dflInitialSupplyIndex = 1e36; // The index for each supplier as of the last time they accrued DFL mapping(address => uint) public dflSupplierIndex; // The DFL accrued but not yet transferred to each user mapping(address => uint) public dflAccrued; /*** Events ***/ /** * @notice Event emitted when interest is accrued */ event AccrueInterest(uint cashPrior, uint interestAccumulated, uint borrowIndex, uint totalBorrows); /** * @notice Event emitted when tokens are minted */ event Mint(address minter, uint mintAmount, uint mintTokens); /** * @notice Event emitted when mFIL are collateralized */ event Collateralize(address collateralizer, uint collateralizeAmount); /** * @notice Event emitted when tokens are redeemed */ event Redeem(address redeemer, uint redeemAmount, uint redeemTokens); /** * @notice Event emitted when underlying is borrowed */ event Borrow(address borrower, uint borrowAmount, uint accountBorrows, uint totalBorrows); /** * @notice Event emitted when a borrow is repaid */ event RepayBorrow(address payer, address borrower, uint repayAmount, uint accountBorrows, uint totalBorrows); /** * @notice Event emitted when collaterals are redeemed */ event RedeemCollateral(address redeemer, uint redeemAmount); /** * @notice Event emitted when a liquidate borrow is repaid */ event LiquidateBorrow(address liquidator, address borrower, uint accountBorrows, uint accountCollaterals); /*** Admin Events ***/ /** * @notice Event emitted when pendingAdmin is changed */ event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin); /** * @notice Event emitted when pendingAdmin is accepted, which means admin is updated */ event NewAdmin(address oldAdmin, address newAdmin); /** * @notice Event emitted when mintAllowed is changed */ event MintAllowed(bool mintAllowed); /** * @notice Event emitted when borrowAllowed is changed */ event BorrowAllowed(bool borrowAllowed); /** * @notice Event emitted when interestRateModel is changed */ event NewInterestRateModel(InterestRateModel oldInterestRateModel, InterestRateModel newInterestRateModel); /** * @notice Event emitted when the reserve factor is changed */ event NewReserveFactor(uint oldReserveFactorMantissa, uint newReserveFactorMantissa); /** * @notice Event emitted when the liquidate factor is changed */ event NewLiquidateFactor(uint oldLiquidateFactorMantissa, uint newLiquidateFactorMantissa); /** * @notice EIP20 Transfer event */ event Transfer(address indexed from, address indexed to, uint amount); /** * @notice EIP20 Approval event */ event Approval(address indexed owner, address indexed spender, uint amount); /** * @notice Failure event */ event Failure(uint error, uint info, uint detail); // Event emitted when reserves owner is changed event ReservesOwnerChanged(address oldAddress, address newAddress); // Event emitted when uniswap address is changed event UniswapAddressChanged(address oldAddress, address newAddress); // Event emitted when miner leagure address is changed event MinerLeagueAddressChanged(address oldAddress, address newAddress); // Event emitted when operator address is changed event OperatorAddressChanged(address oldAddress, address newAddress); // Event emitted when technical address is changed event TechnicalAddressChanged(address oldAddress, address newAddress); // Event emitted when undistributed address is changed event UndistributedAddressChanged(address oldAddress, address newAddress); // Event emitted when reserved is reduced event ReservesReduced(address toTho, uint amount); // Event emitted when DFL is accrued event AccrueDFL(uint uniswapPart, uint minerLeaguePart, uint operatorPart, uint technicalPart, uint supplyPart, uint dflSupplyIndex); // Emitted when DFL is distributed to a supplier event DistributedDFL(address supplier, uint supplierDelta); // Event emitted when DFL percentage is changed event PercentagesChanged(uint uniswapPercentage, uint minerLeaguePercentage, uint operatorPercentage); /** * @notice constructor */ constructor(address interestRateModelAddress, address eFILAddress_, address mFILAddress_, address dflAddress_, address reservesOwner_, address uniswapAddress_, address minerLeagueAddress_, address operatorAddress_, address technicalAddress_, address undistributedAddress_) public { // set admin admin = msg.sender; // Initialize block number and borrow index accrualBlockNumber = getBlockNumber(); borrowIndex = mantissaOne; // reserve 50% uint err = _setReserveFactorFresh(0.5e18); require(err == uint(Error.NO_ERROR), "setting reserve factor failed"); // set liquidate factor to 200% err = _setLiquidateFactorFresh(2e18); require(err == uint(Error.NO_ERROR), "setting liquidate factor failed"); // Set the interest rate model (depends on block number / borrow index) err = _setInterestRateModelFresh(InterestRateModel(interestRateModelAddress)); require(err == uint(Error.NO_ERROR), "setting interest rate model failed"); // uniswapPercentage = 0.25e18; // 25% // minerLeaguePercentage = 0.1e18; // 10% // operatorPercentage = 0.03e18; // 3% err = _setDFLPercentagesFresh(0.25e18, 0.1e18, 0.03e18); require(err == uint(Error.NO_ERROR), "setting DFL percentages failed"); // allow mint/borrow mintAllowed = true; borrowAllowed = true; // token addresses & tokens eFILAddress = eFILAddress_; mFILAddress = mFILAddress_; dflToken = DFL(dflAddress_); // set owner of reserves reservesOwner = reservesOwner_; // DFL dflAccrualBlockNumber = getBlockNumber(); dflSupplyIndex = dflInitialSupplyIndex; nextHalveBlockNumber = dflAccrualBlockNumber + halvePeriod; // DFL addresses uniswapAddress = uniswapAddress_; minerLeagueAddress = minerLeagueAddress_; operatorAddress = operatorAddress_; technicalAddress = technicalAddress_; undistributedAddress = undistributedAddress_; emit Transfer(address(0), address(this), 0); } /** * @notice Transfer `tokens` tokens from `src` to `dst` by `spender` * @dev Called by both `transfer` and `transferFrom` internally * @param spender The address of the account performing the transfer * @param src The address of the source account * @param dst The address of the destination account * @param tokens The number of tokens to transfer * @return Whether or not the transfer succeeded */ function transferTokens(address spender, address src, address dst, uint tokens) internal returns (uint) { /* Do not allow self-transfers */ if (src == dst || dst == address(0)) { return fail(Error.BAD_INPUT, FailureInfo.TRANSFER_NOT_ALLOWED); } // Keep the flywheel moving accrueDFL(); distributeSupplierDFL(src, false); distributeSupplierDFL(dst, false); /* Get the allowance, infinite for the account owner */ uint startingAllowance = 0; if (spender == src) { startingAllowance = uint(-1); } else { startingAllowance = transferAllowances[src][spender]; } /* Do the calculations, checking for {under,over}flow */ MathError mathErr; uint allowanceNew; uint srcTokensNew; uint dstTokensNew; (mathErr, allowanceNew) = subUInt(startingAllowance, tokens); if (mathErr != MathError.NO_ERROR) { return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_NOT_ALLOWED); } (mathErr, srcTokensNew) = subUInt(accountTokens[src], tokens); if (mathErr != MathError.NO_ERROR) { return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_NOT_ENOUGH); } (mathErr, dstTokensNew) = addUInt(accountTokens[dst], tokens); if (mathErr != MathError.NO_ERROR) { return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_TOO_MUCH); } ///////////////////////// // EFFECTS & INTERACTIONS // (No safe failures beyond this point) accountTokens[src] = srcTokensNew; accountTokens[dst] = dstTokensNew; /* Eat some of the allowance (if necessary) */ if (startingAllowance != uint(-1)) { transferAllowances[src][spender] = allowanceNew; } /* We emit a Transfer event */ emit Transfer(src, dst, tokens); return uint(Error.NO_ERROR); } /** * @notice Transfer `amount` tokens from `msg.sender` to `dst` * @param dst The address of the destination account * @param amount The number of tokens to transfer * @return Whether or not the transfer succeeded */ function transfer(address dst, uint256 amount) external nonReentrant returns (bool) { return transferTokens(msg.sender, msg.sender, dst, amount) == uint(Error.NO_ERROR); } /** * @notice Transfer `amount` tokens from `src` to `dst` * @param src The address of the source account * @param dst The address of the destination account * @param amount The number of tokens to transfer * @return Whether or not the transfer succeeded */ function transferFrom(address src, address dst, uint256 amount) external nonReentrant returns (bool) { return transferTokens(msg.sender, src, dst, amount) == uint(Error.NO_ERROR); } /** * @notice Approve `spender` to transfer up to `amount` from `src` * @dev This will overwrite the approval amount for `spender` * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) * @param spender The address of the account which may transfer tokens * @param amount The number of tokens that are approved (-1 means infinite) * @return Whether or not the approval succeeded */ function approve(address spender, uint256 amount) external returns (bool) { require(spender != address(0), "cannot approve to the zero address"); address src = msg.sender; transferAllowances[src][spender] = amount; emit Approval(src, spender, amount); return true; } /** * @notice Get the current allowance from `owner` for `spender` * @param owner The address of the account which owns the tokens to be spent * @param spender The address of the account which may transfer tokens * @return The number of tokens allowed to be spent (-1 means infinite) */ function allowance(address owner, address spender) external view returns (uint256) { return transferAllowances[owner][spender]; } /** * @notice Get the token balance of the `owner` * @param owner The address of the account to query * @return The number of tokens owned by `owner` */ function balanceOf(address owner) external view returns (uint256) { return accountTokens[owner]; } /** * @notice Get the underlying balance of the `owner` * @dev This also accrues interest in a transaction * @param owner The address of the account to query * @return The amount of underlying owned by `owner` */ function balanceOfUnderlying(address owner) external returns (uint) { Exp memory exchangeRate = Exp({mantissa: exchangeRateCurrent()}); (MathError mErr, uint balance) = mulScalarTruncate(exchangeRate, accountTokens[owner]); require(mErr == MathError.NO_ERROR, "balance could not be calculated"); return balance; } /** * @notice Get the collateral of the `account` * @param account The address of the account to query * @return The number of collaterals owned by `account` */ function getCollateral(address account) external view returns (uint256) { return accountCollaterals[account]; } /** * @dev Function to simply retrieve block number * This exists mainly for inheriting test contracts to stub this result. */ function getBlockNumber() internal view returns (uint) { return block.number; } /** * @notice Returns the current per-block borrow interest rate * @return The borrow interest rate per block, scaled by 1e18 */ function borrowRatePerBlock() external view returns (uint) { return interestRateModel.getBorrowRate(getCashPrior(), totalBorrows, totalReserves); } /** * @notice Returns the current per-block supply interest rate * @return The supply interest rate per block, scaled by 1e18 */ function supplyRatePerBlock() external view returns (uint) { return interestRateModel.getSupplyRate(getCashPrior(), totalBorrows, totalReserves, reserveFactorMantissa); } /** * @notice Returns the current total borrows plus accrued interest * @return The total borrows with interest */ function totalBorrowsCurrent() external nonReentrant returns (uint) { require(accrueInterest() == uint(Error.NO_ERROR), "accrue interest failed"); return totalBorrows; } /** * @notice Accrue interest to updated borrowIndex and then calculate account's borrow balance using the updated borrowIndex * @param account The address whose balance should be calculated after updating borrowIndex * @return The calculated balance */ function borrowBalanceCurrent(address account) external nonReentrant returns (uint) { require(accrueInterest() == uint(Error.NO_ERROR), "accrue interest failed"); return borrowBalanceStored(account); } /** * @notice Return the borrow balance of account based on stored data * @param account The address whose balance should be calculated * @return The calculated balance */ function borrowBalanceStored(address account) public view returns (uint) { (MathError err, uint result) = borrowBalanceStoredInternal(account); require(err == MathError.NO_ERROR, "borrowBalanceStored: borrowBalanceStoredInternal failed"); return result; } /** * @notice Return the borrow balance of account based on stored data * @param account The address whose balance should be calculated * @return (error code, the calculated balance or 0 if error code is non-zero) */ function borrowBalanceStoredInternal(address account) internal view returns (MathError, uint) { /* Note: we do not assert that is up to date */ MathError mathErr; uint principalTimesIndex; uint result; /* Get borrowBalance and borrowIndex */ BorrowSnapshot storage borrowSnapshot = accountBorrows[account]; /* If borrowBalance = 0 then borrowIndex is likely also 0. * Rather than failing the calculation with a division by 0, we immediately return 0 in this case. */ if (borrowSnapshot.principal == 0) { return (MathError.NO_ERROR, 0); } /* Calculate new borrow balance using the interest index: * recentBorrowBalance = borrower.borrowBalance * global.borrowIndex / borrower.borrowIndex */ (mathErr, principalTimesIndex) = mulUInt(borrowSnapshot.principal, borrowIndex); if (mathErr != MathError.NO_ERROR) { return (mathErr, 0); } (mathErr, result) = divUInt(principalTimesIndex, borrowSnapshot.interestIndex); if (mathErr != MathError.NO_ERROR) { return (mathErr, 0); } return (MathError.NO_ERROR, result); } /** * @notice Accrue interest then return the up-to-date exchange rate * @return Calculated exchange rate scaled by 1e18 */ function exchangeRateCurrent() public returns (uint) { require(accrueInterest() == uint(Error.NO_ERROR), "accrue interest failed"); return exchangeRateStored(); } /** * @notice Calculates the exchange rate from the underlying to the ceFIL * @dev This function does not accrue interest before calculating the exchange rate * @return Calculated exchange rate scaled by 1e18 */ function exchangeRateStored() public view returns (uint) { (MathError err, uint result) = exchangeRateStoredInternal(); require(err == MathError.NO_ERROR, "exchangeRateStored: exchangeRateStoredInternal failed"); return result; } /** * @notice Calculates the exchange rate from the underlying to the ceFIL * @dev This function does not accrue interest before calculating the exchange rate * @return (error code, calculated exchange rate scaled by 1e18) */ function exchangeRateStoredInternal() internal view returns (MathError, uint) { uint _totalSupply = totalSupply; if (_totalSupply == 0) { /* * If there are no tokens minted: * exchangeRate = initialExchangeRate */ return (MathError.NO_ERROR, initialExchangeRateMantissa); } else { /* * Otherwise: * exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply */ uint totalCash = getCashPrior(); uint cashPlusBorrowsMinusReserves; Exp memory exchangeRate; MathError mathErr; (mathErr, cashPlusBorrowsMinusReserves) = addThenSubUInt(totalCash, totalBorrows, totalReserves); if (mathErr != MathError.NO_ERROR) { return (mathErr, 0); } (mathErr, exchangeRate) = getExp(cashPlusBorrowsMinusReserves, _totalSupply); if (mathErr != MathError.NO_ERROR) { return (mathErr, 0); } return (MathError.NO_ERROR, exchangeRate.mantissa); } } /** * @notice Accrue interest then return the up-to-date collateral rate * @return Calculated collateral rate scaled by 1e18 */ function collateralRateCurrent(address borrower) external returns (uint) { require(accrueInterest() == uint(Error.NO_ERROR), "accrue interest failed"); return collateralRateStored(borrower); } /** * @notice Calculates the collateral rate of borrower from stored states * @dev This function does not accrue interest before calculating the collateral rate * @return Calculated exchange rate scaled by 1e18 */ function collateralRateStored(address borrower) public view returns (uint) { (MathError err, uint rate, ,) = collateralRateInternal(borrower); require(err == MathError.NO_ERROR, "collateralRateStored: collateralRateInternal failed"); return rate; } function collateralRateInternal(address borrower) internal view returns (MathError, uint, uint, uint) { MathError mathErr; uint _accountBorrows; uint _accountCollaterals; Exp memory collateralRate; (mathErr, _accountBorrows) = borrowBalanceStoredInternal(borrower); if (mathErr != MathError.NO_ERROR) { return (mathErr, 0, 0, 0); } _accountCollaterals = accountCollaterals[borrower]; (mathErr, collateralRate) = getExp(_accountBorrows, _accountCollaterals); if (mathErr != MathError.NO_ERROR) { return (mathErr, 0, 0, 0); } return (MathError.NO_ERROR, collateralRate.mantissa, _accountBorrows, _accountCollaterals); } // Accrue DFL then return the up-to-date accrued amount function accruedDFLCurrent(address supplier) external nonReentrant returns (uint) { accrueDFL(); return accruedDFLStoredInternal(supplier); } // Accrue DFL then return the up-to-date accrued amount function accruedDFLStored(address supplier) public view returns (uint) { return accruedDFLStoredInternal(supplier); } // Return the accrued DFL of account based on stored data function accruedDFLStoredInternal(address supplier) internal view returns(uint) { Double memory supplyIndex = Double({mantissa: dflSupplyIndex}); Double memory supplierIndex = Double({mantissa: dflSupplierIndex[supplier]}); if (supplierIndex.mantissa == 0 && supplyIndex.mantissa > 0) { supplierIndex.mantissa = dflInitialSupplyIndex; } Double memory deltaIndex = sub_(supplyIndex, supplierIndex); uint supplierDelta = mul_(accountTokens[supplier], deltaIndex); uint supplierAccrued = add_(dflAccrued[supplier], supplierDelta); return supplierAccrued; } /** * @notice Get cash balance of this in the underlying asset * @return The quantity of underlying asset owned by this contract */ function getCash() external view returns (uint) { return getCashPrior(); } /** * @notice Applies accrued interest to total borrows and reserves * @dev This calculates interest accrued from the last checkpointed block * up to the current block and writes new checkpoint to storage. */ function accrueInterest() public returns (uint) { /* Remember the initial block number */ uint currentBlockNumber = getBlockNumber(); uint accrualBlockNumberPrior = accrualBlockNumber; /* Short-circuit accumulating 0 interest */ if (accrualBlockNumberPrior == currentBlockNumber) { return uint(Error.NO_ERROR); } /* Read the previous values out of storage */ uint cashPrior = getCashPrior(); uint borrowsPrior = totalBorrows; uint reservesPrior = totalReserves; uint borrowIndexPrior = borrowIndex; /* Calculate the current borrow interest rate */ uint borrowRateMantissa = interestRateModel.getBorrowRate(cashPrior, borrowsPrior, reservesPrior); /* Calculate the number of blocks elapsed since the last accrual */ (MathError mathErr, uint blockDelta) = subUInt(currentBlockNumber, accrualBlockNumberPrior); require(mathErr == MathError.NO_ERROR, "could not calculate block delta"); /* * Calculate the interest accumulated into borrows and reserves and the new index: * simpleInterestFactor = borrowRate * blockDelta * interestAccumulated = simpleInterestFactor * totalBorrows * totalBorrowsNew = interestAccumulated + totalBorrows * totalReservesNew = interestAccumulated * reserveFactor + totalReserves * borrowIndexNew = simpleInterestFactor * borrowIndex + borrowIndex */ Exp memory simpleInterestFactor; uint interestAccumulated; uint totalBorrowsNew; uint totalReservesNew; uint borrowIndexNew; (mathErr, simpleInterestFactor) = mulScalar(Exp({mantissa: borrowRateMantissa}), blockDelta); if (mathErr != MathError.NO_ERROR) { return failOpaque(Error.MATH_ERROR, FailureInfo.ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED, uint(mathErr)); } (mathErr, interestAccumulated) = mulScalarTruncate(simpleInterestFactor, borrowsPrior); if (mathErr != MathError.NO_ERROR) { return failOpaque(Error.MATH_ERROR, FailureInfo.ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED, uint(mathErr)); } (mathErr, totalBorrowsNew) = addUInt(interestAccumulated, borrowsPrior); if (mathErr != MathError.NO_ERROR) { return failOpaque(Error.MATH_ERROR, FailureInfo.ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED, uint(mathErr)); } (mathErr, totalReservesNew) = mulScalarTruncateAddUInt(Exp({mantissa: reserveFactorMantissa}), interestAccumulated, reservesPrior); if (mathErr != MathError.NO_ERROR) { return failOpaque(Error.MATH_ERROR, FailureInfo.ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, uint(mathErr)); } (mathErr, borrowIndexNew) = mulScalarTruncateAddUInt(simpleInterestFactor, borrowIndexPrior, borrowIndexPrior); if (mathErr != MathError.NO_ERROR) { return failOpaque(Error.MATH_ERROR, FailureInfo.ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED, uint(mathErr)); } ///////////////////////// // EFFECTS & INTERACTIONS // (No safe failures beyond this point) /* We write the previously calculated values into storage */ accrualBlockNumber = currentBlockNumber; borrowIndex = borrowIndexNew; totalBorrows = totalBorrowsNew; totalReserves = totalReservesNew; /* We emit an AccrueInterest event */ emit AccrueInterest(cashPrior, interestAccumulated, borrowIndexNew, totalBorrowsNew); return uint(Error.NO_ERROR); } /** * @notice Sender supplies assets into and receives cTokens in exchange * @dev Accrues interest whether or not the operation succeeds, unless reverted * @param mintAmount The amount of the underlying asset to supply * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function mint(uint mintAmount) external nonReentrant returns (uint) { uint err = accrueInterest(); if (err != uint(Error.NO_ERROR)) { // accrueInterest emits logs on errors, but we still want to log the fact that an attempted borrow failed return fail(Error(err), FailureInfo.ACCRUE_INTEREST_FAILED); } // Keep the flywheel moving accrueDFL(); distributeSupplierDFL(msg.sender, false); // mintFresh emits the actual Mint event if successful and logs on errors, so we don't need to (err,) = mintFresh(msg.sender, mintAmount); return err; } struct MintLocalVars { Error err; MathError mathErr; uint exchangeRateMantissa; uint mintTokens; uint totalSupplyNew; uint accountTokensNew; uint actualMintAmount; } /** * @notice User supplies assets into and receives cTokens in exchange * @dev Assumes interest has already been accrued up to the current block * @param minter The address of the account which is supplying the assets * @param mintAmount The amount of the underlying asset to supply * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual mint amount. */ function mintFresh(address minter, uint mintAmount) internal returns (uint, uint) { if (!mintAllowed || accountCollaterals[minter] != 0) { return (fail(Error.REJECTION, FailureInfo.MINT_REJECTION), 0); } MintLocalVars memory vars; (vars.mathErr, vars.exchangeRateMantissa) = exchangeRateStoredInternal(); if (vars.mathErr != MathError.NO_ERROR) { return (failOpaque(Error.MATH_ERROR, FailureInfo.MINT_EXCHANGE_RATE_READ_FAILED, uint(vars.mathErr)), 0); } ///////////////////////// // EFFECTS & INTERACTIONS // (No safe failures beyond this point) vars.actualMintAmount = doTransferIn(eFILAddress, minter, mintAmount); /* * We get the current exchange rate and calculate the number of cTokens to be minted: * mintTokens = actualMintAmount / exchangeRate */ (vars.mathErr, vars.mintTokens) = divScalarByExpTruncate(vars.actualMintAmount, Exp({mantissa: vars.exchangeRateMantissa})); require(vars.mathErr == MathError.NO_ERROR, "MINT_EXCHANGE_CALCULATION_FAILED"); /* * We calculate the new total supply of cTokens and minter token balance, checking for overflow: * totalSupplyNew = totalSupply + mintTokens * accountTokensNew = accountTokens[minter] + mintTokens */ (vars.mathErr, vars.totalSupplyNew) = addUInt(totalSupply, vars.mintTokens); require(vars.mathErr == MathError.NO_ERROR, "MINT_NEW_TOTAL_SUPPLY_CALCULATION_FAILED"); (vars.mathErr, vars.accountTokensNew) = addUInt(accountTokens[minter], vars.mintTokens); require(vars.mathErr == MathError.NO_ERROR, "MINT_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED"); /* We write previously calculated values into storage */ totalSupply = vars.totalSupplyNew; accountTokens[minter] = vars.accountTokensNew; /* We emit a Mint event, and a Transfer event */ emit Mint(minter, vars.actualMintAmount, vars.mintTokens); emit Transfer(address(this), minter, vars.mintTokens); return (uint(Error.NO_ERROR), vars.actualMintAmount); } /** * @dev Accrues interest whether or not the operation succeeds, unless reverted * @param collateralizeAmount The amount of the underlying asset to collateralize * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function collateralize(uint collateralizeAmount) external nonReentrant returns (uint) { uint err = accrueInterest(); if (err != uint(Error.NO_ERROR)) { // accrueInterest emits logs on errors, but we still want to log the fact that an attempted borrow failed return fail(Error(err), FailureInfo.ACCRUE_INTEREST_FAILED); } // Keep the flywheel moving accrueDFL(); (err,) = collateralizeFresh(msg.sender, collateralizeAmount); return err; } struct CollateralizeLocalVars { Error err; MathError mathErr; uint totalCollateralsNew; uint accountCollateralsNew; uint actualCollateralizeAmount; } /** * @param collateralizer The address of the account which is supplying the assets * @param collateralizeAmount The amount of the underlying asset to supply * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual collateralize amount. */ function collateralizeFresh(address collateralizer, uint collateralizeAmount) internal returns (uint, uint) { if (accountTokens[collateralizer] != 0) { return (fail(Error.REJECTION, FailureInfo.COLLATERALIZE_REJECTION), 0); } CollateralizeLocalVars memory vars; ///////////////////////// // EFFECTS & INTERACTIONS // (No safe failures beyond this point) vars.actualCollateralizeAmount = doTransferIn(mFILAddress, collateralizer, collateralizeAmount); (vars.mathErr, vars.totalCollateralsNew) = addUInt(totalCollaterals, vars.actualCollateralizeAmount); require(vars.mathErr == MathError.NO_ERROR, "COLLATERALIZE_NEW_TOTAL_COLLATERALS_CALCULATION_FAILED"); (vars.mathErr, vars.accountCollateralsNew) = addUInt(accountCollaterals[collateralizer], vars.actualCollateralizeAmount); require(vars.mathErr == MathError.NO_ERROR, "COLLATERALIZE_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED"); /* We write previously calculated values into storage */ totalCollaterals = vars.totalCollateralsNew; accountCollaterals[collateralizer] = vars.accountCollateralsNew; /* We emit a Collateralize event, and a Transfer event */ emit Collateralize(collateralizer, vars.actualCollateralizeAmount); return (uint(Error.NO_ERROR), vars.actualCollateralizeAmount); } /** * @notice Sender redeems cTokens in exchange for the underlying asset * @dev Accrues interest whether or not the operation succeeds, unless reverted * @param redeemTokens The number of cTokens to redeem into underlying * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function redeem(uint redeemTokens) external nonReentrant returns (uint) { uint err = accrueInterest(); if (err != uint(Error.NO_ERROR)) { // accrueInterest emits logs on errors, but we still want to log the fact that an attempted redeem failed return fail(Error(err), FailureInfo.ACCRUE_INTEREST_FAILED); } // Keep the flywheel moving accrueDFL(); distributeSupplierDFL(msg.sender, false); // redeemFresh emits redeem-specific logs on errors, so we don't need to return redeemFresh(msg.sender, redeemTokens, 0); } /** * @notice Sender redeems cTokens in exchange for a specified amount of underlying asset * @dev Accrues interest whether or not the operation succeeds, unless reverted * @param redeemAmount The amount of underlying to redeem * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function redeemUnderlying(uint redeemAmount) external nonReentrant returns (uint) { uint err = accrueInterest(); if (err != uint(Error.NO_ERROR)) { // accrueInterest emits logs on errors, but we still want to log the fact that an attempted redeem failed return fail(Error(err), FailureInfo.ACCRUE_INTEREST_FAILED); } // Keep the flywheel moving accrueDFL(); distributeSupplierDFL(msg.sender, false); // redeemFresh emits redeem-specific logs on errors, so we don't need to return redeemFresh(msg.sender, 0, redeemAmount); } struct RedeemLocalVars { Error err; MathError mathErr; uint exchangeRateMantissa; uint redeemTokens; uint redeemAmount; uint totalSupplyNew; uint accountTokensNew; } /** * @notice User redeems cTokens in exchange for the underlying asset * @dev Assumes interest has already been accrued up to the current block * @param redeemer The address of the account which is redeeming the tokens * @param redeemTokensIn The number of cTokens to redeem into underlying (only one of redeemTokensIn or redeemAmountIn may be non-zero) * @param redeemAmountIn The number of underlying tokens to receive from redeeming cTokens (only one of redeemTokensIn or redeemAmountIn may be non-zero) * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function redeemFresh(address redeemer, uint redeemTokensIn, uint redeemAmountIn) internal returns (uint) { require(redeemTokensIn == 0 || redeemAmountIn == 0, "one of redeemTokensIn or redeemAmountIn must be zero"); RedeemLocalVars memory vars; /* exchangeRate = invoke Exchange Rate Stored() */ (vars.mathErr, vars.exchangeRateMantissa) = exchangeRateStoredInternal(); if (vars.mathErr != MathError.NO_ERROR) { return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_EXCHANGE_RATE_READ_FAILED, uint(vars.mathErr)); } /* If redeemTokensIn > 0: */ if (redeemTokensIn > 0) { /* * We calculate the exchange rate and the amount of underlying to be redeemed: * redeemTokens = redeemTokensIn * redeemAmount = redeemTokensIn x exchangeRateCurrent */ vars.redeemTokens = redeemTokensIn; (vars.mathErr, vars.redeemAmount) = mulScalarTruncate(Exp({mantissa: vars.exchangeRateMantissa}), redeemTokensIn); if (vars.mathErr != MathError.NO_ERROR) { return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_EXCHANGE_TOKENS_CALCULATION_FAILED, uint(vars.mathErr)); } } else { /* * We get the current exchange rate and calculate the amount to be redeemed: * redeemTokens = redeemAmountIn / exchangeRate * redeemAmount = redeemAmountIn */ (vars.mathErr, vars.redeemTokens) = divScalarByExpTruncate(redeemAmountIn, Exp({mantissa: vars.exchangeRateMantissa})); if (vars.mathErr != MathError.NO_ERROR) { return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED, uint(vars.mathErr)); } vars.redeemAmount = redeemAmountIn; } /* * We calculate the new total supply and redeemer balance, checking for underflow: * totalSupplyNew = totalSupply - redeemTokens * accountTokensNew = accountTokens[redeemer] - redeemTokens */ (vars.mathErr, vars.totalSupplyNew) = subUInt(totalSupply, vars.redeemTokens); if (vars.mathErr != MathError.NO_ERROR) { return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, uint(vars.mathErr)); } (vars.mathErr, vars.accountTokensNew) = subUInt(accountTokens[redeemer], vars.redeemTokens); if (vars.mathErr != MathError.NO_ERROR) { return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, uint(vars.mathErr)); } /* Fail gracefully if protocol has insufficient cash */ if (getCashPrior() < vars.redeemAmount) { return fail(Error.TOKEN_INSUFFICIENT_CASH, FailureInfo.REDEEM_TRANSFER_OUT_NOT_POSSIBLE); } ///////////////////////// // EFFECTS & INTERACTIONS // (No safe failures beyond this point) doTransferOut(eFILAddress, redeemer, vars.redeemAmount); /* We write previously calculated values into storage */ totalSupply = vars.totalSupplyNew; accountTokens[redeemer] = vars.accountTokensNew; /* We emit a Transfer event, and a Redeem event */ emit Transfer(redeemer, address(this), vars.redeemTokens); emit Redeem(redeemer, vars.redeemAmount, vars.redeemTokens); return uint(Error.NO_ERROR); } /** * @notice Sender borrows assets from the protocol to their own address * @param borrowAmount The amount of the underlying asset to borrow * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function borrow(uint borrowAmount) external nonReentrant returns (uint) { uint err = accrueInterest(); if (err != uint(Error.NO_ERROR)) { // accrueInterest emits logs on errors, but we still want to log the fact that an attempted borrow failed return fail(Error(err), FailureInfo.ACCRUE_INTEREST_FAILED); } // Keep the flywheel moving accrueDFL(); // borrowFresh emits borrow-specific logs on errors, so we don't need to return borrowFresh(msg.sender, borrowAmount); } struct BorrowLocalVars { MathError mathErr; uint actualBorrowAmount; uint accountBorrows; uint accountBorrowsNew; uint totalBorrowsNew; } /** * @notice Users borrow assets from the protocol to their own address * @param borrowAmount The amount of the underlying asset to borrow * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function borrowFresh(address borrower, uint borrowAmount) internal returns (uint) { if (!borrowAllowed) { return fail(Error.REJECTION, FailureInfo.BORROW_REJECTION); } BorrowLocalVars memory vars; (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal(borrower); if (vars.mathErr != MathError.NO_ERROR) { return failOpaque(Error.MATH_ERROR, FailureInfo.BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, uint(vars.mathErr)); } if (borrowAmount == uint(-1)) { vars.actualBorrowAmount = accountCollaterals[borrower] > vars.accountBorrows ? accountCollaterals[borrower] - vars.accountBorrows : 0; } else { vars.actualBorrowAmount = borrowAmount; } /* Fail gracefully if protocol has insufficient underlying cash */ if (getCashPrior() < vars.actualBorrowAmount) { return fail(Error.TOKEN_INSUFFICIENT_CASH, FailureInfo.BORROW_CASH_NOT_AVAILABLE); } /* * We calculate the new borrower and total borrow balances, failing on overflow: * accountBorrowsNew = accountBorrows + actualBorrowAmount * totalBorrowsNew = totalBorrows + actualBorrowAmount */ (vars.mathErr, vars.accountBorrowsNew) = addUInt(vars.accountBorrows, vars.actualBorrowAmount); if (vars.mathErr != MathError.NO_ERROR) { return failOpaque(Error.MATH_ERROR, FailureInfo.BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, uint(vars.mathErr)); } // Check collaterals if (accountCollaterals[borrower] < vars.accountBorrowsNew) { return fail(Error.INSUFFICIENT_COLLATERAL, FailureInfo.BORROW_INSUFFICIENT_COLLATERAL); } (vars.mathErr, vars.totalBorrowsNew) = addUInt(totalBorrows, vars.actualBorrowAmount); if (vars.mathErr != MathError.NO_ERROR) { return failOpaque(Error.MATH_ERROR, FailureInfo.BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, uint(vars.mathErr)); } ///////////////////////// // EFFECTS & INTERACTIONS // (No safe failures beyond this point) doTransferOut(eFILAddress, borrower, vars.actualBorrowAmount); /* We write the previously calculated values into storage */ accountBorrows[borrower].principal = vars.accountBorrowsNew; accountBorrows[borrower].interestIndex = borrowIndex; totalBorrows = vars.totalBorrowsNew; /* We emit a Borrow event */ emit Borrow(borrower, vars.actualBorrowAmount, vars.accountBorrowsNew, vars.totalBorrowsNew); return uint(Error.NO_ERROR); } /** * @notice Sender repays their own borrow * @param repayAmount The amount to repay * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function repayBorrow(uint repayAmount) external nonReentrant returns (uint) { uint err = accrueInterest(); if (err != uint(Error.NO_ERROR)) { // accrueInterest emits logs on errors, but we still want to log the fact that an attempted borrow failed return fail(Error(err), FailureInfo.ACCRUE_INTEREST_FAILED); } // Keep the flywheel moving accrueDFL(); // repayBorrowFresh emits repay-borrow-specific logs on errors, so we don't need to (err,) = repayBorrowFresh(msg.sender, msg.sender, repayAmount); return err; } /** * @notice Sender repays a borrow belonging to borrower * @param borrower the account with the debt being payed off * @param repayAmount The amount to repay * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function repayBorrowBehalf(address borrower, uint repayAmount) external nonReentrant returns (uint) { uint err = accrueInterest(); if (err != uint(Error.NO_ERROR)) { // accrueInterest emits logs on errors, but we still want to log the fact that an attempted borrow failed return fail(Error(err), FailureInfo.ACCRUE_INTEREST_FAILED); } // Keep the flywheel moving accrueDFL(); // repayBorrowFresh emits repay-borrow-specific logs on errors, so we don't need to (err,) = repayBorrowFresh(msg.sender, borrower, repayAmount); return err; } struct RepayBorrowLocalVars { Error err; MathError mathErr; uint repayAmount; uint borrowerIndex; uint accountBorrows; uint accountBorrowsNew; uint totalBorrowsNew; uint actualRepayAmount; } /** * @notice Borrows are repaid by another user (possibly the borrower). * @param payer the account paying off the borrow * @param borrower the account with the debt being payed off * @param repayAmount the amount of undelrying tokens being returned * @return (uint, uint) An error code (0=success, otherwise a failure, see ErrorReporter.sol), and the actual repayment amount. */ function repayBorrowFresh(address payer, address borrower, uint repayAmount) internal returns (uint, uint) { RepayBorrowLocalVars memory vars; /* We remember the original borrowerIndex for verification purposes */ vars.borrowerIndex = accountBorrows[borrower].interestIndex; /* We fetch the amount the borrower owes, with accumulated interest */ (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal(borrower); if (vars.mathErr != MathError.NO_ERROR) { return (failOpaque(Error.MATH_ERROR, FailureInfo.REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, uint(vars.mathErr)), 0); } /* If repayAmount == -1, repayAmount = accountBorrows */ if (repayAmount == uint(-1)) { vars.repayAmount = vars.accountBorrows; } else { vars.repayAmount = repayAmount; } ///////////////////////// // EFFECTS & INTERACTIONS // (No safe failures beyond this point) vars.actualRepayAmount = doTransferIn(eFILAddress, payer, vars.repayAmount); /* * We calculate the new borrower and total borrow balances, failing on underflow: * accountBorrowsNew = accountBorrows - actualRepayAmount * totalBorrowsNew = totalBorrows - actualRepayAmount */ (vars.mathErr, vars.accountBorrowsNew) = subUInt(vars.accountBorrows, vars.actualRepayAmount); require(vars.mathErr == MathError.NO_ERROR, "REPAY_BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED"); (vars.mathErr, vars.totalBorrowsNew) = subUInt(totalBorrows, vars.actualRepayAmount); require(vars.mathErr == MathError.NO_ERROR, "REPAY_BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED"); /* We write the previously calculated values into storage */ accountBorrows[borrower].principal = vars.accountBorrowsNew; accountBorrows[borrower].interestIndex = borrowIndex; totalBorrows = vars.totalBorrowsNew; /* We emit a RepayBorrow event */ emit RepayBorrow(payer, borrower, vars.actualRepayAmount, vars.accountBorrowsNew, vars.totalBorrowsNew); return (uint(Error.NO_ERROR), vars.actualRepayAmount); } /** * redeem collaterals * @dev Accrues interest whether or not the operation succeeds, unless reverted * @param redeemAmount The number of collateral to redeem into underlying * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function redeemCollateral(uint redeemAmount) external nonReentrant returns (uint) { uint err = accrueInterest(); if (err != uint(Error.NO_ERROR)) { // accrueInterest emits logs on errors, but we still want to log the fact that an attempted redeem failed return fail(Error(err), FailureInfo.ACCRUE_INTEREST_FAILED); } // Keep the flywheel moving accrueDFL(); // redeemCollateralFresh emits redeem-collaterals-specific logs on errors, so we don't need to return redeemCollateralFresh(msg.sender, redeemAmount); } struct RedeemCollateralLocalVars { Error err; MathError mathErr; uint redeemAmount; uint accountBorrows; uint accountCollateralsOld; uint accountCollateralsNew; uint totalCollateralsNew; } /** * redeem collaterals * @dev Assumes interest has already been accrued up to the current block * @param redeemer The address of the account which is redeeming * @param redeemAmount The number of collaterals to redeem into underlying * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function redeemCollateralFresh(address redeemer, uint redeemAmount) internal returns (uint) { RedeemCollateralLocalVars memory vars; (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal(redeemer); if (vars.mathErr != MathError.NO_ERROR) { return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_COLLATERAL_ACCUMULATED_BORROW_CALCULATION_FAILED, uint(vars.mathErr)); } vars.accountCollateralsOld = accountCollaterals[redeemer]; if (redeemAmount == uint(-1)) { vars.redeemAmount = vars.accountCollateralsOld >= vars.accountBorrows ? vars.accountCollateralsOld - vars.accountBorrows : 0; } else { vars.redeemAmount = redeemAmount; } (vars.mathErr, vars.accountCollateralsNew) = subUInt(accountCollaterals[redeemer], vars.redeemAmount); if (vars.mathErr != MathError.NO_ERROR) { return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_COLLATERAL_NEW_ACCOUNT_COLLATERAL_CALCULATION_FAILED, uint(vars.mathErr)); } // Check collateral if (vars.accountCollateralsNew < vars.accountBorrows) { return fail(Error.INSUFFICIENT_COLLATERAL, FailureInfo.REDEEM_COLLATERAL_INSUFFICIENT_COLLATERAL); } (vars.mathErr, vars.totalCollateralsNew) = subUInt(totalCollaterals, vars.redeemAmount); require(vars.mathErr == MathError.NO_ERROR, "REDEEM_COLLATERALS_NEW_TOTAL_COLLATERALS_CALCULATION_FAILED"); ///////////////////////// // EFFECTS & INTERACTIONS // (No safe failures beyond this point) doTransferOut(mFILAddress, redeemer, vars.redeemAmount); /* We write previously calculated values into storage */ totalCollaterals = vars.totalCollateralsNew; accountCollaterals[redeemer] = vars.accountCollateralsNew; /* We emit a RedeemCollateral event */ emit RedeemCollateral(redeemer, vars.redeemAmount); return uint(Error.NO_ERROR); } /** * liquidate borrow * @dev Accrues interest whether or not the operation succeeds, unless reverted * @param borrower The borrower's address * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function liquidateBorrow(address borrower) external nonReentrant returns (uint) { uint err = accrueInterest(); if (err != uint(Error.NO_ERROR)) { return fail(Error(err), FailureInfo.ACCRUE_INTEREST_FAILED); } // Keep the flywheel moving accrueDFL(); return liquidateBorrowFresh(msg.sender, borrower); } struct LiquidateBorrowLocalVars { Error err; MathError mathErr; uint accountBorrows; uint accountCollaterals; uint collateralRate; uint totalBorrowsNew; } /** * liquidate borrow * @dev Assumes interest has already been accrued up to the current block * @param liquidator The liquidator's address * @param borrower The borrower's address * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function liquidateBorrowFresh(address liquidator, address borrower) internal returns (uint) { // make things simple if (accountCollaterals[liquidator] != 0 || accountTokens[liquidator] != 0) { return fail(Error.REJECTION, FailureInfo.LIQUIDATE_BORROW_REJECTION); } LiquidateBorrowLocalVars memory vars; (vars.mathErr, vars.collateralRate, vars.accountBorrows, vars.accountCollaterals) = collateralRateInternal(borrower); if (vars.mathErr != MathError.NO_ERROR) { return failOpaque(Error.MATH_ERROR, FailureInfo.LIQUIDATE_BORROW_COLLATERAL_RATE_CALCULATION_FAILED, uint(vars.mathErr)); } if (vars.collateralRate < liquidateFactorMantissa) { return fail(Error.REJECTION, FailureInfo.LIQUIDATE_BORROW_NOT_SATISFIED); } ///////////////////////// // EFFECTS & INTERACTIONS // (No safe failures beyond this point) require(doTransferIn(eFILAddress, liquidator, vars.accountBorrows) == vars.accountBorrows, "LIQUIDATE_BORROW_TRANSFER_IN_FAILED"); (vars.mathErr, vars.totalBorrowsNew) = subUInt(totalBorrows, vars.accountBorrows); require(vars.mathErr == MathError.NO_ERROR, "LIQUIDATE_BORROW_NEW_TOTAL_BORROWS_CALCULATION_FAILED"); /* We write the previously calculated values into storage */ accountBorrows[borrower].principal = 0; accountBorrows[borrower].interestIndex = borrowIndex; totalBorrows = vars.totalBorrowsNew; accountCollaterals[borrower] = 0; accountCollaterals[liquidator] = vars.accountCollaterals; /* We emit a RepayBorrow event */ emit LiquidateBorrow(liquidator, borrower, vars.accountBorrows, vars.accountCollaterals); return uint(Error.NO_ERROR); } /*** DFL ***/ // accrue DFL function accrueDFL() internal { uint startBlockNumber = dflAccrualBlockNumber; uint endBlockNumber = startBlockNumber; uint currentBlockNumber = getBlockNumber(); while (endBlockNumber < currentBlockNumber) { if (currentSpeed < minSpeed) { break; } startBlockNumber = endBlockNumber; if (currentBlockNumber < nextHalveBlockNumber) { endBlockNumber = currentBlockNumber; } else { endBlockNumber = nextHalveBlockNumber; } distributeAndUpdateSupplyIndex(startBlockNumber, endBlockNumber); if (endBlockNumber == nextHalveBlockNumber) { nextHalveBlockNumber = nextHalveBlockNumber + halvePeriod; currentSpeed = currentSpeed / 2; } } // update dflAccrualBlockNumber dflAccrualBlockNumber = currentBlockNumber; } // Accrue DFL for suppliers by updating the supply index function distributeAndUpdateSupplyIndex(uint startBlockNumber, uint endBlockNumber) internal { uint deltaBlocks = sub_(endBlockNumber, startBlockNumber); if (deltaBlocks > 0) { uint deltaDFLs = mul_(deltaBlocks, currentSpeed); dflToken.mint(address(this), deltaDFLs); uint uniswapPart = div_(mul_(uniswapPercentage, deltaDFLs), mantissaOne); uint minerLeaguePart = div_(mul_(minerLeaguePercentage, deltaDFLs), mantissaOne); uint operatorPart = div_(mul_(operatorPercentage, deltaDFLs), mantissaOne); uint technicalPart = div_(mul_(technicalPercentage, deltaDFLs), mantissaOne); uint supplyPart = sub_(sub_(sub_(sub_(deltaDFLs, uniswapPart), minerLeaguePart), operatorPart), technicalPart); // accrue, not transfer directly dflAccrued[uniswapAddress] = add_(dflAccrued[uniswapAddress], uniswapPart); dflAccrued[minerLeagueAddress] = add_(dflAccrued[minerLeagueAddress], minerLeaguePart); dflAccrued[operatorAddress] = add_(dflAccrued[operatorAddress], operatorPart); dflAccrued[technicalAddress] = add_(dflAccrued[technicalAddress], technicalPart); if (totalSupply > 0) { Double memory ratio = fraction(supplyPart, totalSupply); Double memory index = add_(Double({mantissa: dflSupplyIndex}), ratio); dflSupplyIndex = index.mantissa; } else { dflAccrued[undistributedAddress] = add_(dflAccrued[undistributedAddress], supplyPart); } emit AccrueDFL(uniswapPart, minerLeaguePart, operatorPart, technicalPart, supplyPart, dflSupplyIndex); } } // Calculate DFL accrued by a supplier and possibly transfer it to them function distributeSupplierDFL(address supplier, bool distributeAll) internal { /* Verify accrued block number equals current block number */ require(dflAccrualBlockNumber == getBlockNumber(), "FRESHNESS_CHECK"); uint supplierAccrued = accruedDFLStoredInternal(supplier); dflAccrued[supplier] = transferDFL(supplier, supplierAccrued, distributeAll ? 0 : dflClaimThreshold); dflSupplierIndex[supplier] = dflSupplyIndex; emit DistributedDFL(supplier, supplierAccrued - dflAccrued[supplier]); } // Transfer DFL to the user, if they are above the threshold function transferDFL(address user, uint userAccrued, uint threshold) internal returns (uint) { if (userAccrued >= threshold && userAccrued > 0) { uint dflRemaining = dflToken.balanceOf(address(this)); if (userAccrued <= dflRemaining) { dflToken.transfer(user, userAccrued); return 0; } } return userAccrued; } function claimDFL() public nonReentrant { accrueDFL(); distributeSupplierDFL(msg.sender, true); } // Claim all DFL accrued by the suppliers function claimDFL(address[] memory holders) public nonReentrant { accrueDFL(); for (uint i = 0; i < holders.length; i++) { distributeSupplierDFL(holders[i], true); } } // Reduce reserves, only by staking contract function claimReserves() public nonReentrant { require(accrueInterest() == uint(Error.NO_ERROR), "accrue interest failed"); uint cash = getCashPrior(); uint actualAmount = cash > totalReserves ? totalReserves : cash; doTransferOut(eFILAddress, reservesOwner, actualAmount); totalReserves = sub_(totalReserves, actualAmount); emit ReservesReduced(reservesOwner, actualAmount); } /*** Admin Functions ***/ /** * @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. * @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. * @param newPendingAdmin New pending admin. * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function _setPendingAdmin(address newPendingAdmin) external returns (uint) { // Check caller = admin if (msg.sender != admin) { return fail(Error.UNAUTHORIZED, FailureInfo.ADMIN_CHECK); } // Save current value, if any, for inclusion in log address oldPendingAdmin = pendingAdmin; // Store pendingAdmin with value newPendingAdmin pendingAdmin = newPendingAdmin; // Emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin) emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin); return uint(Error.NO_ERROR); } /** * @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin * @dev Admin function for pending admin to accept role and update admin * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function _acceptAdmin() external returns (uint) { // Check caller is pendingAdmin and pendingAdmin ≠ address(0) if (msg.sender != pendingAdmin || msg.sender == address(0)) { return fail(Error.UNAUTHORIZED, FailureInfo.ADMIN_CHECK); } // Save current values for inclusion in log address oldAdmin = admin; address oldPendingAdmin = pendingAdmin; // Store admin with value pendingAdmin admin = pendingAdmin; // Clear the pending value pendingAdmin = address(0); emit NewAdmin(oldAdmin, admin); emit NewPendingAdmin(oldPendingAdmin, pendingAdmin); return uint(Error.NO_ERROR); } /** * @dev Change mintAllowed * @param mintAllowed_ New value. * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function _setMintAllowed(bool mintAllowed_) external returns (uint) { // Check caller = admin if (msg.sender != admin) { return fail(Error.UNAUTHORIZED, FailureInfo.ADMIN_CHECK); } if (mintAllowed != mintAllowed_) { mintAllowed = mintAllowed_; emit MintAllowed(mintAllowed_); } return uint(Error.NO_ERROR); } /** * @dev Change borrowAllowed * @param borrowAllowed_ New value. * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function _setBorrowAllowed(bool borrowAllowed_) external returns (uint) { // Check caller = admin if (msg.sender != admin) { return fail(Error.UNAUTHORIZED, FailureInfo.ADMIN_CHECK); } if (borrowAllowed != borrowAllowed_) { borrowAllowed = borrowAllowed_; emit BorrowAllowed(borrowAllowed_); } return uint(Error.NO_ERROR); } /** * @notice accrues interest and sets a new reserve factor for the protocol using _setReserveFactorFresh * @dev Admin function to accrue interest and set a new reserve factor * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function _setReserveFactor(uint newReserveFactorMantissa) external nonReentrant returns (uint) { uint error = accrueInterest(); if (error != uint(Error.NO_ERROR)) { // accrueInterest emits logs on errors, but on top of that we want to log the fact that an attempted reserve factor change failed. return fail(Error(error), FailureInfo.ACCRUE_INTEREST_FAILED); } // _setReserveFactorFresh emits reserve-factor-specific logs on errors, so we don't need to. return _setReserveFactorFresh(newReserveFactorMantissa); } /** * @notice Sets a new reserve factor for the protocol (*requires fresh interest accrual) * @dev Admin function to set a new reserve factor * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function _setReserveFactorFresh(uint newReserveFactorMantissa) internal returns (uint) { // Check caller is admin if (msg.sender != admin) { return fail(Error.UNAUTHORIZED, FailureInfo.ADMIN_CHECK); } // Check newReserveFactor ≤ maxReserveFactor if (newReserveFactorMantissa > reserveFactorMaxMantissa) { return fail(Error.BAD_INPUT, FailureInfo.SET_RESERVE_FACTOR_BOUNDS_CHECK); } uint oldReserveFactorMantissa = reserveFactorMantissa; reserveFactorMantissa = newReserveFactorMantissa; emit NewReserveFactor(oldReserveFactorMantissa, newReserveFactorMantissa); return uint(Error.NO_ERROR); } /** * @notice accrues interest and sets a new liquidate factor for the protocol using _setLiquidateFactorFresh * @dev Admin function to accrue interest and set a new liquidate factor * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function _setLiquidateFactor(uint newLiquidateFactorMantissa) external nonReentrant returns (uint) { uint error = accrueInterest(); if (error != uint(Error.NO_ERROR)) { // accrueInterest emits logs on errors, but on top of that we want to log the fact that an attempted liquidate factor change failed. return fail(Error(error), FailureInfo.ACCRUE_INTEREST_FAILED); } return _setLiquidateFactorFresh(newLiquidateFactorMantissa); } function _setLiquidateFactorFresh(uint newLiquidateFactorMantissa) internal returns (uint) { // Check caller is admin if (msg.sender != admin) { return fail(Error.UNAUTHORIZED, FailureInfo.ADMIN_CHECK); } if (newLiquidateFactorMantissa < liquidateFactorMinMantissa) { return fail(Error.BAD_INPUT, FailureInfo.SET_LIQUIDATE_FACTOR_BOUNDS_CHECK); } uint oldLiquidateFactorMantissa = liquidateFactorMantissa; liquidateFactorMantissa = newLiquidateFactorMantissa; emit NewLiquidateFactor(oldLiquidateFactorMantissa, newLiquidateFactorMantissa); return uint(Error.NO_ERROR); } /** * @notice accrues interest and updates the interest rate model using _setInterestRateModelFresh * @dev Admin function to accrue interest and update the interest rate model * @param newInterestRateModel the new interest rate model to use * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function _setInterestRateModel(InterestRateModel newInterestRateModel) public nonReentrant returns (uint) { uint error = accrueInterest(); if (error != uint(Error.NO_ERROR)) { // accrueInterest emits logs on errors, but on top of that we want to log the fact that an attempted change of interest rate model failed return fail(Error(error), FailureInfo.ACCRUE_INTEREST_FAILED); } // _setInterestRateModelFresh emits interest-rate-model-update-specific logs on errors, so we don't need to. return _setInterestRateModelFresh(newInterestRateModel); } /** * @notice updates the interest rate model (*requires fresh interest accrual) * @dev Admin function to update the interest rate model * @param newInterestRateModel the new interest rate model to use * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function _setInterestRateModelFresh(InterestRateModel newInterestRateModel) internal returns (uint) { // Used to store old model for use in the event that is emitted on success InterestRateModel oldInterestRateModel; // Check caller is admin if (msg.sender != admin) { return fail(Error.UNAUTHORIZED, FailureInfo.ADMIN_CHECK); } // Track the current interest rate model oldInterestRateModel = interestRateModel; // Ensure invoke newInterestRateModel.isInterestRateModel() returns true require(newInterestRateModel.isInterestRateModel(), "marker method returned false"); // Set the interest rate model to newInterestRateModel interestRateModel = newInterestRateModel; // Emit NewInterestRateModel(oldInterestRateModel, newInterestRateModel) emit NewInterestRateModel(oldInterestRateModel, newInterestRateModel); return uint(Error.NO_ERROR); } /** * @dev Change reservesOwner * @param newReservesOwner New value. * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function _setReservesOwner(address newReservesOwner) public returns (uint) { claimReserves(); return _setReservesOwnerFresh(newReservesOwner); } function _setReservesOwnerFresh(address newReservesOwner) internal returns (uint) { // Check caller = admin if (msg.sender != admin) { return fail(Error.UNAUTHORIZED, FailureInfo.ADMIN_CHECK); } address oldReservesOwner = reservesOwner; reservesOwner = newReservesOwner; emit ReservesOwnerChanged(oldReservesOwner, newReservesOwner); return uint(Error.NO_ERROR); } /** * @dev Change minerLeagueAddress * @param newMinerLeagueAddress New value. * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function _setMinerLeagueAddress(address newMinerLeagueAddress) external nonReentrant returns (uint) { // accrue accrueDFL(); return _setMinerLeagueAddressFresh(newMinerLeagueAddress); } function _setMinerLeagueAddressFresh(address newMinerLeagueAddress) internal returns (uint) { if (msg.sender != minerLeagueAddress) { return fail(Error.UNAUTHORIZED, FailureInfo.PARTICIPANT_CHECK); } // transfers accrued if (dflAccrued[minerLeagueAddress] != 0) { doTransferOut(address(dflToken), minerLeagueAddress, dflAccrued[minerLeagueAddress]); delete dflAccrued[minerLeagueAddress]; } address oldMinerLeagueAddress = minerLeagueAddress; minerLeagueAddress = newMinerLeagueAddress; emit MinerLeagueAddressChanged(oldMinerLeagueAddress, newMinerLeagueAddress); return uint(Error.NO_ERROR); } /** * @dev Change operatorAddress * @param newOperatorAddress New value. * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function _setOperatorAddress(address newOperatorAddress) external nonReentrant returns (uint) { // accrue accrueDFL(); return _setOperatorAddressFresh(newOperatorAddress); } function _setOperatorAddressFresh(address newOperatorAddress) internal returns (uint) { if (msg.sender != operatorAddress) { return fail(Error.UNAUTHORIZED, FailureInfo.PARTICIPANT_CHECK); } // transfers accrued if (dflAccrued[operatorAddress] != 0) { doTransferOut(address(dflToken), operatorAddress, dflAccrued[operatorAddress]); delete dflAccrued[operatorAddress]; } address oldOperatorAddress = operatorAddress; operatorAddress = newOperatorAddress; emit OperatorAddressChanged(oldOperatorAddress, newOperatorAddress); return uint(Error.NO_ERROR); } /** * @dev Change technicalAddress * @param newTechnicalAddress New value. * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function _setTechnicalAddress(address newTechnicalAddress) external nonReentrant returns (uint) { // accrue accrueDFL(); return _setTechnicalAddressFresh(newTechnicalAddress); } function _setTechnicalAddressFresh(address newTechnicalAddress) internal returns (uint) { if (msg.sender != technicalAddress) { return fail(Error.UNAUTHORIZED, FailureInfo.PARTICIPANT_CHECK); } // transfers accrued if (dflAccrued[technicalAddress] != 0) { doTransferOut(address(dflToken), technicalAddress, dflAccrued[technicalAddress]); delete dflAccrued[technicalAddress]; } address oldTechnicalAddress = technicalAddress; technicalAddress = newTechnicalAddress; emit TechnicalAddressChanged(oldTechnicalAddress, newTechnicalAddress); return uint(Error.NO_ERROR); } /** * @dev Change uniswapAddress * @param newUniswapAddress New value. * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function _setUniswapAddress(address newUniswapAddress) external nonReentrant returns (uint) { // accrue accrueDFL(); return _setUniswapAddressFresh(newUniswapAddress); } function _setUniswapAddressFresh(address newUniswapAddress) internal returns (uint) { // Check caller = admin if (msg.sender != admin) { return fail(Error.UNAUTHORIZED, FailureInfo.ADMIN_CHECK); } // transfers accrued if (dflAccrued[uniswapAddress] != 0) { doTransferOut(address(dflToken), uniswapAddress, dflAccrued[uniswapAddress]); delete dflAccrued[uniswapAddress]; } address oldUniswapAddress = uniswapAddress; uniswapAddress = newUniswapAddress; emit UniswapAddressChanged(oldUniswapAddress, newUniswapAddress); return uint(Error.NO_ERROR); } /** * @dev Change undistributedAddress * @param newUndistributedAddress New value. * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function _setUndistributedAddress(address newUndistributedAddress) external nonReentrant returns (uint) { // accrue accrueDFL(); return _setUndistributedAddressFresh(newUndistributedAddress); } function _setUndistributedAddressFresh(address newUndistributedAddress) internal returns (uint) { // Check caller = admin if (msg.sender != admin) { return fail(Error.UNAUTHORIZED, FailureInfo.ADMIN_CHECK); } // transfers accrued to old address if (dflAccrued[undistributedAddress] != 0) { doTransferOut(address(dflToken), undistributedAddress, dflAccrued[undistributedAddress]); delete dflAccrued[undistributedAddress]; } address oldUndistributedAddress = undistributedAddress; undistributedAddress = newUndistributedAddress; emit UndistributedAddressChanged(oldUndistributedAddress, newUndistributedAddress); return uint(Error.NO_ERROR); } /** * @dev Change DFL percentages * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details) */ function _setDFLPercentages(uint uniswapPercentage_, uint minerLeaguePercentage_, uint operatorPercentage_) external nonReentrant returns (uint) { accrueDFL(); return _setDFLPercentagesFresh(uniswapPercentage_, minerLeaguePercentage_, operatorPercentage_); } function _setDFLPercentagesFresh(uint uniswapPercentage_, uint minerLeaguePercentage_, uint operatorPercentage_) internal returns (uint) { // Check caller = admin if (msg.sender != admin) { return fail(Error.UNAUTHORIZED, FailureInfo.ADMIN_CHECK); } uint sumPercentage = add_(add_(add_(uniswapPercentage_, minerLeaguePercentage_), operatorPercentage_), technicalPercentage); require(sumPercentage <= mantissaOne, "PERCENTAGE_EXCEEDS"); uniswapPercentage = uniswapPercentage_; minerLeaguePercentage = minerLeaguePercentage_; operatorPercentage = operatorPercentage_; emit PercentagesChanged(uniswapPercentage_, minerLeaguePercentage_, operatorPercentage_); return uint(Error.NO_ERROR); } /*** Safe Token ***/ /** * @notice Gets balance of this contract in terms of the underlying * @dev This excludes the value of the current message, if any * @return The quantity of underlying tokens owned by this contract */ function getCashPrior() internal view returns (uint) { EIP20Interface token = EIP20Interface(eFILAddress); return token.balanceOf(address(this)); } /** * @dev Similar to EIP20 transfer, except it handles a False result from `transferFrom` and reverts in that case. * This will revert due to insufficient balance or insufficient allowance. * This function returns the actual amount received, * which may be less than `amount` if there is a fee attached to the transfer. * * Note: This wrapper safely handles non-standard ERC-20 tokens that do not return a value. * See here: https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca */ function doTransferIn(address underlying, address from, uint amount) internal returns (uint) { EIP20NonStandardInterface token = EIP20NonStandardInterface(underlying); uint balanceBefore = EIP20Interface(underlying).balanceOf(address(this)); token.transferFrom(from, address(this), amount); bool success; assembly { switch returndatasize() case 0 { // This is a non-standard ERC-20 success := not(0) // set success to true } case 32 { // This is a compliant ERC-20 returndatacopy(0, 0, 32) success := mload(0) // Set `success = returndata` of external call } default { // This is an excessively non-compliant ERC-20, revert. revert(0, 0) } } require(success, "TOKEN_TRANSFER_IN_FAILED"); // Calculate the amount that was *actually* transferred uint balanceAfter = EIP20Interface(underlying).balanceOf(address(this)); require(balanceAfter >= balanceBefore, "TOKEN_TRANSFER_IN_OVERFLOW"); return balanceAfter - balanceBefore; // underflow already checked above, just subtract } /** * @dev Similar to EIP20 transfer, except it handles a False success from `transfer` and returns an explanatory * error code rather than reverting. If caller has not called checked protocol's balance, this may revert due to * insufficient cash held in this contract. If caller has checked protocol's balance prior to this call, and verified * it is >= amount, this should not revert in normal conditions. * * Note: This wrapper safely handles non-standard ERC-20 tokens that do not return a value. * See here: https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca */ function doTransferOut(address underlying, address to, uint amount) internal { EIP20NonStandardInterface token = EIP20NonStandardInterface(underlying); token.transfer(to, amount); bool success; assembly { switch returndatasize() case 0 { // This is a non-standard ERC-20 success := not(0) // set success to true } case 32 { // This is a complaint ERC-20 returndatacopy(0, 0, 32) success := mload(0) // Set `success = returndata` of external call } default { // This is an excessively non-compliant ERC-20, revert. revert(0, 0) } } require(success, "TOKEN_TRANSFER_OUT_FAILED"); } } // File: contracts\StakingDFL.sol pragma solidity ^0.5.16; contract StakingDFL is ReentrancyGuard, Exponential { using SafeMath for uint; /** * @notice Address of DeFIL contract */ address public deFILAddress; /** * @notice Address of DFL */ address public dflAddress; /** * @notice Address of eFIL */ address public eFILAddress; /** * @notice Administrator for this contract */ address public admin; /** * @notice Pending administrator for this contract */ address public pendingAdmin; // Minimum bonus amount per share uint public minBonusAmount; // Reserved part that stands for already shared bonus. uint public sharedBonusAmount; // Total number of deposits. uint public totalDeposits; // Mapping of account to outstanding deposit balances mapping (address => uint) public accountDeposits; // The initial accrual index uint public constant initialAccruedIndex = 1e36; // The last accrued index uint public accruedIndex; // The index for each account as of the last time they accrued mapping(address => uint) public accountAccruedIndex; /*** Events ***/ // Event emitted when new Staking tokens is deposited event Deposit(address account, uint amount); // Event emitted when new Staking tokens is withdrawed event Withdraw(address account, uint amount); // Emitted when bonus is accrued event Bonus(uint amount, uint accruedIndex); // Emitted when bonus is distributed to a participant event Distributed(address account, uint amount); // Event emitted when pendingAdmin is changed event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin); // Event emitted when pendingAdmin is accepted, which means admin is updated event NewAdmin(address oldAdmin, address newAdmin); constructor(address dflAddress_, address eFILAddress_, uint minBonusAmount_) public { // set admin admin = msg.sender; dflAddress = dflAddress_; eFILAddress = eFILAddress_; minBonusAmount = minBonusAmount_; // init accrued index accruedIndex = initialAccruedIndex; } function accrueBonus() public { DeFIL deFIL = DeFIL(deFILAddress); deFIL.claimReserves(); if (totalDeposits == 0) { return; } EIP20Interface bonusToken = EIP20Interface(eFILAddress); uint thisBalance = bonusToken.balanceOf(address(this)); uint avaiableBalance = thisBalance.sub(sharedBonusAmount); if (avaiableBalance < minBonusAmount) { return; } Double memory ratio = fraction(avaiableBalance, totalDeposits); Double memory doubleAccruedIndex = add_(Double({mantissa: accruedIndex}), ratio); // update accruedIndex accruedIndex = doubleAccruedIndex.mantissa; sharedBonusAmount = sharedBonusAmount.add(avaiableBalance); emit Bonus(avaiableBalance, doubleAccruedIndex.mantissa); } // Accrue bonus and return the accrued bonus of account function accruedBonusCurrent() external nonReentrant returns(uint) { accrueBonus(); return accruedBonusStoredInternal(msg.sender); } // Return the accrued bonus of account based on stored data function accruedBonusStored() public view returns(uint) { return accruedBonusStoredInternal(msg.sender); } // Return the accrued bonus of account based on stored data function accruedBonusStoredInternal(address account) public view returns(uint) { Double memory doubleAccruedIndex = Double({mantissa: accruedIndex}); Double memory doubleAccountIndex = Double({mantissa: accountAccruedIndex[account]}); if (doubleAccountIndex.mantissa == 0 && doubleAccruedIndex.mantissa > 0) { doubleAccountIndex.mantissa = initialAccruedIndex; } Double memory deltaIndex = sub_(doubleAccruedIndex, doubleAccountIndex); uint accountDelta = mul_(accountDeposits[account], deltaIndex); return accountDelta; } function claim(address[] memory accounts) public nonReentrant { accrueBonus(); for (uint i = 0; i < accounts.length; i++) { distributeBonus(accounts[i]); } } function distributeBonus(address account) internal { uint accountDelta = accruedBonusStoredInternal(account); // transfer bonus token to account doTransferOut(eFILAddress, account, accountDelta); accountAccruedIndex[account] = accruedIndex; sharedBonusAmount = sharedBonusAmount.sub(accountDelta); emit Distributed(account, accountDelta); } // Deposit Staking tokens function deposit(uint amount) external nonReentrant { address account = msg.sender; // accrue & distribute accrueBonus(); distributeBonus(account); // transfer staking token in uint actualAmount = doTransferIn(dflAddress, account, amount); // increase total deposits totalDeposits = totalDeposits.add(actualAmount); accountDeposits[account] = accountDeposits[account].add(actualAmount); emit Deposit(account, actualAmount); } // Withdraw staking tokens function withdraw(uint amount) external nonReentrant { address account = msg.sender; require(accountDeposits[account] >= amount, "withdraw: insufficient value"); // accrue & distribute accrueBonus(); distributeBonus(account); // transfer staking tokens back to account doTransferOut(dflAddress, account, amount); // decrease total deposits totalDeposits = totalDeposits.sub(amount); accountDeposits[account] = accountDeposits[account].sub(amount); emit Withdraw(account, amount); } /*** Admin Functions ***/ /** * @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. * @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer. * @param newPendingAdmin New pending admin. */ function _setPendingAdmin(address newPendingAdmin) external { require(msg.sender == admin, "Not admin"); require(newPendingAdmin != address(0), "Bad pending admin"); // Save current value, if any, for inclusion in log address oldPendingAdmin = pendingAdmin; // Store pendingAdmin with value newPendingAdmin pendingAdmin = newPendingAdmin; // Emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin) emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin); } /** * @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin * @dev Admin function for pending admin to accept role and update admin */ function _acceptAdmin() external { // Check caller is pendingAdmin require(msg.sender == pendingAdmin && msg.sender != address(0), "Not pending admin"); // Save current values for inclusion in log address oldAdmin = admin; address oldPendingAdmin = pendingAdmin; // Store admin with value pendingAdmin admin = pendingAdmin; // Clear the pending value pendingAdmin = address(0); emit NewAdmin(oldAdmin, admin); emit NewPendingAdmin(oldPendingAdmin, pendingAdmin); } /** * @dev set DeFIL address * @param deFILAddress_ New value. */ function _setDeFILAddress(address deFILAddress_) external { require(deFILAddress == address(0), "Can noly set once"); require(msg.sender == admin, "Not admin"); deFILAddress = deFILAddress_; } /** * @dev Change minBonusAmount * @param minBonusAmount_ New value. */ function _setMinBonusAmount(uint minBonusAmount_) external { require(msg.sender == admin, "Not admin"); accrueBonus(); minBonusAmount = minBonusAmount_; } /*** Safe Token ***/ /** * @dev Similar to EIP20 transfer, except it handles a False result from `transferFrom` and reverts in that case. * This will revert due to insufficient balance or insufficient allowance. * This function returns the actual amount received, * which may be less than `amount` if there is a fee attached to the transfer. * * Note: This wrapper safely handles non-standard ERC-20 tokens that do not return a value. * See here: https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca */ function doTransferIn(address underlying, address from, uint amount) internal returns (uint) { EIP20NonStandardInterface token = EIP20NonStandardInterface(underlying); uint balanceBefore = EIP20Interface(underlying).balanceOf(address(this)); token.transferFrom(from, address(this), amount); bool success; assembly { switch returndatasize() case 0 { // This is a non-standard ERC-20 success := not(0) // set success to true } case 32 { // This is a compliant ERC-20 returndatacopy(0, 0, 32) success := mload(0) // Set `success = returndata` of external call } default { // This is an excessively non-compliant ERC-20, revert. revert(0, 0) } } require(success, "TOKEN_TRANSFER_IN_FAILED"); // Calculate the amount that was *actually* transferred uint balanceAfter = EIP20Interface(underlying).balanceOf(address(this)); require(balanceAfter >= balanceBefore, "TOKEN_TRANSFER_IN_OVERFLOW"); return balanceAfter - balanceBefore; // underflow already checked above, just subtract } /** * @dev Similar to EIP20 transfer, except it handles a False success from `transfer` and returns an explanatory * error code rather than reverting. If caller has not called checked protocol's balance, this may revert due to * insufficient cash held in this contract. If caller has checked protocol's balance prior to this call, and verified * it is >= amount, this should not revert in normal conditions. * * Note: This wrapper safely handles non-standard ERC-20 tokens that do not return a value. * See here: https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca */ function doTransferOut(address underlying, address to, uint amount) internal { EIP20NonStandardInterface token = EIP20NonStandardInterface(underlying); token.transfer(to, amount); bool success; assembly { switch returndatasize() case 0 { // This is a non-standard ERC-20 success := not(0) // set success to true } case 32 { // This is a complaint ERC-20 returndatacopy(0, 0, 32) success := mload(0) // Set `success = returndata` of external call } default { // This is an excessively non-compliant ERC-20, revert. revert(0, 0) } } require(success, "TOKEN_TRANSFER_OUT_FAILED"); } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"dflAddress_","type":"address"},{"internalType":"address","name":"eFILAddress_","type":"address"},{"internalType":"uint256","name":"minBonusAmount_","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"accruedIndex","type":"uint256"}],"name":"Bonus","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Distributed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"}],"name":"NewAdmin","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldPendingAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newPendingAdmin","type":"address"}],"name":"NewPendingAdmin","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdraw","type":"event"},{"constant":false,"inputs":[],"name":"_acceptAdmin","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"deFILAddress_","type":"address"}],"name":"_setDeFILAddress","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"minBonusAmount_","type":"uint256"}],"name":"_setMinBonusAmount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"newPendingAdmin","type":"address"}],"name":"_setPendingAdmin","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"accountAccruedIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"accountDeposits","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"accrueBonus","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"accruedBonusCurrent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"accruedBonusStored","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"accruedBonusStoredInternal","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"accruedIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address[]","name":"accounts","type":"address[]"}],"name":"claim","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"deFILAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"deposit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"dflAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"eFILAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"initialAccruedIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"minBonusAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"pendingAdmin","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"sharedBonusAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalDeposits","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdraw","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60806040523480156200001157600080fd5b50604051620017de380380620017de8339810160408190526200003491620000b0565b6001600055600480546001600160a01b03199081163317909155600280546001600160a01b0395861690831617905560038054939094169216919091179091556006556ec097ce7bc90715b34b9f1000000000600a556200013e565b80516200009d8162000119565b92915050565b80516200009d8162000133565b600080600060608486031215620000c657600080fd5b6000620000d4868662000090565b9350506020620000e78682870162000090565b9250506040620000fa86828701620000a3565b9150509250925092565b60006001600160a01b0382166200009d565b90565b620001248162000104565b81146200013057600080fd5b50565b620001248162000116565b611690806200014e6000396000f3fe608060405234801561001057600080fd5b506004361061014d5760003560e01c806378048359116100c3578063b6b55f251161007c578063b6b55f2514610241578063b71d1a0c14610254578063bb5260e414610267578063e2074e7e1461026f578063e9c714f214610282578063f851a4401461028a5761014d565b806378048359146102065780637d8820971461020e5780638355ae8114610216578063835dada01461021e578063993e00a814610231578063b2879ee4146102395761014d565b8063340ad04911610115578063340ad049146101c05780633d7ec221146101c857806347bad83b146101d057806348c84e68146101e3578063592e3a5b146101eb57806360ad954c146101f35761014d565b80631a2d668d14610152578063267822471461017b5780632e1a7d4d146101905780632fa0fad0146101a5578063318d9e5d146101ad575b600080fd5b610165610160366004611168565b610292565b604051610172919061156e565b60405180910390f35b610183610345565b6040516101729190611451565b6101a361019e3660046111c3565b610354565b005b61016561047b565b6101a36101bb36600461118e565b610481565b6101656104ea565b6101656104f0565b6101656101de366004611168565b610500565b6101a3610512565b6101656106cf565b6101a3610201366004611168565b6106e2565b610183610757565b610165610766565b61016561076c565b61016561022c366004611168565b6107b1565b6101656107c3565b6101836107c9565b6101a361024f3660046111c3565b6107d8565b6101a3610262366004611168565b6108ce565b61018361097d565b6101a361027d3660046111c3565b61098c565b6101a36109c3565b610183610aa1565b600061029c6110b5565b506040805160208101909152600a5481526102b56110b5565b5060408051602080820183526001600160a01b0386166000908152600b90915291909120548082521580156102ea5750815115155b15610302576ec097ce7bc90715b34b9f100000000081525b61030a6110b5565b6103148383610ab0565b6001600160a01b0386166000908152600960205260408120549192509061033b9083610ae0565b9695505050505050565b6005546001600160a01b031681565b600260005414156103805760405162461bcd60e51b81526004016103779061154e565b60405180910390fd5b600260009081553380825260096020526040909120548211156103b55760405162461bcd60e51b81526004016103779061151e565b6103bd610512565b6103c681610b0f565b6002546103dd906001600160a01b03168284610b98565b6008546103f0908363ffffffff610c4d16565b6008556001600160a01b03811660009081526009602052604090205461041c908363ffffffff610c4d16565b6001600160a01b0382166000908152600960205260409081902091909155517f884edad9ce6fa2440d8a54cc123490eb96d2768479d49ff9c7366125a94243649061046a90839085906114a2565b60405180910390a150506001600055565b60075481565b600260005414156104a45760405162461bcd60e51b81526004016103779061154e565b60026000556104b1610512565b60005b81518110156104e1576104d98282815181106104cc57fe5b6020026020010151610b0f565b6001016104b4565b50506001600055565b60065481565b60006104fb33610292565b905090565b600b6020526000908152604090205481565b60015460408051638af7cb8f60e01b815290516001600160a01b03909216918291638af7cb8f91600480830192600092919082900301818387803b15801561055957600080fd5b505af115801561056d573d6000803e3d6000fd5b505050506008546000141561058257506106cd565b6003546040516370a0823160e01b81526001600160a01b039091169060009082906370a08231906105b7903090600401611451565b60206040518083038186803b1580156105cf57600080fd5b505afa1580156105e3573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061060791908101906111e1565b9050600061062060075483610c4d90919063ffffffff16565b905060065481101561063557505050506106cd565b61063d6110b5565b61064982600854610c96565b90506106536110b5565b61066d6040518060200160405280600a5481525083610ccb565b8051600a55600754909150610688908463ffffffff610cf016565b60075580516040517f4fed9a60104e96799f37b7014d83bc025c24cb41cbc141c517ca3e788e8c86d3916106be9186919061157c565b60405180910390a15050505050505b565b6ec097ce7bc90715b34b9f100000000081565b6001546001600160a01b03161561070b5760405162461bcd60e51b8152600401610377906114de565b6004546001600160a01b031633146107355760405162461bcd60e51b81526004016103779061155e565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b6001546001600160a01b031681565b60085481565b6000600260005414156107915760405162461bcd60e51b81526004016103779061154e565b600260005561079e610512565b6107a733610292565b9050600160005590565b60096020526000908152604090205481565b600a5481565b6003546001600160a01b031681565b600260005414156107fb5760405162461bcd60e51b81526004016103779061154e565b600260005533610809610512565b61081281610b0f565b60025460009061082c906001600160a01b03168385610d15565b600854909150610842908263ffffffff610cf016565b6008556001600160a01b03821660009081526009602052604090205461086e908263ffffffff610cf016565b6001600160a01b0383166000908152600960205260409081902091909155517fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c906108bc90849084906114a2565b60405180910390a15050600160005550565b6004546001600160a01b031633146108f85760405162461bcd60e51b81526004016103779061155e565b6001600160a01b03811661091e5760405162461bcd60e51b81526004016103779061153e565b600580546001600160a01b038381166001600160a01b03198316179092556040519116907fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a990610971908390859061145f565b60405180910390a15050565b6002546001600160a01b031681565b6004546001600160a01b031633146109b65760405162461bcd60e51b81526004016103779061155e565b6109be610512565b600655565b6005546001600160a01b0316331480156109dc57503315155b6109f85760405162461bcd60e51b81526004016103779061152e565b60048054600580546001600160a01b038082166001600160a01b03198086168217968790559092169092556040519282169390927ff9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc92610a5c92869291169061145f565b60405180910390a16005546040517fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9916109719184916001600160a01b03169061145f565b6004546001600160a01b031681565b610ab86110b5565b6040518060200160405280610ad585600001518560000151610ef8565b905290505b92915050565b60006ec097ce7bc90715b34b9f1000000000610b00848460000151610f32565b81610b0757fe5b049392505050565b6000610b1a82610292565b600354909150610b34906001600160a01b03168383610b98565b600a546001600160a01b0383166000908152600b6020526040902055600754610b63908263ffffffff610c4d16565b6007556040517fb649c98f58055c520df0dcb5709eff2e931217ff2fb1e21376130d31bbb1c0af9061097190849084906114a2565b60405163a9059cbb60e01b815283906001600160a01b0382169063a9059cbb90610bc890869086906004016114a2565b600060405180830381600087803b158015610be257600080fd5b505af1158015610bf6573d6000803e3d6000fd5b5050505060003d60008114610c125760208114610c1c57600080fd5b6000199150610c28565b60206000803e60005191505b5080610c465760405162461bcd60e51b8152600401610377906114fe565b5050505050565b6000610c8f83836040518060400160405280601f81526020017f536166654d6174683a207375627472616374696f6e20756e646572666c6f7700815250610f74565b9392505050565b610c9e6110b5565b6040518060200160405280610ad5610cc5866ec097ce7bc90715b34b9f1000000000610f32565b85610fa0565b610cd36110b5565b6040518060200160405280610ad585600001518560000151610fd3565b600082820183811015610c8f5760405162461bcd60e51b81526004016103779061150e565b6040516370a0823160e01b8152600090849082906001600160a01b038316906370a0823190610d48903090600401611451565b60206040518083038186803b158015610d6057600080fd5b505afa158015610d74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610d9891908101906111e1565b6040516323b872dd60e01b81529091506001600160a01b038316906323b872dd90610dcb9088903090899060040161147a565b600060405180830381600087803b158015610de557600080fd5b505af1158015610df9573d6000803e3d6000fd5b5050505060003d60008114610e155760208114610e1f57600080fd5b6000199150610e2b565b60206000803e60005191505b5080610e495760405162461bcd60e51b8152600401610377906114ce565b6040516370a0823160e01b81526000906001600160a01b038916906370a0823190610e78903090600401611451565b60206040518083038186803b158015610e9057600080fd5b505afa158015610ea4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610ec891908101906111e1565b905082811015610eea5760405162461bcd60e51b8152600401610377906114ee565b919091039695505050505050565b6000610c8f8383604051806040016040528060158152602001747375627472616374696f6e20756e646572666c6f7760581b815250610f74565b6000610c8f83836040518060400160405280601781526020017f6d756c7469706c69636174696f6e206f766572666c6f77000000000000000000815250611009565b60008184841115610f985760405162461bcd60e51b815260040161037791906114bd565b505050900390565b6000610c8f83836040518060400160405280600e81526020016d646976696465206279207a65726f60901b81525061105a565b6000610c8f8383604051806040016040528060118152602001706164646974696f6e206f766572666c6f7760781b81525061108e565b6000831580611016575082155b1561102357506000610c8f565b8383028385828161103057fe5b041483906110515760405162461bcd60e51b815260040161037791906114bd565b50949350505050565b6000818361107b5760405162461bcd60e51b815260040161037791906114bd565b5082848161108557fe5b04949350505050565b600083830182858210156110515760405162461bcd60e51b815260040161037791906114bd565b6040518060200160405280600081525090565b8035610ada8161162d565b600082601f8301126110e457600080fd5b81356110f76110f2826115b1565b61158a565b9150818183526020840193506020810190508385602084028201111561111c57600080fd5b60005b83811015611148578161113288826110c8565b845250602092830192919091019060010161111f565b5050505092915050565b8035610ada81611644565b8051610ada81611644565b60006020828403121561117a57600080fd5b600061118684846110c8565b949350505050565b6000602082840312156111a057600080fd5b813567ffffffffffffffff8111156111b757600080fd5b611186848285016110d3565b6000602082840312156111d557600080fd5b60006111868484611152565b6000602082840312156111f357600080fd5b6000611186848461115d565b611208816115df565b82525050565b6000611219826115d2565b61122381856115d6565b93506112338185602086016115f3565b61123c81611623565b9093019392505050565b60006112536018836115d6565b7f544f4b454e5f5452414e534645525f494e5f4641494c45440000000000000000815260200192915050565b600061128c6011836115d6565b7043616e206e6f6c7920736574206f6e636560781b815260200192915050565b60006112b9601a836115d6565b7f544f4b454e5f5452414e534645525f494e5f4f564552464c4f57000000000000815260200192915050565b60006112f26019836115d6565b7f544f4b454e5f5452414e534645525f4f55545f4641494c454400000000000000815260200192915050565b600061132b601b836115d6565b7f536166654d6174683a206164646974696f6e206f766572666c6f770000000000815260200192915050565b6000611364601c836115d6565b7f77697468647261773a20696e73756666696369656e742076616c756500000000815260200192915050565b600061139d6011836115d6565b702737ba103832b73234b7339030b236b4b760791b815260200192915050565b60006113ca6011836115d6565b702130b2103832b73234b7339030b236b4b760791b815260200192915050565b60006113f7601f836115d6565b7f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00815260200192915050565b60006114306009836115d6565b682737ba1030b236b4b760b91b815260200192915050565b611208816115f0565b60208101610ada82846111ff565b6040810161146d82856111ff565b610c8f60208301846111ff565b6060810161148882866111ff565b61149560208301856111ff565b6111866040830184611448565b604081016114b082856111ff565b610c8f6020830184611448565b60208082528101610c8f818461120e565b60208082528101610ada81611246565b60208082528101610ada8161127f565b60208082528101610ada816112ac565b60208082528101610ada816112e5565b60208082528101610ada8161131e565b60208082528101610ada81611357565b60208082528101610ada81611390565b60208082528101610ada816113bd565b60208082528101610ada816113ea565b60208082528101610ada81611423565b60208101610ada8284611448565b604081016114b08285611448565b60405181810167ffffffffffffffff811182821017156115a957600080fd5b604052919050565b600067ffffffffffffffff8211156115c857600080fd5b5060209081020190565b5190565b90815260200190565b60006001600160a01b038216610ada565b90565b60005b8381101561160e5781810151838201526020016115f6565b8381111561161d576000848401525b50505050565b601f01601f191690565b611636816115df565b811461164157600080fd5b50565b611636816115f056fea365627a7a72315820587b23b55fdf7f57e82f8b3a884a8d9bab74f5fa71c52fa54d1830ba8c0874ac6c6578706572696d656e74616cf564736f6c634300051100400000000000000000000000006ded0f2c886568fb4bb6f04f179093d3d167c9d700000000000000000000000022b475f3e93390b7e523873ad7073337f4e56c2c000000000000000000000000000000000000000000000000016345785d8a0000
Deployed Bytecode
0x608060405234801561001057600080fd5b506004361061014d5760003560e01c806378048359116100c3578063b6b55f251161007c578063b6b55f2514610241578063b71d1a0c14610254578063bb5260e414610267578063e2074e7e1461026f578063e9c714f214610282578063f851a4401461028a5761014d565b806378048359146102065780637d8820971461020e5780638355ae8114610216578063835dada01461021e578063993e00a814610231578063b2879ee4146102395761014d565b8063340ad04911610115578063340ad049146101c05780633d7ec221146101c857806347bad83b146101d057806348c84e68146101e3578063592e3a5b146101eb57806360ad954c146101f35761014d565b80631a2d668d14610152578063267822471461017b5780632e1a7d4d146101905780632fa0fad0146101a5578063318d9e5d146101ad575b600080fd5b610165610160366004611168565b610292565b604051610172919061156e565b60405180910390f35b610183610345565b6040516101729190611451565b6101a361019e3660046111c3565b610354565b005b61016561047b565b6101a36101bb36600461118e565b610481565b6101656104ea565b6101656104f0565b6101656101de366004611168565b610500565b6101a3610512565b6101656106cf565b6101a3610201366004611168565b6106e2565b610183610757565b610165610766565b61016561076c565b61016561022c366004611168565b6107b1565b6101656107c3565b6101836107c9565b6101a361024f3660046111c3565b6107d8565b6101a3610262366004611168565b6108ce565b61018361097d565b6101a361027d3660046111c3565b61098c565b6101a36109c3565b610183610aa1565b600061029c6110b5565b506040805160208101909152600a5481526102b56110b5565b5060408051602080820183526001600160a01b0386166000908152600b90915291909120548082521580156102ea5750815115155b15610302576ec097ce7bc90715b34b9f100000000081525b61030a6110b5565b6103148383610ab0565b6001600160a01b0386166000908152600960205260408120549192509061033b9083610ae0565b9695505050505050565b6005546001600160a01b031681565b600260005414156103805760405162461bcd60e51b81526004016103779061154e565b60405180910390fd5b600260009081553380825260096020526040909120548211156103b55760405162461bcd60e51b81526004016103779061151e565b6103bd610512565b6103c681610b0f565b6002546103dd906001600160a01b03168284610b98565b6008546103f0908363ffffffff610c4d16565b6008556001600160a01b03811660009081526009602052604090205461041c908363ffffffff610c4d16565b6001600160a01b0382166000908152600960205260409081902091909155517f884edad9ce6fa2440d8a54cc123490eb96d2768479d49ff9c7366125a94243649061046a90839085906114a2565b60405180910390a150506001600055565b60075481565b600260005414156104a45760405162461bcd60e51b81526004016103779061154e565b60026000556104b1610512565b60005b81518110156104e1576104d98282815181106104cc57fe5b6020026020010151610b0f565b6001016104b4565b50506001600055565b60065481565b60006104fb33610292565b905090565b600b6020526000908152604090205481565b60015460408051638af7cb8f60e01b815290516001600160a01b03909216918291638af7cb8f91600480830192600092919082900301818387803b15801561055957600080fd5b505af115801561056d573d6000803e3d6000fd5b505050506008546000141561058257506106cd565b6003546040516370a0823160e01b81526001600160a01b039091169060009082906370a08231906105b7903090600401611451565b60206040518083038186803b1580156105cf57600080fd5b505afa1580156105e3573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061060791908101906111e1565b9050600061062060075483610c4d90919063ffffffff16565b905060065481101561063557505050506106cd565b61063d6110b5565b61064982600854610c96565b90506106536110b5565b61066d6040518060200160405280600a5481525083610ccb565b8051600a55600754909150610688908463ffffffff610cf016565b60075580516040517f4fed9a60104e96799f37b7014d83bc025c24cb41cbc141c517ca3e788e8c86d3916106be9186919061157c565b60405180910390a15050505050505b565b6ec097ce7bc90715b34b9f100000000081565b6001546001600160a01b03161561070b5760405162461bcd60e51b8152600401610377906114de565b6004546001600160a01b031633146107355760405162461bcd60e51b81526004016103779061155e565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b6001546001600160a01b031681565b60085481565b6000600260005414156107915760405162461bcd60e51b81526004016103779061154e565b600260005561079e610512565b6107a733610292565b9050600160005590565b60096020526000908152604090205481565b600a5481565b6003546001600160a01b031681565b600260005414156107fb5760405162461bcd60e51b81526004016103779061154e565b600260005533610809610512565b61081281610b0f565b60025460009061082c906001600160a01b03168385610d15565b600854909150610842908263ffffffff610cf016565b6008556001600160a01b03821660009081526009602052604090205461086e908263ffffffff610cf016565b6001600160a01b0383166000908152600960205260409081902091909155517fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c906108bc90849084906114a2565b60405180910390a15050600160005550565b6004546001600160a01b031633146108f85760405162461bcd60e51b81526004016103779061155e565b6001600160a01b03811661091e5760405162461bcd60e51b81526004016103779061153e565b600580546001600160a01b038381166001600160a01b03198316179092556040519116907fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a990610971908390859061145f565b60405180910390a15050565b6002546001600160a01b031681565b6004546001600160a01b031633146109b65760405162461bcd60e51b81526004016103779061155e565b6109be610512565b600655565b6005546001600160a01b0316331480156109dc57503315155b6109f85760405162461bcd60e51b81526004016103779061152e565b60048054600580546001600160a01b038082166001600160a01b03198086168217968790559092169092556040519282169390927ff9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc92610a5c92869291169061145f565b60405180910390a16005546040517fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9916109719184916001600160a01b03169061145f565b6004546001600160a01b031681565b610ab86110b5565b6040518060200160405280610ad585600001518560000151610ef8565b905290505b92915050565b60006ec097ce7bc90715b34b9f1000000000610b00848460000151610f32565b81610b0757fe5b049392505050565b6000610b1a82610292565b600354909150610b34906001600160a01b03168383610b98565b600a546001600160a01b0383166000908152600b6020526040902055600754610b63908263ffffffff610c4d16565b6007556040517fb649c98f58055c520df0dcb5709eff2e931217ff2fb1e21376130d31bbb1c0af9061097190849084906114a2565b60405163a9059cbb60e01b815283906001600160a01b0382169063a9059cbb90610bc890869086906004016114a2565b600060405180830381600087803b158015610be257600080fd5b505af1158015610bf6573d6000803e3d6000fd5b5050505060003d60008114610c125760208114610c1c57600080fd5b6000199150610c28565b60206000803e60005191505b5080610c465760405162461bcd60e51b8152600401610377906114fe565b5050505050565b6000610c8f83836040518060400160405280601f81526020017f536166654d6174683a207375627472616374696f6e20756e646572666c6f7700815250610f74565b9392505050565b610c9e6110b5565b6040518060200160405280610ad5610cc5866ec097ce7bc90715b34b9f1000000000610f32565b85610fa0565b610cd36110b5565b6040518060200160405280610ad585600001518560000151610fd3565b600082820183811015610c8f5760405162461bcd60e51b81526004016103779061150e565b6040516370a0823160e01b8152600090849082906001600160a01b038316906370a0823190610d48903090600401611451565b60206040518083038186803b158015610d6057600080fd5b505afa158015610d74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610d9891908101906111e1565b6040516323b872dd60e01b81529091506001600160a01b038316906323b872dd90610dcb9088903090899060040161147a565b600060405180830381600087803b158015610de557600080fd5b505af1158015610df9573d6000803e3d6000fd5b5050505060003d60008114610e155760208114610e1f57600080fd5b6000199150610e2b565b60206000803e60005191505b5080610e495760405162461bcd60e51b8152600401610377906114ce565b6040516370a0823160e01b81526000906001600160a01b038916906370a0823190610e78903090600401611451565b60206040518083038186803b158015610e9057600080fd5b505afa158015610ea4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610ec891908101906111e1565b905082811015610eea5760405162461bcd60e51b8152600401610377906114ee565b919091039695505050505050565b6000610c8f8383604051806040016040528060158152602001747375627472616374696f6e20756e646572666c6f7760581b815250610f74565b6000610c8f83836040518060400160405280601781526020017f6d756c7469706c69636174696f6e206f766572666c6f77000000000000000000815250611009565b60008184841115610f985760405162461bcd60e51b815260040161037791906114bd565b505050900390565b6000610c8f83836040518060400160405280600e81526020016d646976696465206279207a65726f60901b81525061105a565b6000610c8f8383604051806040016040528060118152602001706164646974696f6e206f766572666c6f7760781b81525061108e565b6000831580611016575082155b1561102357506000610c8f565b8383028385828161103057fe5b041483906110515760405162461bcd60e51b815260040161037791906114bd565b50949350505050565b6000818361107b5760405162461bcd60e51b815260040161037791906114bd565b5082848161108557fe5b04949350505050565b600083830182858210156110515760405162461bcd60e51b815260040161037791906114bd565b6040518060200160405280600081525090565b8035610ada8161162d565b600082601f8301126110e457600080fd5b81356110f76110f2826115b1565b61158a565b9150818183526020840193506020810190508385602084028201111561111c57600080fd5b60005b83811015611148578161113288826110c8565b845250602092830192919091019060010161111f565b5050505092915050565b8035610ada81611644565b8051610ada81611644565b60006020828403121561117a57600080fd5b600061118684846110c8565b949350505050565b6000602082840312156111a057600080fd5b813567ffffffffffffffff8111156111b757600080fd5b611186848285016110d3565b6000602082840312156111d557600080fd5b60006111868484611152565b6000602082840312156111f357600080fd5b6000611186848461115d565b611208816115df565b82525050565b6000611219826115d2565b61122381856115d6565b93506112338185602086016115f3565b61123c81611623565b9093019392505050565b60006112536018836115d6565b7f544f4b454e5f5452414e534645525f494e5f4641494c45440000000000000000815260200192915050565b600061128c6011836115d6565b7043616e206e6f6c7920736574206f6e636560781b815260200192915050565b60006112b9601a836115d6565b7f544f4b454e5f5452414e534645525f494e5f4f564552464c4f57000000000000815260200192915050565b60006112f26019836115d6565b7f544f4b454e5f5452414e534645525f4f55545f4641494c454400000000000000815260200192915050565b600061132b601b836115d6565b7f536166654d6174683a206164646974696f6e206f766572666c6f770000000000815260200192915050565b6000611364601c836115d6565b7f77697468647261773a20696e73756666696369656e742076616c756500000000815260200192915050565b600061139d6011836115d6565b702737ba103832b73234b7339030b236b4b760791b815260200192915050565b60006113ca6011836115d6565b702130b2103832b73234b7339030b236b4b760791b815260200192915050565b60006113f7601f836115d6565b7f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00815260200192915050565b60006114306009836115d6565b682737ba1030b236b4b760b91b815260200192915050565b611208816115f0565b60208101610ada82846111ff565b6040810161146d82856111ff565b610c8f60208301846111ff565b6060810161148882866111ff565b61149560208301856111ff565b6111866040830184611448565b604081016114b082856111ff565b610c8f6020830184611448565b60208082528101610c8f818461120e565b60208082528101610ada81611246565b60208082528101610ada8161127f565b60208082528101610ada816112ac565b60208082528101610ada816112e5565b60208082528101610ada8161131e565b60208082528101610ada81611357565b60208082528101610ada81611390565b60208082528101610ada816113bd565b60208082528101610ada816113ea565b60208082528101610ada81611423565b60208101610ada8284611448565b604081016114b08285611448565b60405181810167ffffffffffffffff811182821017156115a957600080fd5b604052919050565b600067ffffffffffffffff8211156115c857600080fd5b5060209081020190565b5190565b90815260200190565b60006001600160a01b038216610ada565b90565b60005b8381101561160e5781810151838201526020016115f6565b8381111561161d576000848401525b50505050565b601f01601f191690565b611636816115df565b811461164157600080fd5b50565b611636816115f056fea365627a7a72315820587b23b55fdf7f57e82f8b3a884a8d9bab74f5fa71c52fa54d1830ba8c0874ac6c6578706572696d656e74616cf564736f6c63430005110040
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000006ded0f2c886568fb4bb6f04f179093d3d167c9d700000000000000000000000022b475f3e93390b7e523873ad7073337f4e56c2c000000000000000000000000000000000000000000000000016345785d8a0000
-----Decoded View---------------
Arg [0] : dflAddress_ (address): 0x6ded0F2c886568Fb4Bb6F04f179093D3D167c9D7
Arg [1] : eFILAddress_ (address): 0x22B475f3e93390b7E523873ad7073337f4E56C2c
Arg [2] : minBonusAmount_ (uint256): 100000000000000000
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 0000000000000000000000006ded0f2c886568fb4bb6f04f179093d3d167c9d7
Arg [1] : 00000000000000000000000022b475f3e93390b7e523873ad7073337f4e56c2c
Arg [2] : 000000000000000000000000000000000000000000000000016345785d8a0000
Deployed Bytecode Sourcemap
136622:11971:0:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;136622:11971:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;140261:605;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;137138:27;;;:::i;:::-;;;;;;;;142092:593;;;;;;;;;:::i;:::-;;137308:29;;;:::i;140874:202::-;;;;;;;;;:::i;137213:26::-;;;:::i;140068:120::-;;;:::i;137752:51::-;;;;;;;;;:::i;138915:856::-;;;:::i;137564:47::-;;;:::i;144445:224::-;;;;;;;;;:::i;136773:27::-;;;:::i;137380:25::-;;;:::i;139840:155::-;;;:::i;137473:48::-;;;;;;;;;:::i;137651:24::-;;;:::i;136938:26::-;;;:::i;141526:526::-;;;;;;;;;:::i;143043:537::-;;;;;;;;;:::i;136856:25::-;;;:::i;144775:186::-;;;;;;;;;:::i;143769:576::-;;;:::i;137037:20::-;;;:::i;140261:605::-;140334:4;140351:32;;:::i;:::-;-1:-1:-1;140386:32:0;;;;;;;;;140404:12;;140386:32;;140429;;:::i;:::-;-1:-1:-1;140464:48:0;;;;;;;;;-1:-1:-1;;;;;140482:28:0;;-1:-1:-1;140482:28:0;;;:19;:28;;;;;;;;140464:48;;;140527:32;:67;;;;-1:-1:-1;140563:27:0;;:31;;140527:67;140523:149;;;137607:4;140611:49;;140523:149;140684:24;;:::i;:::-;140711:44;140716:18;140736;140711:4;:44::i;:::-;-1:-1:-1;;;;;140791:24:0;;140766:17;140791:24;;;:15;:24;;;;;;140684:71;;-1:-1:-1;140766:17:0;140786:42;;140684:71;140786:4;:42::i;:::-;140766:62;140261:605;-1:-1:-1;;;;;;140261:605:0:o;137138:27::-;;;-1:-1:-1;;;;;137138:27:0;;:::o;142092:593::-;28853:1;29459:7;;:19;;29451:63;;;;-1:-1:-1;;;29451:63:0;;;;;;;;;;;;;;;;;28853:1;29592:7;:18;;;142174:10;142203:24;;;:15;:24;;;;;;;:34;-1:-1:-1;142203:34:0;142195:75;;;;-1:-1:-1;;;142195:75:0;;;;;;;;;142315:13;:11;:13::i;:::-;142339:24;142355:7;142339:15;:24::i;:::-;142442:10;;142428:42;;-1:-1:-1;;;;;142442:10:0;142454:7;142463:6;142428:13;:42::i;:::-;142535:13;;:25;;142553:6;142535:25;:17;:25;:::i;:::-;142519:13;:41;-1:-1:-1;;;;;142598:24:0;;;;;;:15;:24;;;;;;:36;;142627:6;142598:36;:28;:36;:::i;:::-;-1:-1:-1;;;;;142571:24:0;;;;;;:15;:24;;;;;;;:63;;;;142652:25;;;;;142587:7;;142670:6;;142652:25;;;;;;;;;;-1:-1:-1;;28809:1:0;29771:7;:22;142092:593::o;137308:29::-;;;;:::o;140874:202::-;28853:1;29459:7;;:19;;29451:63;;;;-1:-1:-1;;;29451:63:0;;;;;;;;;28853:1;29592:7;:18;140947:13;:11;:13::i;:::-;140976:6;140971:98;140992:8;:15;140988:1;:19;140971:98;;;141029:28;141045:8;141054:1;141045:11;;;;;;;;;;;;;;141029:15;:28::i;:::-;141009:3;;140971:98;;;-1:-1:-1;;28809:1:0;29771:7;:22;140874:202::o;137213:26::-;;;;:::o;140068:120::-;140118:4;140142:38;140169:10;140142:26;:38::i;:::-;140135:45;;140068:120;:::o;137752:51::-;;;;;;;;;;;;;:::o;138915:856::-;138976:12;;139000:21;;;-1:-1:-1;;;139000:21:0;;;;-1:-1:-1;;;;;138976:12:0;;;;;;139000:19;;:21;;;;;138956:11;;139000:21;;;;;;;138956:11;138976:12;139000:21;;;5:2:-1;;;;30:1;27;20:12;5:2;139000:21:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;139000:21:0;;;;139038:13;;139055:1;139038:18;139034:57;;;139073:7;;;139034:57;139146:11;;139188:35;;-1:-1:-1;;;139188:35:0;;-1:-1:-1;;;;;139146:11:0;;;;139103:25;;139146:11;;139188:20;;:35;;139217:4;;139188:35;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;139188:35:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;139188:35:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;139188:35:0;;;;;;;;;139169:54;;139234:20;139257:34;139273:17;;139257:11;:15;;:34;;;;:::i;:::-;139234:57;;139324:14;;139306:15;:32;139302:71;;;139355:7;;;;;;139302:71;139385:19;;:::i;:::-;139407:40;139416:15;139433:13;;139407:8;:40::i;:::-;139385:62;;139458:32;;:::i;:::-;139493:45;139498:32;;;;;;;;139516:12;;139498:32;;;139532:5;139493:4;:45::i;:::-;139598:27;;139583:12;:42;139656:17;;139458:80;;-1:-1:-1;139656:38:0;;139678:15;139656:38;:21;:38;:::i;:::-;139636:17;:58;139735:27;;139712:51;;;;;;139718:15;;139735:27;139712:51;;;;;;;;;;138915:856;;;;;;;:::o;137564:47::-;137607:4;137564:47;:::o;144445:224::-;144522:12;;-1:-1:-1;;;;;144522:12:0;:26;144514:56;;;;-1:-1:-1;;;144514:56:0;;;;;;;;;144603:5;;-1:-1:-1;;;;;144603:5:0;144589:10;:19;144581:41;;;;-1:-1:-1;;;144581:41:0;;;;;;;;;144633:12;:28;;-1:-1:-1;;;;;;144633:28:0;-1:-1:-1;;;;;144633:28:0;;;;;;;;;;144445:224::o;136773:27::-;;;-1:-1:-1;;;;;136773:27:0;;:::o;137380:25::-;;;;:::o;139840:155::-;139901:4;28853:1;29459:7;;:19;;29451:63;;;;-1:-1:-1;;;29451:63:0;;;;;;;;;28853:1;29592:7;:18;139918:13;:11;:13::i;:::-;139949:38;139976:10;139949:26;:38::i;:::-;139942:45;;28809:1;29771:7;:22;139840:155;:::o;137473:48::-;;;;;;;;;;;;;:::o;137651:24::-;;;;:::o;136938:26::-;;;-1:-1:-1;;;;;136938:26:0;;:::o;141526:526::-;28853:1;29459:7;;:19;;29451:63;;;;-1:-1:-1;;;29451:63:0;;;;;;;;;28853:1;29592:7;:18;141607:10;141660:13;:11;:13::i;:::-;141684:24;141700:7;141684:15;:24::i;:::-;141792:10;;141759:17;;141779:41;;-1:-1:-1;;;;;141792:10:0;141804:7;141813:6;141779:12;:41::i;:::-;141885:13;;141759:61;;-1:-1:-1;141885:31:0;;141759:61;141885:31;:17;:31;:::i;:::-;141869:13;:47;-1:-1:-1;;;;;141954:24:0;;;;;;:15;:24;;;;;;:42;;141983:12;141954:42;:28;:42;:::i;:::-;-1:-1:-1;;;;;141927:24:0;;;;;;:15;:24;;;;;;;:69;;;;142014:30;;;;;141943:7;;142031:12;;142014:30;;;;;;;;;;-1:-1:-1;;28809:1:0;29771:7;:22;-1:-1:-1;141526:526:0:o;143043:537::-;143136:5;;-1:-1:-1;;;;;143136:5:0;143122:10;:19;143114:41;;;;-1:-1:-1;;;143114:41:0;;;;;;;;;-1:-1:-1;;;;;143174:29:0;;143166:59;;;;-1:-1:-1;;;143166:59:0;;;;;;;;;143325:12;;;-1:-1:-1;;;;;143408:30:0;;;-1:-1:-1;;;;;;143408:30:0;;;;;;143523:49;;143325:12;;;143523:49;;;;143325:12;;143423:15;;143523:49;;;;;;;;;;143043:537;;:::o;136856:25::-;;;-1:-1:-1;;;;;136856:25:0;;:::o;144775:186::-;144867:5;;-1:-1:-1;;;;;144867:5:0;144853:10;:19;144845:41;;;;-1:-1:-1;;;144845:41:0;;;;;;;;;144897:13;:11;:13::i;:::-;144921:14;:32;144775:186::o;143769:576::-;143876:12;;-1:-1:-1;;;;;143876:12:0;143862:10;:26;:54;;;;-1:-1:-1;143892:10:0;:24;;143862:54;143854:84;;;;-1:-1:-1;;;143854:84:0;;;;;;;;;144023:5;;;144065:12;;;-1:-1:-1;;;;;144065:12:0;;;-1:-1:-1;;;;;;144138:20:0;;;;;;;;;144207:25;;;;;;144250;;144023:5;;;;144065:12;;144250:25;;;;144023:5;;144269;;;144250:25;;;;;;;;;;144324:12;;144291:46;;;;;;144307:15;;-1:-1:-1;;;;;144324:12:0;;144291:46;;137037:20;;;-1:-1:-1;;;;;137037:20:0;;:::o;17388:160::-;17459:13;;:::i;:::-;17492:48;;;;;;;;17510:28;17515:1;:10;;;17527:1;:10;;;17510:4;:28::i;:::-;17492:48;;17485:55;-1:-1:-1;17388:160:0;;;;;:::o;18619:127::-;18681:4;8259;18705:19;18710:1;18713;:10;;;18705:4;:19::i;:::-;:33;;;;;;;18619:127;-1:-1:-1;;;18619:127:0:o;141084:403::-;141146:17;141166:35;141193:7;141166:26;:35::i;:::-;141270:11;;141146:55;;-1:-1:-1;141256:49:0;;-1:-1:-1;;;;;141270:11:0;141283:7;141146:55;141256:13;:49::i;:::-;141349:12;;-1:-1:-1;;;;;141318:28:0;;;;;;:19;:28;;;;;:43;141392:17;;:35;;141414:12;141392:35;:21;:35;:::i;:::-;141372:17;:55;141445:34;;;;;;141457:7;;141466:12;;141445:34;;147674:916;147844:26;;-1:-1:-1;;;147844:26:0;;147822:10;;-1:-1:-1;;;;;147844:14:0;;;;;:26;;147859:2;;147863:6;;147844:26;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;147844:26:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;147844:26:0;;;;147883:12;147937:16;147976:1;147971:152;;;;148146:2;148141:219;;;;148495:1;148492;148485:12;147971:152;-1:-1:-1;;148066:6:0;-1:-1:-1;147971:152:0;;148141:219;148243:2;148240:1;148237;148222:24;148285:1;148279:8;148268:19;;147930:586;;148545:7;148537:45;;;;-1:-1:-1;;;148537:45:0;;;;;;;;;147674:916;;;;;:::o;22420:137::-;22478:7;22505:44;22509:1;22512;22505:44;;;;;;;;;;;;;;;;;:3;:44::i;:::-;22498:51;22420:137;-1:-1:-1;;;22420:137:0:o;20352:147::-;20409:13;;:::i;:::-;20442:49;;;;;;;;20460:29;20465:20;20470:1;8259:4;20465;:20::i;:::-;20487:1;20460:4;:29::i;16753:160::-;16824:13;;:::i;:::-;16857:48;;;;;;;;16875:28;16880:1;:10;;;16892:1;:10;;;16875:4;:28::i;21527:181::-;21585:7;21617:5;;;21641:6;;;;21633:46;;;;-1:-1:-1;;;21633:46:0;;;;;;;;145606:1364;145813:51;;-1:-1:-1;;;145813:51:0;;145693:4;;145770:10;;145693:4;;-1:-1:-1;;;;;145813:36:0;;;;;:51;;145858:4;;145813:51;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;145813:51:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;145813:51:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;145813:51:0;;;;;;;;;145875:47;;-1:-1:-1;;;145875:47:0;;145792:72;;-1:-1:-1;;;;;;145875:18:0;;;;;:47;;145894:4;;145908;;145915:6;;145875:47;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;145875:47:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;145875:47:0;;;;145935:12;145989:16;146028:1;146023:153;;;;146199:2;146194:220;;;;146550:1;146547;146540:12;146023:153;-1:-1:-1;;146119:6:0;-1:-1:-1;146023:153:0;;146194:220;146297:2;146294:1;146291;146276:24;146339:1;146333:8;146322:19;;145982:589;;146600:7;146592:44;;;;-1:-1:-1;;;146592:44:0;;;;;;;;;146734:51;;-1:-1:-1;;;146734:51:0;;146714:17;;-1:-1:-1;;;;;146734:36:0;;;;;:51;;146779:4;;146734:51;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;146734:51:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;146734:51:0;;;;;;;101:4:-1;97:9;90:4;84;80:15;76:31;69:5;65:43;126:6;120:4;113:20;0:138;146734:51:0;;;;;;;;;146714:71;;146820:13;146804:12;:29;;146796:68;;;;-1:-1:-1;;;146796:68:0;;;;;;;;;146882:28;;;;;145606:1364;-1:-1:-1;;;;;;145606:1364:0:o;17556:120::-;17609:4;17633:35;17638:1;17641;17633:35;;;;;;;;;;;;;-1:-1:-1;;;17633:35:0;;;:4;:35::i;18754:122::-;18807:4;18831:37;18836:1;18839;18831:37;;;;;;;;;;;;;;;;;:4;:37::i;22846:192::-;22932:7;22968:12;22960:6;;;;22952:29;;;;-1:-1:-1;;;22952:29:0;;;;;;;;;;-1:-1:-1;;;23004:5:0;;;22846:192::o;20066:113::-;20119:4;20143:28;20148:1;20151;20143:28;;;;;;;;;;;;;-1:-1:-1;;;20143:28:0;;;:4;:28::i;16921:116::-;16974:4;16998:31;17003:1;17006;16998:31;;;;;;;;;;;;;-1:-1:-1;;;16998:31:0;;;:4;:31::i;18884:250::-;18965:4;18986:6;;;:16;;-1:-1:-1;18996:6:0;;18986:16;18982:57;;;-1:-1:-1;19026:1:0;19019:8;;18982:57;19058:5;;;19062:1;19058;:5;:1;19082:5;;;;;:10;19094:12;19074:33;;;;;-1:-1:-1;;;19074:33:0;;;;;;;;;;-1:-1:-1;19125:1:0;18884:250;-1:-1:-1;;;;18884:250:0:o;20187:157::-;20268:4;20300:12;20293:5;20285:28;;;;-1:-1:-1;;;20285:28:0;;;;;;;;;;;20335:1;20331;:5;;;;;;;20187:157;-1:-1:-1;;;;20187:157:0:o;17045:179::-;17126:4;17152:5;;;17184:12;17176:6;;;;17168:29;;;;-1:-1:-1;;;17168:29:0;;;;;;;;;136622:11971;;;;;;;;;;;;;;:::o;5:130:-1:-;72:20;;97:33;72:20;97:33;;160:707;;277:3;270:4;262:6;258:17;254:27;244:2;;295:1;292;285:12;244:2;332:6;319:20;354:80;369:64;426:6;369:64;;;354:80;;;345:89;;451:5;476:6;469:5;462:21;506:4;498:6;494:17;484:27;;528:4;523:3;519:14;512:21;;581:6;628:3;620:4;612:6;608:17;603:3;599:27;596:36;593:2;;;645:1;642;635:12;593:2;670:1;655:206;680:6;677:1;674:13;655:206;;;738:3;760:37;793:3;781:10;760:37;;;748:50;;-1:-1;821:4;812:14;;;;840;;;;;702:1;695:9;655:206;;;659:14;237:630;;;;;;;;875:130;942:20;;967:33;942:20;967:33;;1012:134;1090:13;;1108:33;1090:13;1108:33;;1153:241;;1257:2;1245:9;1236:7;1232:23;1228:32;1225:2;;;1273:1;1270;1263:12;1225:2;1308:1;1325:53;1370:7;1350:9;1325:53;;;1315:63;1219:175;-1:-1;;;;1219:175;1401:377;;1530:2;1518:9;1509:7;1505:23;1501:32;1498:2;;;1546:1;1543;1536:12;1498:2;1581:31;;1632:18;1621:30;;1618:2;;;1664:1;1661;1654:12;1618:2;1684:78;1754:7;1745:6;1734:9;1730:22;1684:78;;1785:241;;1889:2;1877:9;1868:7;1864:23;1860:32;1857:2;;;1905:1;1902;1895:12;1857:2;1940:1;1957:53;2002:7;1982:9;1957:53;;2033:263;;2148:2;2136:9;2127:7;2123:23;2119:32;2116:2;;;2164:1;2161;2154:12;2116:2;2199:1;2216:64;2272:7;2252:9;2216:64;;2303:113;2386:24;2404:5;2386:24;;;2381:3;2374:37;2368:48;;;2423:347;;2535:39;2568:5;2535:39;;;2586:71;2650:6;2645:3;2586:71;;;2579:78;;2662:52;2707:6;2702:3;2695:4;2688:5;2684:16;2662:52;;;2735:29;2757:6;2735:29;;;2726:39;;;;2515:255;-1:-1;;;2515:255;2778:324;;2938:67;3002:2;2997:3;2938:67;;;3038:26;3018:47;;3093:2;3084:12;;2924:178;-1:-1;;2924:178;3111:317;;3271:67;3335:2;3330:3;3271:67;;;-1:-1;;;3351:40;;3419:2;3410:12;;3257:171;-1:-1;;3257:171;3437:326;;3597:67;3661:2;3656:3;3597:67;;;3697:28;3677:49;;3754:2;3745:12;;3583:180;-1:-1;;3583:180;3772:325;;3932:67;3996:2;3991:3;3932:67;;;4032:27;4012:48;;4088:2;4079:12;;3918:179;-1:-1;;3918:179;4106:327;;4266:67;4330:2;4325:3;4266:67;;;4366:29;4346:50;;4424:2;4415:12;;4252:181;-1:-1;;4252:181;4442:328;;4602:67;4666:2;4661:3;4602:67;;;4702:30;4682:51;;4761:2;4752:12;;4588:182;-1:-1;;4588:182;4779:317;;4939:67;5003:2;4998:3;4939:67;;;-1:-1;;;5019:40;;5087:2;5078:12;;4925:171;-1:-1;;4925:171;5105:317;;5265:67;5329:2;5324:3;5265:67;;;-1:-1;;;5345:40;;5413:2;5404:12;;5251:171;-1:-1;;5251:171;5431:331;;5591:67;5655:2;5650:3;5591:67;;;5691:33;5671:54;;5753:2;5744:12;;5577:185;-1:-1;;5577:185;5771:308;;5931:66;5995:1;5990:3;5931:66;;;-1:-1;;;6010:32;;6070:2;6061:12;;5917:162;-1:-1;;5917:162;6087:113;6170:24;6188:5;6170:24;;6207:213;6325:2;6310:18;;6339:71;6314:9;6383:6;6339:71;;6427:324;6573:2;6558:18;;6587:71;6562:9;6631:6;6587:71;;;6669:72;6737:2;6726:9;6722:18;6713:6;6669:72;;6758:435;6932:2;6917:18;;6946:71;6921:9;6990:6;6946:71;;;7028:72;7096:2;7085:9;7081:18;7072:6;7028:72;;;7111;7179:2;7168:9;7164:18;7155:6;7111:72;;7200:324;7346:2;7331:18;;7360:71;7335:9;7404:6;7360:71;;;7442:72;7510:2;7499:9;7495:18;7486:6;7442:72;;7531:301;7669:2;7683:47;;;7654:18;;7744:78;7654:18;7808:6;7744:78;;7839:407;8030:2;8044:47;;;8015:18;;8105:131;8015:18;8105:131;;8253:407;8444:2;8458:47;;;8429:18;;8519:131;8429:18;8519:131;;8667:407;8858:2;8872:47;;;8843:18;;8933:131;8843:18;8933:131;;9081:407;9272:2;9286:47;;;9257:18;;9347:131;9257:18;9347:131;;9495:407;9686:2;9700:47;;;9671:18;;9761:131;9671:18;9761:131;;9909:407;10100:2;10114:47;;;10085:18;;10175:131;10085:18;10175:131;;10323:407;10514:2;10528:47;;;10499:18;;10589:131;10499:18;10589:131;;10737:407;10928:2;10942:47;;;10913:18;;11003:131;10913:18;11003:131;;11151:407;11342:2;11356:47;;;11327:18;;11417:131;11327:18;11417:131;;11565:407;11756:2;11770:47;;;11741:18;;11831:131;11741:18;11831:131;;11979:213;12097:2;12082:18;;12111:71;12086:9;12155:6;12111:71;;12199:324;12345:2;12330:18;;12359:71;12334:9;12403:6;12359:71;;12530:256;12592:2;12586:9;12618:17;;;12693:18;12678:34;;12714:22;;;12675:62;12672:2;;;12750:1;12747;12740:12;12672:2;12766;12759:22;12570:216;;-1:-1;12570:216;12793:304;;12952:18;12944:6;12941:30;12938:2;;;12984:1;12981;12974:12;12938:2;-1:-1;13019:4;13007:17;;;13072:15;;12875:222;13104:122;13192:12;;13163:63;13234:163;13337:19;;;13386:4;13377:14;;13330:67;13405:91;;-1:-1;;;;;13565:54;;13467:24;13548:76;13631:72;13693:5;13676:27;13711:268;13776:1;13783:101;13797:6;13794:1;13791:13;13783:101;;;13864:11;;;13858:18;13845:11;;;13838:39;13819:2;13812:10;13783:101;;;13899:6;13896:1;13893:13;13890:2;;;13964:1;13955:6;13950:3;13946:16;13939:27;13890:2;13760:219;;;;;13987:97;14075:2;14055:14;-1:-1;;14051:28;;14035:49;14092:117;14161:24;14179:5;14161:24;;;14154:5;14151:35;14141:2;;14200:1;14197;14190:12;14141:2;14135:74;;14216:117;14285:24;14303:5;14285:24;
Swarm Source
bzzr://587b23b55fdf7f57e82f8b3a884a8d9bab74f5fa71c52fa54d1830ba8c0874ac
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.