Cryo Explorer Ethereum Mainnet

Address Contract Partially Verified

Address 0xc92FAb4De20E5C2A3Ca5BA7DB4dd81480Ad1Ff04
Balance 0 ETH
Nonce 2
Code Size 5956 bytes
Indexed Transactions 0
External Etherscan · Sourcify

Contract Bytecode

5956 bytes
0x60806040523480156200001157600080fd5b50600436106200016b5760003560e01c806367fc6dea11620000d5578063b38c43e31162000087578063b38c43e31462000279578063b86677fe1462000290578063b888c479146200029a578063c5fa55a514620002a4578063cf4f363014620002bb578063da8be86414620002d2576200016b565b806367fc6dea146200023057806378e97925146200023a57806380d04de814620002445780639e88d77e146200024e578063acc4bd081462000265578063ae951b2e146200026f576200016b565b806318369a2a116200012f57806318369a2a14620001f457806328b5030b14620001fe57806338af3eed1462000208578063427db38014620002125780634929e162146200021c578063626be5671462000226576200016b565b8062d89b331462000170578063026e402b14620001925780630357371d14620001ab5780630f45cc8114620001c25780630fb5a6b414620001db575b600080fd5b6200017a620002e9565b60405162000189919062000e18565b60405180910390f35b620001a9620001a336600462000d69565b620002f2565b005b620001a9620001bc36600462000d69565b62000503565b620001cc620005f0565b60405162000189919062000dd1565b620001e5620005ff565b604051620001899190620010c3565b620001e562000605565b620001e56200060b565b620001cc6200066b565b620001cc6200067a565b620001a962000689565b620001e5620006fc565b620001e562000721565b620001e56200075b565b620001e562000761565b620001e56200025f36600462000d4b565b62000767565b620001e562000779565b6200017a6200078e565b620001a96200028a36600462000d4b565b620007a0565b620001cc62000836565b620001e562000845565b620001a9620002b536600462000d4b565b62000865565b620001cc620002cc36600462000d4b565b620008dc565b620001e5620002e336600462000d4b565b620008f7565b60005415155b90565b6003546001600160a01b03163314620003285760405162461bcd60e51b81526004016200031f9062000eff565b60405180910390fd5b6200033262000a56565b811115620003545760405162461bcd60e51b81526004016200031f9062000fe2565b6001600160a01b0382811660009081526007602052604090205416156200039557620003926200038483620008f7565b829063ffffffff62000add16565b90505b6009546040516001600160a01b039091169060009084908390620003b99062000d25565b620003c692919062000de5565b604051809103906000f080158015620003e3573d6000803e3d6000fd5b506001600160a01b03858116600090815260076020908152604080832080546001600160a01b031916948616949094179093556008905220849055600a5490915062000430908462000add565b600a5560405163a9059cbb60e01b81526001600160a01b0383169063a9059cbb9062000463908490879060040162000dff565b602060405180830381600087803b1580156200047e57600080fd5b505af115801562000493573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620004b9919062000d96565b50836001600160a01b03167fb0d234274aef7a61aa5a2eb44c23881ebf46a068cccbd413c978bcbd555fe17f84604051620004f59190620010c3565b60405180910390a250505050565b6003546001600160a01b03163314620005305760405162461bcd60e51b81526004016200031f9062000eff565b6006546200053d620006fc565b1115620005815760006200056460065462000557620006fc565b9063ffffffff62000b0e16565b6005549091506200057c908263ffffffff62000add16565b600555505b80620005a15760405162461bcd60e51b81526004016200031f906200107d565b6000620005ad6200060b565b905080821115620005d25760405162461bcd60e51b81526004016200031f9062000e79565b620005de838362000b52565b50620005e9620006fc565b6006555050565b6002546001600160a01b031681565b60015481565b60055481565b6000806200061862000721565b60015460055491925090600090829062000639908563ffffffff62000c2c16565b816200064157fe5b0490506000620006626200065462000845565b839063ffffffff62000b0e16565b94505050505090565b6003546001600160a01b031681565b6004546001600160a01b031681565b620006943362000c6c565b6009546040516317066a5760e21b81526001600160a01b0390911690635c19a95c90620006c690339060040162000dd1565b600060405180830381600087803b158015620006e157600080fd5b505af1158015620006f6573d6000803e3d6000fd5b50505050565b60006200071c600a546200070f62000a56565b9063ffffffff62000add16565b905090565b60006200072d620002e9565b6200073b57506000620002ef565b600154600054420381811162000752578062000754565b815b9250505090565b60005481565b600a5481565b60086020526000908152604090205481565b60006200078562000721565b60015403905090565b60006200079a62000779565b15905090565b6003546001600160a01b03163314620007cd5760405162461bcd60e51b81526004016200031f9062000eff565b600654620007da620006fc565b111562000811576000620007f460065462000557620006fc565b6005549091506200080c908263ffffffff62000add16565b600555505b6200082681620008206200060b565b62000b52565b62000830620006fc565b60065550565b6009546001600160a01b031681565b60006200071c62000855620006fc565b6005549063ffffffff62000b0e16565b6003546001600160a01b03163314620008925760405162461bcd60e51b81526004016200031f9062000eff565b600480546001600160a01b0319166001600160a01b0383169081179091556040517f636f16dafcc1e5b7ae44b2a7fd661757f160672716bb47a02c7d3f5108be49a090600090a250565b6007602052600090815260409020546001600160a01b031681565b6003546000906001600160a01b03163314620009275760405162461bcd60e51b81526004016200031f9062000eff565b6001600160a01b038083166000908152600760205260409020541680620009625760405162461bcd60e51b81526004016200031f9062000f4f565b806001600160a01b0316633ccfd60b6040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156200099e57600080fd5b505af1158015620009b3573d6000803e3d6000fd5b505050506001600160a01b038316600090815260086020526040902054600a54620009df908262000b0e565b600a556001600160a01b038416600081815260076020908152604080832080546001600160a01b0319169055600890915280822091909155517f17659a1d1f57d2e58b7063ee8b518b50d00bf3e5c0d8224b68ba865e4725a0b49062000a47908490620010c3565b60405180910390a29392505050565b6009546040516370a0823160e01b81526000916001600160a01b0316906370a082319062000a8990309060040162000dd1565b60206040518083038186803b15801562000aa257600080fd5b505afa15801562000ab7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200071c919062000db8565b60008282018381101562000b055760405162461bcd60e51b81526004016200031f9062000ec8565b90505b92915050565b600062000b0583836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f77000081525062000cf6565b60025460405163a9059cbb60e01b81526001600160a01b039091169063a9059cbb9062000b86908590859060040162000dff565b602060405180830381600087803b15801562000ba157600080fd5b505af115801562000bb6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000bdc919062000d96565b506003546040516001600160a01b038085169216907fcb54aad3bd772fcfe1bc124e01bd1a91a91c9d80126d8b3014c4d9e687d5ca489062000c20908590620010c3565b60405180910390a35050565b60008262000c3d5750600062000b08565b8282028284828162000c4b57fe5b041462000b055760405162461bcd60e51b81526004016200031f9062000fa1565b6004546001600160a01b0382811691161462000c9c5760405162461bcd60e51b81526004016200031f9062001027565b600380546001600160a01b0319166001600160a01b0383169081179091556040517fe356863d8c81d46ff30d41a6332e1d04d2fb6c0f043fa6554e3d1e1deae95a8a90600090a250600480546001600160a01b0319169055565b6000818484111562000d1d5760405162461bcd60e51b81526004016200031f919062000e23565b505050900390565b61064280620010cd83390190565b80356001600160a01b038116811462000b0857600080fd5b60006020828403121562000d5d578081fd5b62000b05838362000d33565b6000806040838503121562000d7c578081fd5b62000d88848462000d33565b946020939093013593505050565b60006020828403121562000da8578081fd5b8151801515811462000b05578182fd5b60006020828403121562000dca578081fd5b5051919050565b6001600160a01b0391909116815260200190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b03929092168252602082015260400190565b901515815260200190565b6000602080835283518082850152825b8181101562000e515785810183015185820160400152820162000e33565b8181111562000e635783604083870101525b50601f01601f1916929092016040019392505050565b6020808252602f908201527f4c696e656172546f6b656e54696d656c6f636b3a206e6f7420656e6f7567682060408201526e72656c656173656420746f6b656e7360881b606082015260800190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b60208082526030908201527f4c696e656172546f6b656e54696d656c6f636b3a2043616c6c6572206973206e60408201526f6f7420612062656e656669636961727960801b606082015260800190565b60208082526032908201527f54696d656c6f636b656444656c656761746f723a2044656c656761746520636f6040820152711b9d1c9858dd081b9bdb995e1a5cdd195b9d60721b606082015260800190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b60208082526025908201527f54696d656c6f636b656444656c656761746f723a204e6f7420656e6f75676820604082015264547269626560d81b606082015260800190565b60208082526036908201527f4c696e656172546f6b656e54696d656c6f636b3a2043616c6c6572206973206e6040820152756f742070656e64696e672062656e656669636961727960501b606082015260800190565b60208082526026908201527f4c696e656172546f6b656e54696d656c6f636b3a206e6f20616d6f756e742064604082015265195cda5c995960d21b606082015260800190565b9081526020019056fe608060405234801561001057600080fd5b5060405161064238038061064283398101604081905261002f9161010e565b60006100426001600160e01b0361010a16565b600080546001600160a01b0319166001600160a01b0383169081178255604051929350917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a350600180546001600160a01b0319166001600160a01b0383811691909117918290556040516317066a5760e21b8152911690635c19a95c906100d1908590600401610147565b600060405180830381600087803b1580156100eb57600080fd5b505af11580156100ff573d6000803e3d6000fd5b505050505050610173565b3390565b60008060408385031215610120578182fd5b825161012b8161015b565b602084015190925061013c8161015b565b809150509250929050565b6001600160a01b0391909116815260200190565b6001600160a01b038116811461017057600080fd5b50565b6104c0806101826000396000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c80633ccfd60b1461005c578063715018a6146100665780638da5cb5b1461006e578063b86677fe1461008c578063f2fde38b14610094575b600080fd5b6100646100a7565b005b610064610211565b61007661029a565b60405161008391906103e2565b60405180910390f35b6100766102a9565b6100646100a236600461037c565b6102b8565b6100af610378565b6001600160a01b03166100c061029a565b6001600160a01b0316146100ef5760405162461bcd60e51b81526004016100e690610455565b60405180910390fd5b6001546040516370a0823160e01b81526001600160a01b039091169060009082906370a08231906101249030906004016103e2565b60206040518083038186803b15801561013c57600080fd5b505afa158015610150573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061017491906103ca565b9050816001600160a01b031663a9059cbb61018d61029a565b836040518363ffffffff1660e01b81526004016101ab9291906103f6565b602060405180830381600087803b1580156101c557600080fd5b505af11580156101d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101fd91906103aa565b5061020661029a565b6001600160a01b0316ff5b610219610378565b6001600160a01b031661022a61029a565b6001600160a01b0316146102505760405162461bcd60e51b81526004016100e690610455565b600080546040516001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080546001600160a01b0319169055565b6000546001600160a01b031690565b6001546001600160a01b031681565b6102c0610378565b6001600160a01b03166102d161029a565b6001600160a01b0316146102f75760405162461bcd60e51b81526004016100e690610455565b6001600160a01b03811661031d5760405162461bcd60e51b81526004016100e69061040f565b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b3390565b60006020828403121561038d578081fd5b81356001600160a01b03811681146103a3578182fd5b9392505050565b6000602082840312156103bb578081fd5b815180151581146103a3578182fd5b6000602082840312156103db578081fd5b5051919050565b6001600160a01b0391909116815260200190565b6001600160a01b03929092168252602082015260400190565b60208082526026908201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160408201526564647265737360d01b606082015260800190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260408201526060019056fea2646970667358221220386ea63ca2f318b02deda68ffd17822438160431e507fb700f13923eab8f078f64736f6c63430006060033a264697066735822122006f2ef7ff1d6d1333faa5b157baa1f2fe6aba4e80ba5831f4df08ace524cef5164736f6c63430006060033

Verified Source Code Partial Match

Compiler: v0.6.6+commit.6c089d02 EVM: istanbul Optimization: Yes (200 runs)
IFei.sol 56 lines
pragma solidity ^0.6.2;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

/// @title FEI stablecoin interface
/// @author Fei Protocol
interface IFei is IERC20 {
    // ----------- Events -----------

    event Minting(
        address indexed _to,
        address indexed _minter,
        uint256 _amount
    );

    event Burning(
        address indexed _to,
        address indexed _burner,
        uint256 _amount
    );

    event IncentiveContractUpdate(
        address indexed _incentivized,
        address indexed _incentiveContract
    );

    // ----------- State changing api -----------

    function burn(uint256 amount) external;

    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    // ----------- Burner only state changing api -----------

    function burnFrom(address account, uint256 amount) external;

    // ----------- Minter only state changing api -----------

    function mint(address account, uint256 amount) external;

    // ----------- Governor only state changing api -----------

    function setIncentiveContract(address account, address incentive) external;

    // ----------- Getters -----------

    function incentiveContract(address account) external view returns (address);
}
Timed.sol 76 lines
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;

import "@openzeppelin/contracts/utils/SafeCast.sol";

/// @title an abstract contract for timed events
/// @author Fei Protocol
abstract contract Timed {
    using SafeCast for uint256;

    /// @notice the start timestamp of the timed period
    uint256 public startTime;

    /// @notice the duration of the timed period
    uint256 public duration;

    event DurationUpdate(uint256 _duration);

    event TimerReset(uint256 _startTime);

    constructor(uint256 _duration) public {
        _setDuration(_duration);
    }

    modifier duringTime() {
        require(isTimeStarted(), "Timed: time not started");
        require(!isTimeEnded(), "Timed: time ended");
        _;
    }

    modifier afterTime() {
        require(isTimeEnded(), "Timed: time not ended");
        _;
    }

    /// @notice return true if time period has ended
    function isTimeEnded() public view returns (bool) {
        return remainingTime() == 0;
    }

    /// @notice number of seconds remaining until time is up
    /// @return remaining
    function remainingTime() public view returns (uint256) {
        return duration - timeSinceStart(); // duration always >= timeSinceStart which is on [0,d]
    }

    /// @notice number of seconds since contract was initialized
    /// @return timestamp
    /// @dev will be less than or equal to duration
    function timeSinceStart() public view returns (uint256) {
        if (!isTimeStarted()) {
            return 0; // uninitialized
        }
        uint256 _duration = duration;
        // solhint-disable-next-line not-rely-on-time
        uint256 timePassed = block.timestamp - startTime; // block timestamp always >= startTime
        return timePassed > _duration ? _duration : timePassed;
    }

    function isTimeStarted() public view returns (bool) {
        return startTime != 0;
    }

    function _initTimed() internal {
        // solhint-disable-next-line not-rely-on-time
        startTime = block.timestamp;
        
        // solhint-disable-next-line not-rely-on-time
        emit TimerReset(block.timestamp);
    }

    function _setDuration(uint _duration) internal {
        duration = _duration;
        emit DurationUpdate(_duration);
    }
}
SafeMathCopy.sol 159 lines
// SPDX-License-Identifier: MIT

pragma solidity ^0.6.0;

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMathCopy { // To avoid namespace collision between openzeppelin safemath and uniswap safemath
    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");

        return c;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return sub(a, b, "SafeMath: subtraction overflow");
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        uint256 c = a - b;

        return c;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
        if (a == 0) {
            return 0;
        }

        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");

        return c;
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return div(a, b, "SafeMath: division by zero");
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        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;
    }
}
TimelockedDelegator.sol 134 lines
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;

import "@openzeppelin/contracts/access/Ownable.sol";
import "./ITimelockedDelegator.sol";
import "../utils/LinearTokenTimelock.sol";

/// @title a proxy delegate contract for TRIBE
/// @author Fei Protocol
contract Delegatee is Ownable {
    ITribe public tribe;

    /// @notice Delegatee constructor
    /// @param _delegatee the address to delegate TRIBE to
    /// @param _tribe the TRIBE token address
    constructor(address _delegatee, address _tribe) public {
        tribe = ITribe(_tribe);
        tribe.delegate(_delegatee);
    }

    /// @notice send TRIBE back to timelock and selfdestruct
    function withdraw() public onlyOwner {
        ITribe _tribe = tribe;
        uint256 balance = _tribe.balanceOf(address(this));
        _tribe.transfer(owner(), balance);
        selfdestruct(payable(owner()));
    }
}

/// @title a timelock for TRIBE allowing for sub-delegation
/// @author Fei Protocol
/// @notice allows the timelocked TRIBE to be delegated by the beneficiary while locked
contract TimelockedDelegator is ITimelockedDelegator, LinearTokenTimelock {
    /// @notice associated delegate proxy contract for a delegatee
    mapping(address => address) public override delegateContract;

    /// @notice associated delegated amount of TRIBE for a delegatee
    /// @dev Using as source of truth to prevent accounting errors by transferring to Delegate contracts
    mapping(address => uint256) public override delegateAmount;

    /// @notice the TRIBE token contract
    ITribe public override tribe;

    /// @notice the total delegated amount of TRIBE
    uint256 public override totalDelegated;

    /// @notice Delegatee constructor
    /// @param _tribe the TRIBE token address
    /// @param _beneficiary default delegate, admin, and timelock beneficiary
    /// @param _duration duration of the token timelock window
    constructor(
        address _tribe,
        address _beneficiary,
        uint256 _duration
    ) public LinearTokenTimelock(_beneficiary, _duration, _tribe) {
        tribe = ITribe(_tribe);
        tribe.delegate(_beneficiary);
    }

    /// @notice delegate locked TRIBE to a delegatee
    /// @param delegatee the target address to delegate to
    /// @param amount the amount of TRIBE to delegate. Will increment existing delegated TRIBE
    function delegate(address delegatee, uint256 amount)
        public
        override
        onlyBeneficiary
    {
        require(
            amount <= _tribeBalance(),
            "TimelockedDelegator: Not enough Tribe"
        );

        // withdraw and include an existing delegation
        if (delegateContract[delegatee] != address(0)) {
            amount = amount.add(undelegate(delegatee));
        }

        ITribe _tribe = tribe;
        address _delegateContract =
            address(new Delegatee(delegatee, address(_tribe)));
        delegateContract[delegatee] = _delegateContract;

        delegateAmount[delegatee] = amount;
        totalDelegated = totalDelegated.add(amount);

        _tribe.transfer(_delegateContract, amount);

        emit Delegate(delegatee, amount);
    }

    /// @notice return delegated TRIBE to the timelock
    /// @param delegatee the target address to undelegate from
    /// @return the amount of TRIBE returned
    function undelegate(address delegatee)
        public
        override
        onlyBeneficiary
        returns (uint256)
    {
        address _delegateContract = delegateContract[delegatee];
        require(
            _delegateContract != address(0),
            "TimelockedDelegator: Delegate contract nonexistent"
        );

        Delegatee(_delegateContract).withdraw();

        uint256 amount = delegateAmount[delegatee];
        totalDelegated = totalDelegated.sub(amount);

        delegateContract[delegatee] = address(0);
        delegateAmount[delegatee] = 0;

        emit Undelegate(delegatee, amount);

        return amount;
    }

    /// @notice calculate total TRIBE held plus delegated
    /// @dev used by LinearTokenTimelock to determine the released amount
    function totalToken() public view override returns (uint256) {
        return _tribeBalance().add(totalDelegated);
    }

    /// @notice accept beneficiary role over timelocked TRIBE. Delegates all held (non-subdelegated) tribe to beneficiary
    function acceptBeneficiary() public override {
        _setBeneficiary(msg.sender);
        tribe.delegate(msg.sender);
    }

    function _tribeBalance() internal view returns (uint256) {
        return tribe.balanceOf(address(this));
    }
}
ITimelockedDelegator.sol 38 lines
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "../token/IFei.sol";

interface ITribe is IERC20 {
    function delegate(address delegatee) external;
}

/// @title TimelockedDelegator interface
/// @author Fei Protocol
interface ITimelockedDelegator {
    // ----------- Events -----------

    event Delegate(address indexed _delegatee, uint256 _amount);

    event Undelegate(address indexed _delegatee, uint256 _amount);

    // ----------- Beneficiary only state changing api -----------

    function delegate(address delegatee, uint256 amount) external;

    function undelegate(address delegatee) external returns (uint256);

    // ----------- Getters -----------

    function delegateContract(address delegatee)
        external
        view
        returns (address);

    function delegateAmount(address delegatee) external view returns (uint256);

    function totalDelegated() external view returns (uint256);

    function tribe() external view returns (ITribe);
}
LinearTokenTimelock.sol 130 lines
pragma solidity ^0.6.0;

// Inspired by OpenZeppelin TokenTimelock contract
// Reference: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/TokenTimelock.sol

import "./Timed.sol";
import "./ILinearTokenTimelock.sol";
import "../external/SafeMathCopy.sol";

contract LinearTokenTimelock is ILinearTokenTimelock, Timed {
    using SafeMathCopy for uint256;

    /// @notice ERC20 basic token contract being held in timelock
    IERC20 public override lockedToken;

    /// @notice beneficiary of tokens after they are released
    address public override beneficiary;

    /// @notice pending beneficiary appointed by current beneficiary
    address public override pendingBeneficiary;

    /// @notice initial balance of lockedToken
    uint256 public override initialBalance;

    uint256 internal lastBalance;

    constructor(
        address _beneficiary,
        uint256 _duration,
        address _lockedToken
    ) public Timed(_duration) {
        require(_duration != 0, "LinearTokenTimelock: duration is 0");
        require(
            _beneficiary != address(0),
            "LinearTokenTimelock: Beneficiary must not be 0 address"
        );

        beneficiary = _beneficiary;
        _initTimed();

        _setLockedToken(_lockedToken);
    }

    // Prevents incoming LP tokens from messing up calculations
    modifier balanceCheck() {
        if (totalToken() > lastBalance) {
            uint256 delta = totalToken().sub(lastBalance);
            initialBalance = initialBalance.add(delta);
        }
        _;
        lastBalance = totalToken();
    }

    modifier onlyBeneficiary() {
        require(
            msg.sender == beneficiary,
            "LinearTokenTimelock: Caller is not a beneficiary"
        );
        _;
    }

    /// @notice releases `amount` unlocked tokens to address `to`
    function release(address to, uint256 amount) external override onlyBeneficiary balanceCheck {
        require(amount != 0, "LinearTokenTimelock: no amount desired");

        uint256 available = availableForRelease();
        require(amount <= available, "LinearTokenTimelock: not enough released tokens");

        _release(to, amount);
    }

    /// @notice releases maximum unlocked tokens to address `to`
    function releaseMax(address to) external override onlyBeneficiary balanceCheck {
        _release(to, availableForRelease());
    }

    /// @notice the total amount of tokens held by timelock
    function totalToken() public view override virtual returns (uint256) {
        return lockedToken.balanceOf(address(this));
    }

    /// @notice amount of tokens released to beneficiary
    function alreadyReleasedAmount() public view override returns (uint256) {
        return initialBalance.sub(totalToken());
    }

    /// @notice amount of held tokens unlocked and available for release
    function availableForRelease() public view override returns (uint256) {
        uint256 elapsed = timeSinceStart();
        uint256 _duration = duration;

        uint256 totalAvailable = initialBalance.mul(elapsed) / _duration;
        uint256 netAvailable = totalAvailable.sub(alreadyReleasedAmount());
        return netAvailable;
    }

    /// @notice current beneficiary can appoint new beneficiary, which must be accepted
    function setPendingBeneficiary(address _pendingBeneficiary)
        public
        override
        onlyBeneficiary
    {
        pendingBeneficiary = _pendingBeneficiary;
        emit PendingBeneficiaryUpdate(_pendingBeneficiary);
    }

    /// @notice pending beneficiary accepts new beneficiary
    function acceptBeneficiary() public override virtual {
        _setBeneficiary(msg.sender);
    }

    function _setBeneficiary(address newBeneficiary) internal {
        require(
            newBeneficiary == pendingBeneficiary,
            "LinearTokenTimelock: Caller is not pending beneficiary"
        );
        beneficiary = newBeneficiary;
        emit BeneficiaryUpdate(newBeneficiary);
        pendingBeneficiary = address(0);
    }

    function _setLockedToken(address tokenAddress) internal {
        lockedToken = IERC20(tokenAddress);
    }

    function _release(address to, uint256 amount) internal {
        lockedToken.transfer(to, amount);
        emit Release(beneficiary, to, amount);
    }
}
Context.sol 24 lines
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

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

    function _msgData() internal view virtual returns (bytes memory) {
        this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
        return msg.data;
    }
}
ILinearTokenTimelock.sol 40 lines
pragma solidity ^0.6.2;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

/// @title LinearTokenTimelock interface
/// @author Fei Protocol
interface ILinearTokenTimelock {
    // ----------- Events -----------

    event Release(address indexed _beneficiary, address indexed _recipient, uint256 _amount);
    event BeneficiaryUpdate(address indexed _beneficiary);
    event PendingBeneficiaryUpdate(address indexed _pendingBeneficiary);

    // ----------- State changing api -----------

    function release(address to, uint amount) external;

    function releaseMax(address to) external;

    function setPendingBeneficiary(address _pendingBeneficiary) external;

    function acceptBeneficiary() external;


    // ----------- Getters -----------

    function lockedToken() external view returns (IERC20);

    function beneficiary() external view returns (address);

    function pendingBeneficiary() external view returns (address);

    function initialBalance() external view returns (uint256);

    function availableForRelease() external view returns (uint256);

    function totalToken() external view returns(uint256);

    function alreadyReleasedAmount() external view returns (uint256);
}
Ownable.sol 68 lines
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

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

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

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor () internal {
        address msgSender = _msgSender();
        _owner = msgSender;
        emit OwnershipTransferred(address(0), msgSender);
    }

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

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

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        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 virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        emit OwnershipTransferred(_owner, newOwner);
        _owner = newOwner;
    }
}
SafeCast.sol 211 lines
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;


/**
 * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
 * checks.
 *
 * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
 * easily result in undesired exploitation or bugs, since developers usually
 * assume that overflows raise errors. `SafeCast` restores this intuition by
 * reverting the transaction when such 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.
 *
 * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing
 * all math on `uint256` and `int256` and then downcasting.
 */
library SafeCast {

    /**
     * @dev Returns the downcasted uint128 from uint256, reverting on
     * overflow (when the input is greater than largest uint128).
     *
     * Counterpart to Solidity's `uint128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     */
    function toUint128(uint256 value) internal pure returns (uint128) {
        require(value < 2**128, "SafeCast: value doesn\'t fit in 128 bits");
        return uint128(value);
    }

    /**
     * @dev Returns the downcasted uint64 from uint256, reverting on
     * overflow (when the input is greater than largest uint64).
     *
     * Counterpart to Solidity's `uint64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     */
    function toUint64(uint256 value) internal pure returns (uint64) {
        require(value < 2**64, "SafeCast: value doesn\'t fit in 64 bits");
        return uint64(value);
    }

    /**
     * @dev Returns the downcasted uint32 from uint256, reverting on
     * overflow (when the input is greater than largest uint32).
     *
     * Counterpart to Solidity's `uint32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     */
    function toUint32(uint256 value) internal pure returns (uint32) {
        require(value < 2**32, "SafeCast: value doesn\'t fit in 32 bits");
        return uint32(value);
    }

    /**
     * @dev Returns the downcasted uint16 from uint256, reverting on
     * overflow (when the input is greater than largest uint16).
     *
     * Counterpart to Solidity's `uint16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     */
    function toUint16(uint256 value) internal pure returns (uint16) {
        require(value < 2**16, "SafeCast: value doesn\'t fit in 16 bits");
        return uint16(value);
    }

    /**
     * @dev Returns the downcasted uint8 from uint256, reverting on
     * overflow (when the input is greater than largest uint8).
     *
     * Counterpart to Solidity's `uint8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits.
     */
    function toUint8(uint256 value) internal pure returns (uint8) {
        require(value < 2**8, "SafeCast: value doesn\'t fit in 8 bits");
        return uint8(value);
    }

    /**
     * @dev Converts a signed int256 into an unsigned uint256.
     *
     * Requirements:
     *
     * - input must be greater than or equal to 0.
     */
    function toUint256(int256 value) internal pure returns (uint256) {
        require(value >= 0, "SafeCast: value must be positive");
        return uint256(value);
    }

    /**
     * @dev Returns the downcasted int128 from int256, reverting on
     * overflow (when the input is less than smallest int128 or
     * greater than largest int128).
     *
     * Counterpart to Solidity's `int128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     *
     * _Available since v3.1._
     */
    function toInt128(int256 value) internal pure returns (int128) {
        require(value >= -2**127 && value < 2**127, "SafeCast: value doesn\'t fit in 128 bits");
        return int128(value);
    }

    /**
     * @dev Returns the downcasted int64 from int256, reverting on
     * overflow (when the input is less than smallest int64 or
     * greater than largest int64).
     *
     * Counterpart to Solidity's `int64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     *
     * _Available since v3.1._
     */
    function toInt64(int256 value) internal pure returns (int64) {
        require(value >= -2**63 && value < 2**63, "SafeCast: value doesn\'t fit in 64 bits");
        return int64(value);
    }

    /**
     * @dev Returns the downcasted int32 from int256, reverting on
     * overflow (when the input is less than smallest int32 or
     * greater than largest int32).
     *
     * Counterpart to Solidity's `int32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     *
     * _Available since v3.1._
     */
    function toInt32(int256 value) internal pure returns (int32) {
        require(value >= -2**31 && value < 2**31, "SafeCast: value doesn\'t fit in 32 bits");
        return int32(value);
    }

    /**
     * @dev Returns the downcasted int16 from int256, reverting on
     * overflow (when the input is less than smallest int16 or
     * greater than largest int16).
     *
     * Counterpart to Solidity's `int16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     *
     * _Available since v3.1._
     */
    function toInt16(int256 value) internal pure returns (int16) {
        require(value >= -2**15 && value < 2**15, "SafeCast: value doesn\'t fit in 16 bits");
        return int16(value);
    }

    /**
     * @dev Returns the downcasted int8 from int256, reverting on
     * overflow (when the input is less than smallest int8 or
     * greater than largest int8).
     *
     * Counterpart to Solidity's `int8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits.
     *
     * _Available since v3.1._
     */
    function toInt8(int256 value) internal pure returns (int8) {
        require(value >= -2**7 && value < 2**7, "SafeCast: value doesn\'t fit in 8 bits");
        return int8(value);
    }

    /**
     * @dev Converts an unsigned uint256 into a signed int256.
     *
     * Requirements:
     *
     * - input must be less than or equal to maxInt256.
     */
    function toInt256(uint256 value) internal pure returns (int256) {
        require(value < 2**255, "SafeCast: value doesn't fit in an int256");
        return int256(value);
    }
}
IERC20.sol 77 lines
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

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

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

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

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

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

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

    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

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

Read Contract

alreadyReleasedAmount 0xb888c479 → uint256
availableForRelease 0x28b5030b → uint256
beneficiary 0x38af3eed → address
delegateAmount 0x9e88d77e → uint256
delegateContract 0xcf4f3630 → address
duration 0x0fb5a6b4 → uint256
initialBalance 0x18369a2a → uint256
isTimeEnded 0xae951b2e → bool
isTimeStarted 0x00d89b33 → bool
lockedToken 0x0f45cc81 → address
pendingBeneficiary 0x427db380 → address
remainingTime 0xacc4bd08 → uint256
startTime 0x78e97925 → uint256
timeSinceStart 0x67fc6dea → uint256
totalDelegated 0x80d04de8 → uint256
totalToken 0x626be567 → uint256
tribe 0xb86677fe → address

Write Contract 6 functions

These functions modify contract state and require a wallet transaction to execute.

acceptBeneficiary 0x4929e162
No parameters
delegate 0x026e402b
address delegatee
uint256 amount
release 0x0357371d
address to
uint256 amount
releaseMax 0xb38c43e3
address to
setPendingBeneficiary 0xc5fa55a5
address _pendingBeneficiary
undelegate 0xda8be864
address delegatee
returns: uint256

Recent Transactions

No transactions found for this address