Cryo Explorer Ethereum Mainnet

Address Contract Partially Verified

Address 0xe8E06a5613dC86D459bC8Fb989e173bB8b256072
Balance 0 ETH
Nonce 1
Code Size 8156 bytes
Indexed Transactions 0
External Etherscan · Sourcify

Contract Bytecode

8156 bytes
0x608060405234801561001057600080fd5b506004361061023d5760003560e01c806355b6ed5c1161013b578063a9059cbb116100b8578063d6565a2d1161007c578063d6565a2d146106eb578063dd62ed3e14610708578063e498484c14610736578063f67e675614610753578063f7d623bb146107705761023d565b8063a9059cbb1461066c578063bbe4fd5014610698578063bd5bf4ce146106a0578063c3124525146106db578063d2e6bcfa146106e35761023d565b80638da5cb5b116100ff5780638da5cb5b146105d25780638f2dbc21146105f657806395d89b411461061b57806399d0cfa114610623578063a6f9dae1146106465761023d565b806355b6ed5c1461055157806358ff4ddd1461057f578063613fc9fd1461059c57806361a52a36146105a457806370a08231146105ac5761023d565b806323b872dd116101c9578063313ce5671161018d578063313ce5671461045957806331eb3f37146104615780633a6088db146104bb57806342966c68146104d85780634c86259e146104f55761023d565b806323b872dd146103ad57806325c01505146103e357806326986d3f1461040257806327e235e31461040a578063291ab43b146104305761023d565b80630eb1bc08116102105780630eb1bc081461032157806317f4cb8b1461032957806318160ddd146103465780631c89edc71461034e5780631df5b4d2146103845761023d565b8063022466b51461024257806306fdde031461025c57806308dbbb03146102d9578063095ea7b3146102e1575b600080fd5b61024a61078d565b60408051918252519081900360200190f35b6102646107b1565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561029e578181015183820152602001610286565b50505050905090810190601f1680156102cb5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61024a61083e565b61030d600480360360408110156102f757600080fd5b506001600160a01b03813516906020013561084b565b604080519115158252519081900360200190f35b61024a6108b2565b61024a6004803603602081101561033f57600080fd5b50356108b8565b61024a61099c565b61036b6004803603602081101561036457600080fd5b50356109a2565b6040805192835260208301919091528051918290030190f35b61024a6004803603606081101561039a57600080fd5b5080359060208101359060400135610a0d565b61030d600480360360608110156103c357600080fd5b506001600160a01b03813581169160208101359091169060400135610a6f565b610400600480360360208110156103f957600080fd5b5035610c2e565b005b61024a610d69565b61024a6004803603602081101561042057600080fd5b50356001600160a01b0316610d6f565b61024a6004803603606081101561044657600080fd5b5080359060208101359060400135610d81565b61024a610dad565b61047e6004803603602081101561047757600080fd5b5035610db3565b604080519687526001600160a01b0390951660208701528585019390935260608501919091526080840152151560a0830152519081900360c00190f35b61024a600480360360208110156104d157600080fd5b5035610e26565b61030d600480360360208110156104ee57600080fd5b5035610f2e565b6105126004803603602081101561050b57600080fd5b5035611063565b604080516001600160a01b03909716875260208701959095528585019390935260608501919091526080840152151560a0830152519081900360c00190f35b61024a6004803603604081101561056757600080fd5b506001600160a01b03813581169160200135166110a5565b61024a6004803603602081101561059557600080fd5b50356110c2565b61040061115d565b61024a61116f565b61024a600480360360208110156105c257600080fd5b50356001600160a01b0316611176565b6105da611191565b604080516001600160a01b039092168252519081900360200190f35b6105fe6111a0565b6040805167ffffffffffffffff9092168252519081900360200190f35b6102646111e5565b61024a6004803603604081101561063957600080fd5b508035906020013561123d565b61030d6004803603602081101561065c57600080fd5b50356001600160a01b031661124f565b61030d6004803603604081101561068257600080fd5b506001600160a01b038135169060200135611341565b61024a611433565b6106bd600480360360208110156106b657600080fd5b5035611437565b60408051938452602084019290925282820152519081900360600190f35b6106bd61145e565b61036b61146a565b61036b6004803603602081101561070157600080fd5b5035611491565b61024a6004803603604081101561071e57600080fd5b506001600160a01b03813581169160200135166114aa565b61024a6004803603602081101561074c57600080fd5b50356114d5565b61036b6004803603602081101561076957600080fd5b5035611503565b61030d6004803603602081101561078657600080fd5b50356115ba565b7f000000000000000000000000000000000000000000000000000000005ff9379681565b60018054604080516020600284861615610100026000190190941693909304601f810184900484028201840190925281815292918301828280156108365780601f1061080b57610100808354040283529160200191610836565b820191906000526020600020905b81548152906001019060200180831161081957829003601f168201915b505050505081565b68056bc75e2d6310000081565b3360008181526006602090815260408083206001600160a01b038716808552908352818420869055815186815291519394909390927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925928290030190a35060015b92915050565b61019a81565b6000818152600860209081526040808320815160c08101835281546001600160a01b031681526001820154938101939093526002810154918301919091526003810154606083015260048101546080830181905260059091015460ff16151560a0830152829061093f90620151809061093990610933611433565b906117de565b9061183b565b9050600f8110156109615761095a82602001516102ee61123d565b9250610995565b601e81101561097a5761095a82602001516101f461123d565b602d81101561099557610992826020015160fa61123d565b92505b5050919050565b60045481565b6000818152600760209081526040808320815180830190925280548083526001909101549282019290925282916109e5576109db61146a565b9250925050610a08565b6109f9816020015182600001516004610d81565b9250610a04836114d5565b9150505b915091565b600080610a1e846004546004610d81565b90506000610a2b826114d5565b90506000610a3e606461093989856118a5565b90506000610a52826301e185586000610d81565b9050610a63606461093983896118a5565b98975050505050505050565b6000610a7e84848460006118fe565b610acf576040805162461bcd60e51b815260206004820152601c60248201527f546f6b656e3a205f7472616e73666572436865636b206661696c656400000000604482015290519081900360640190fd5b6001600160a01b0384166000908152600660209081526040808320338452909152902054821115610b47576040805162461bcd60e51b815260206004820152601a60248201527f546f6b656e3a20657863656564696e6720616c6c6f77616e6365000000000000604482015290519081900360640190fd5b6001600160a01b0384166000908152600660209081526040808320338452909152902054610b7590836117de565b6001600160a01b038516600081815260066020908152604080832033845282528083209490945591815260059091522054610bb090836117de565b6001600160a01b038086166000908152600560205260408082209390935590851681522054610bdf9083611a38565b6001600160a01b038085166000818152600560209081526040918290209490945580518681529051919392881692600080516020611f6283398151915292918290030190a35060019392505050565b6000546001600160a01b03163314610c8a576040805162461bcd60e51b815260206004820152601a60248201527927bbb730b136329d1036bab9ba103132903a34329037bbb732b960311b604482015290519081900360640190fd5b600080610c9683611503565b9150915061072182148015610cad57506201518081145b610cfe576040805162461bcd60e51b815260206004820152601860248201527f464559546f6b656e3a206e6f74206f6c6420656e6f7567680000000000000000604482015290519081900360640190fd5b600083815260086020526040902054610d20906001600160a01b031684611a92565b5050604080518481526020810184905280820186905290517f9fb5c0857986c4f071d2fdb4e3d5e9a116bb3be34ecc8a4ca1abe6a886d098d292509081900360600190a1505050565b61072181565b60056020526000908152604090205481565b600060018201600a90810a850290848281610d9857fe5b0460050181610da357fe5b0495945050505050565b60035481565b600090815260086020908152604091829020825160c08101845281546001600160a01b03168082526001830154938201849052600283015494820185905260038301546060830181905260048401546080840181905260059094015460ff16151560a09093018390529395909493929190565b6000818152600860209081526040808320815160c08101835281546001600160a01b0316815260018201549381019390935260028101549183019190915260038101546060830152600481015460808301526005015460ff16151560a08201819052610e985780606001519150610f28565b600080610ea485611503565b915091506000610eb2611db8565b67ffffffffffffffff1690506000610eca82856117de565b9050805b82811015610f0a57610efe8660200151600760008481526020019081526020016000206001015462015180610a0d565b90960195600101610ece565b50610f1f856020015160096002015485610a0d565b86019550505050505b50919050565b600080546001600160a01b03163314610f8b576040805162461bcd60e51b815260206004820152601a60248201527927bbb730b136329d1036bab9ba103132903a34329037bbb732b960311b604482015290519081900360640190fd5b33600090815260056020526040812054610fa590846117de565b1015610ff8576040805162461bcd60e51b815260206004820152601b60248201527f464559546f6b656e3a20657863656564696e672062616c616e63650000000000604482015290519081900360640190fd5b60045461100590836117de565b6004553360009081526005602052604090205461102290836117de565b33600081815260056020908152604080832094909455835186815293519193600080516020611f62833981519152929081900390910190a35060015b919050565b6008602052600090815260409020805460018201546002830154600384015460048501546005909501546001600160a01b039094169492939192909160ff1686565b600660209081526000928352604080842090915290825290205481565b6000818152600860209081526040808320815160c08101835281546001600160a01b0316815260018201549381019390935260028101549183019190915260038101546060830152600481015460808301526005015460ff16151560a082018190526111335760400151905061105e565b61115661113f846108b8565b61093361114b86610e26565b602085015190611a38565b9392505050565b61116d611168611db8565b611dca565b565b6201518081565b6001600160a01b031660009081526005602052604090205490565b6000546001600160a01b031681565b60007f000000000000000000000000000000000000000000000000000000005ff937966111cb611433565b10156111d85760006111e0565b6111e0611db8565b905090565b6002805460408051602060018416156101000260001901909316849004601f810184900484028201840190925281815292918301828280156108365780601f1061080b57610100808354040283529160200191610836565b600061115661271061093985856118a5565b600080546001600160a01b031633146112ac576040805162461bcd60e51b815260206004820152601a60248201527927bbb730b136329d1036bab9ba103132903a34329037bbb732b960311b604482015290519081900360640190fd5b6001600160a01b0382166112f15760405162461bcd60e51b8152600401808060200182810382526034815260200180611f2e6034913960400191505060405180910390fd5b600080546001600160a01b0319166001600160a01b0384169081178255604051909133917f5d92051b4a9b6e7154c5be37e18edd17bfd2e650a3a6dbf8c3eded0ef431ff0e9190a3506001919050565b600061135033848460006118fe565b6113a1576040805162461bcd60e51b815260206004820152601c60248201527f546f6b656e3a205f7472616e73666572436865636b206661696c656400000000604482015290519081900360640190fd5b336000908152600560205260409020546113bb90836117de565b33600090815260056020526040808220929092556001600160a01b038516815220546113e79083611a38565b6001600160a01b038416600081815260056020908152604091829020939093558051858152905191923392600080516020611f628339815191529281900390910190a350600192915050565b4290565b6000806000611447611168611db8565b6114513385611a92565b9250925092509193909250565b600954600a54600b5483565b6000806114806009600201546004546004610d81565b915061148b826114d5565b90509091565b6007602052600090815260409020805460019091015482565b6001600160a01b03918216600090815260066020908152604080832093909416825291909152205490565b6000606482116114f1576114ec61019a60646118a5565b6108ac565b6108ac8261093961019a6127106118a5565b6000818152600860209081526040808320815160c08101835281546001600160a01b031681526001820154938101939093526002810154918301919091526003810154606083015260048101546080830181905260059091015460ff16151560a0830152829190829061157890610933611433565b9050611587816201518061183b565b93506107218411156115a35761072193506201518092506115b3565b6115b08162015180611e7b565b92505b5050915091565b60006115ca3360008460016118fe565b61161b576040805162461bcd60e51b815260206004820152601f60248201527f464559546f6b656e3a205f7472616e73666572436865636b206661696c656400604482015290519081900360640190fd5b68056bc75e2d63100000821015611679576040805162461bcd60e51b815260206004820152601d60248201527f464559546f6b656e3a207374616b652062656c6f77206d696e696d756d000000604482015290519081900360640190fd5b3360009081526005602052604090205461169390836117de565b33600081815260056020908152604080832094909455835160c08101855292835282018590529181018290526060810191909152608081016116d3611433565b815260016020918201819052600954600090815260088352604090819020845181546001600160a01b0319166001600160a01b0390911617815592840151918301919091558201516002820155606082015160038201556080820151600482015560a0909101516005909101805460ff1916911515919091179055600b5461175b9083611a38565b600b55600954604080513381526020810185905281517f32705d413ffd76af5104215480a9b5784ae0349bc7fd042427e7f186d3bee6a2929181900390910190a26040805183815290516000913391600080516020611f628339815191529181900360200190a35060016117d0611168611db8565b600980546001019055919050565b600082821115611835576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b6000808211611891576040805162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b600082848161189c57fe5b04949350505050565b6000826118b4575060006108ac565b828202828482816118c157fe5b04146111565760405162461bcd60e51b8152600401808060200182810382526021815260200180611f0d6021913960400191505060405180910390fd5b60008161194a576001600160a01b03841661194a5760405162461bcd60e51b8152600401808060200182810382526025815260200180611f826025913960400191505060405180910390fd5b6001600160a01b0385166000908152600560205260409020548311156119b7576040805162461bcd60e51b815260206004820152601b60248201527f464559546f6b656e3a20657863656564696e672062616c616e63650000000000604482015290519081900360640190fd5b6001600160a01b0384166000908152600560205260409020546119da8185611a38565b1015611a2d576040805162461bcd60e51b815260206004820152601b60248201527f464559546f6b656e3a206f766572666c6f772064657465637465640000000000604482015290519081900360640190fd5b506001949350505050565b600082820183811015611156576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b6000818152600860209081526040808320815160c08101835281546001600160a01b031681526001820154938101939093526002810154918301919091526003810154606083015260048101546080830181905260059091015460ff16151560a0830152829182918290611b1190620151809061093990610933611433565b90506003811015611b69576040805162461bcd60e51b815260206004820152601860248201527f464559546f6b656e3a20696d6d6174757265207374616b650000000000000000604482015290519081900360640190fd5b866001600160a01b031682600001516001600160a01b031614611bd3576040805162461bcd60e51b815260206004820152601b60248201527f464559546f6b656e3a2077726f6e67207374616b65206f776e65720000000000604482015290519081900360640190fd5b8160a00151611c29576040805162461bcd60e51b815260206004820152601a60248201527f464559546f6b656e3a207374616b65206e6f7420616374697665000000000000604482015290519081900360640190fd5b600060a083015260208201519450602d8110611c4b57611c4886610e26565b92505b611c54866108b8565b9350611c6f8461093385600454611a3890919063ffffffff16565b60045560608201839052611c87846109338786611a38565b6040838101918252600088815260086020908152828220865181546001600160a01b0319166001600160a01b03918216178255828801516001830155945160028201819055606088015160038301556080880151600483015560a08801516005928301805460ff1916911515919091179055948c16835290522054611d0b91611a38565b6001600160a01b038816600090815260056020526040902055600b54611d3190866117de565b600b5560408083015181516001600160a01b038a1681526020810191909152815188927f1400fbd2ee4a2075080df3e8fe9550cae0dab5bd1d037452a12390141e45563d928290030190a2604080830151815190815290516001600160a01b03891691600091600080516020611f628339815191529181900360200190a350509250925092565b60006111e0611dc5611433565b611ee0565b600a545b8167ffffffffffffffff16811015611e2857600081815260076020818152604080842081518083019092526004548252600b5482840190815294869052929091525181559051600191820155600a80548201905501611dce565b50600454600b5460408051928352602083019190915267ffffffffffffffff831682820152517f94a13e9f9a91f7369c805b3cd3ffa4ae084c462ce95a364deeb1db54b4672f879181900360600190a150565b600081611ecf576040805162461bcd60e51b815260206004820152601860248201527f536166654d6174683a206d6f64756c6f206279207a65726f0000000000000000604482015290519081900360640190fd5b818381611ed857fe5b069392505050565b620151807f000000000000000000000000000000000000000000000000000000005ff93796909103049056fe536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f774f776e61626c653a206e6577206f776e6572206d757374206e6f742062652074686520626c61636b686f6c652061646472657373ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef464559546f6b656e3a2063616e6e6f742073656e6420746f206275726e2061646472657373a2646970667358221220c1917cf1139d22cdade3da4c9bb704080c483bc9a0e2340e761658bcd06d5bc864736f6c63430007060033

Verified Source Code Partial Match

Compiler: v0.7.6+commit.7338295f EVM: istanbul Optimization: Yes (200 runs)
Declaration.sol 57 lines
// SPDX-License-Identifier: -- ? --

pragma solidity ^0.7.3;

abstract contract Declaration  {

    string public name = "Feyorra";
    string public symbol = "FEY";

    uint256 public decimals = 18;
    uint256 public totalSupply = 1000000000E18;

    uint256 public constant YEARLY_INTEREST = 410;
    uint256 public constant MINIMUM_STAKE = 100E18;
    uint256 public constant SECONDS_IN_DAY = 86400;
    uint256 public constant MAX_STAKE_DAYS = 1825;

    uint256 public immutable LAUNCH_TIME;

    struct Globals {
        uint256 stakingId;
        uint256 currentFeyDay;
        uint256 totalStakedAmount;
    }

    struct StakeElement {
        address userAddress;
        uint256 stakedAmount;
        uint256 returnAmount;
        uint256 interestAmount;
        uint256 stakedAt;
        bool isActive;
    }

    struct SnapShot {
        uint256 totalSupply;
        uint256 totalStakedAmount;
    }

    mapping(address => uint256) public balances;
    mapping(address => mapping(address => uint256)) public allowances;

    mapping(uint256 => SnapShot) public snapshots;
    mapping(uint256 => StakeElement) public stakeList;

    Globals public globals;

    modifier incrementId() {
        _;
        globals.stakingId++;
    }

    constructor() {
        LAUNCH_TIME = block.timestamp;
        balances[msg.sender] = totalSupply;
    }
}
Events.sol 42 lines
// SPDX-License-Identifier: -- ? --

pragma solidity ^0.7.3;

abstract contract Events  {

    event StakeStart(
        uint256 indexed _stakingId,
        address _address,
        uint256 _amount
    );

    event StakeEnd(
        uint256 indexed _stakingId,
        address _address,
        uint256 _amount
    );

    event Transfer(
        address indexed _from,
        address indexed _to,
        uint256 _value
    );

    event Approval(
        address indexed _owner,
        address indexed _spender,
        uint256 _value
    );

    event ClosedGhostStake(
        uint256 daysOld,
        uint256 secondsOld,
        uint256 stakeId
    );

    event SnapshotCaptured(
        uint256 _totalSupply,
        uint256 _totalStakedAmount,
        uint64 _snapshotDay
    );
}
FEYToken.sol 523 lines
// SPDX-License-Identifier: -- ? --

import './Token.sol';

pragma solidity ^0.7.3;

contract FEYToken is Token {

    using SafeMath for uint256;

    /**
        * @notice returns the interest rate by getting the global variable
        * YEARLY_INTEREST and subtracting the percentage passed.
        * Lowers the default interest rate as amount staked rises towards the totalSupply.
        * Used to record the rates for snapshots + to calculate stake interest
        * @param _percentage any uint256 figure
        * @return interestRate
     */
    function getInterestRateYearly(
        uint256 _percentage
    )
        public
        pure
        returns (uint256 interestRate)
    {
        return _percentage > 100
            ? uint256(YEARLY_INTEREST).mul(uint256(10000)).div(_percentage)
            : YEARLY_INTEREST.mul(100);
    }
    
    /**
        * @notice a no args function used to get current APY
        * @dev _precision in getPercent is fixed to 4
        * @return percentage -- totalStaked on a particular day out of totalSupply
        * @return interestRateYearly -- APY based on relative size of current total stakes
     */
    function getYearlyInterestLatest()
        public
        view
        returns (
            uint256 percentage,
            uint256 interestRateYearly
        )
    {
        percentage = getPercent(
            globals.totalStakedAmount,
            totalSupply,
            4
        );

        interestRateYearly = getInterestRateYearly(
            percentage
        );
    }

    /**
        * @notice function used to get APY of a specific day
        * @param _day integer for the target day, starting @ 0
        * @dev _precision in getPercent is fixed to 4
        * @return percentage -- totalStaked on a particular day out of totalSupply
        * @return interestRateYearly -- APY based on relative size of stake
     */
    function getYearlyInterestHistorical(
        uint256 _day
    )
        public
        view
        returns (
            uint256 percentage,
            uint256 interestRateYearly
        )
    {
        SnapShot memory s = snapshots[_day];

        if (s.totalSupply == 0) {
            return getYearlyInterestLatest();
        }

        percentage = getPercent(
            s.totalStakedAmount,
            s.totalSupply,
            4
        );

        interestRateYearly = getInterestRateYearly(
            percentage
        );
    }

    /**
        * @notice calculates amount of interest earned per second
        * @param _stakedAmount principal amount
        * @param _totalStakedAmount summation of principal amount staked by everyone
        * @param _seconds time spent earning interest on a particular day
        * _seconds will be passed as the full SECONDS_IN_DAY for full days that we staked
        * _seconds will be the seconds that have passed by the time getInterest is called on the last day
        * @dev _precision in getPercent is fixed to 4
        * @return durationInterestAmt -- totalStaked on a particular day out of totalSupply
     */
    function getInterest(
        uint256 _stakedAmount,
        uint256 _totalStakedAmount,
        uint256 _seconds
    )
        public
        view
        returns (uint256 durationInterestAmt)
    {
        uint256 percentage = getPercent(
            _totalStakedAmount,
            totalSupply,
            4
        );

        uint256 interestRateYearly = getInterestRateYearly(
            percentage
        );

        uint256 yearFullAmount = _stakedAmount
            .mul(interestRateYearly)
            .div(100);

        uint256 dailyInterestAmt = getPercent(
            yearFullAmount,
            31556952,
            0
        );

        durationInterestAmt = dailyInterestAmt
            .mul(_seconds)
            .div(100);
    }

    /**
         * @notice admin function to close a matured stake OBO the staker
         * @param _stakingId ID of the stake, used as the Key from the stakeList mapping
         * @dev can only close after all of the seconds of the last day have passed
      */
    function closeGhostStake(
        uint256 _stakingId
    )
        external
        onlyOwner
    {
        (uint256 daysOld, uint256 secondsOld) =

        getStakeAge(
            _stakingId
        );

        require(
            daysOld == MAX_STAKE_DAYS &&
            secondsOld == SECONDS_IN_DAY,
            'FEYToken: not old enough'
        );

        _closeStake(
            stakeList[_stakingId].userAddress,
            _stakingId
        );

        emit ClosedGhostStake(
            daysOld,
            secondsOld,
            _stakingId
        );
    }

    /**
        * @notice calculates number of days and remaining seconds on current day that a stake is open
        * @param _stakingId ID of the stake, used as the Key from the stakeList mapping
        * @return daysTotal -- number of complete days that the stake has been open
        * @return secondsToday -- number of seconds the stake has been open on the current day
     */
    function getStakeAge(
        uint256 _stakingId
    )
        public
        view
        returns (
            uint256 daysTotal,
            uint256 secondsToday
        )
    {
        StakeElement memory _stakeElement = stakeList[_stakingId];

        uint256 secondsTotal = getNow()
            .sub(_stakeElement.stakedAt);

        daysTotal = secondsTotal
            .div(SECONDS_IN_DAY);

        if (daysTotal > MAX_STAKE_DAYS) {

            daysTotal = MAX_STAKE_DAYS;
            secondsToday = SECONDS_IN_DAY;

        } else {
            secondsToday = secondsTotal
                .mod(SECONDS_IN_DAY);
        }
    }

    /**
        * @notice calculates amount of interest due to be credited to the staker based on:
        * number of days and remaining seconds on current day that a stake is open
        * @param _stakingId ID of the stake, used as the Key from the stakeList mapping
        * @return stakeInterest -- total interest per second the stake was open on each day
     */
    function getStakeInterest(
        uint256 _stakingId
    )
        public
        view
        returns (
            uint256 stakeInterest
        )
    {
        StakeElement memory _stakeElement = stakeList[_stakingId];

        if (_stakeElement.isActive == false) {

            stakeInterest = _stakeElement.interestAmount;

        } else {

            (
                uint256 daysTotal,
                uint256 secondsToday
            ) = getStakeAge(_stakingId);

            uint256 finalDay = _currentFeyDay();
            uint256 startDay = finalDay.sub(daysTotal);

            for (uint256 _day = startDay; _day < finalDay; _day++) {
                stakeInterest += getInterest(
                    _stakeElement.stakedAmount,
                    snapshots[_day].totalStakedAmount,
                    SECONDS_IN_DAY
                );
            }

            stakeInterest += getInterest(
                _stakeElement.stakedAmount,
                globals.totalStakedAmount,
                secondsToday
            );
        }
    }

    /**
        * @notice penalties are taken if you close a stake before the completion of the 4th day
        * if closed before the end of the 15th day: 7.5% of staked amount is penalized
        * if closed before the end of the 30th day: 5% of staked amount is penalized
        * if closed before the end of the 45th day: 2.5% of staked amount is penalized
        * @param _stakingId ID of the stake, used as the Key from the stakeList mapping
        * @return penaltyAmount -- amount that will be debited from the stakers principal when they close their stake
     */
    function getStakePenalty(
        uint256 _stakingId
    )
        public
        view
        returns (uint256 penaltyAmount)
    {
        StakeElement memory _stakeElement = stakeList[_stakingId];

        uint256 daysDifference = getNow()
            .sub(_stakeElement.stakedAt)
            .div(SECONDS_IN_DAY);

        if (daysDifference < 15) {

            penaltyAmount = percentCalculator(
                _stakeElement.stakedAmount,
                750
            );

        } else if (daysDifference < 30) {

            penaltyAmount = percentCalculator(
                _stakeElement.stakedAmount,
                500
            );

        } else if (daysDifference < 45) {

            penaltyAmount = percentCalculator(
                _stakeElement.stakedAmount,
                250
            );
        }
    }

    /**
        * @notice calculates principal + interest - penalty (if applicable)
        * Note: this does not calculate a return rate, only what the sum would be if the stake was closed at that moment
        * @param _stakingId ID of the stake, used as the Key from the stakeList mapping
        * @dev the calculated value is only in memory
        * @return uint256 -- principal + interest - penalty
     */
    function estimateReturn(
        uint256 _stakingId
    )
        public
        view
        returns (uint256)
    {
        StakeElement memory _stakeElement = stakeList[_stakingId];

        if (_stakeElement.isActive == false) {
            return  _stakeElement.returnAmount;
        }

        return _stakeElement.stakedAmount
            .add(getStakeInterest(_stakingId))
            .sub(getStakePenalty(_stakingId));
    }

    /**
        * @notice close a stake older than 1 full day to:
        * 1) credit principal + interest - penalty to the balance of the staker
        * 2) update totalStakedAmount in globals
        * 3) take snapshot of current FEY status before the stake closes
        * No interest is accrued unless the stake is at least on its 4th day
        * Updates global variables to reflect the closed stake
        * @param _stakingId ID of the stake, used as the Key from the stakeList mapping
        * @return stakedAmount -- represents the total calculated by: principal + interest - penalty
        * @return penaltyAmount -- amount that will be debited from the stakers principal when they close their stake
        * @return interestAmount -- amount that will be debited from the stakers principal when they close their stake
     */
    function closeStake(
        uint256 _stakingId
    )
        public
        snapshotTriggerOnClose
        returns (
            uint256 stakedAmount,
            uint256 penaltyAmount,
            uint256 interestAmount
        )
    {
        return _closeStake(
            msg.sender,
            _stakingId
        );
    }

    function _closeStake(
        address _staker,
        uint256 _stakingId
    )
        internal
        returns (
            uint256 stakedAmount,
            uint256 penaltyAmount,
            uint256 interestAmount
        )
    {
        StakeElement memory _stakeElement = stakeList[_stakingId];

        uint256 daysDifference = getNow()
            .sub(_stakeElement.stakedAt)
            .div(SECONDS_IN_DAY);

        require(
            daysDifference >= 3,
            'FEYToken: immature stake'
        );

        require(
            _stakeElement.userAddress == _staker,
            'FEYToken: wrong stake owner'
        );

        require(
            _stakeElement.isActive,
            'FEYToken: stake not active'
        );

        _stakeElement.isActive = false;

        stakedAmount = _stakeElement.stakedAmount;

        if (daysDifference >= 45) {
            interestAmount = getStakeInterest(
                _stakingId
            );
        }

        penaltyAmount = getStakePenalty(
            _stakingId
        );

        totalSupply = totalSupply
            .add(interestAmount)
            .sub(penaltyAmount);

        _stakeElement.interestAmount = interestAmount;
        _stakeElement.returnAmount = stakedAmount
            .add(interestAmount)
            .sub(penaltyAmount);

        stakeList[_stakingId] = _stakeElement;

        balances[_staker] =
        balances[_staker].add(_stakeElement.returnAmount);

        globals.totalStakedAmount =
        globals.totalStakedAmount.sub(stakedAmount);

        emit StakeEnd(
            _stakingId,
            _staker,
            _stakeElement.returnAmount
        );

        emit Transfer(
            address(0x0),
            _staker,
            _stakeElement.returnAmount
        );
    }

    /**
        * @notice open a stake:
        * 1) must be greater than MINIMUM_STAKE in Declarations
        * 2) address opening the stake must have the amount of funds that they wish to stake in their balances[0xaddress]
        * 3) increment the global incrementId that is used to set the stakingId
        * 3) take snapshot of current FEY status before the stake is opened
        * Updates global variables to reflect the new stake
        * @param _amount the amount that you want to stake, will become your principal amount
        * @return true if no revert or error occurs
     */
    function openStake(
        uint256 _amount
    )
        external
        incrementId
        snapshotTriggerOnOpen
        returns (bool)
    {
        require(
            _transferCheck(
                msg.sender,
                address(0x0),
                _amount,
                true
            ),
            'FEYToken: _transferCheck failed'
        );

        require(
            _amount >= MINIMUM_STAKE,
            'FEYToken: stake below minimum'
        );

        balances[msg.sender] =
        balances[msg.sender].sub(_amount);

        stakeList[globals.stakingId] = StakeElement(
            msg.sender,
            _amount,
            0,
            0,
            getNow(),
            true
        );

        globals.totalStakedAmount =
        globals.totalStakedAmount.add(_amount);

        emit StakeStart(
            globals.stakingId,
            msg.sender,
            _amount
        );

        emit Transfer(
            msg.sender,
            address(0),
            _amount
        );

        return true;
    }

    /**
        * @notice getter for the data of a specific stake
        * @param _stakingId ID of the stake, used as the Key from the stakeList mapping
        * @return _stakedAmount -- represents the total calculated by: principal + interest - penalty
        * @return _userAddress -- address that was used to open the stake
        * @return _returnAmount -- principal + interest - penalty
        * @return interestAmount -- amount of interest accrued after closing the stake
        * @return _stakedAt -- timestamp of when stake was opened
        * @return _isActive -- boolean for if the stake is open and accruing interest
     */
    function getStaking(
        uint256 _stakingId
    )
        external
        view
        returns (
            uint256 _stakedAmount,
            address _userAddress,
            uint256 _returnAmount,
            uint256 interestAmount,
            uint256 _stakedAt,
            bool _isActive
        )
    {
        StakeElement memory _stakeElement = stakeList[_stakingId];

        return (
            _stakeElement.stakedAmount,
            _stakeElement.userAddress,
            _stakeElement.returnAmount,
            _stakeElement.interestAmount,
            _stakeElement.stakedAt,
            _stakeElement.isActive
        );
    }
}
Helper.sol 128 lines
// SPDX-License-Identifier: -- ? --

pragma solidity ^0.7.3;

import './Timing.sol';
import './Ownable.sol';
import './Events.sol';
import './SafeMath.sol';

contract Helper is Ownable, Timing, Events {

    using SafeMath for uint256;

    /**
    * @notice burns set amount of tokens
    * @dev currently unused based on changing requirements
    * @param _amount -- amount to be burned
    * @return true if burn() succeeds
    */
    function burn(
        uint256 _amount
    )
        external
        onlyOwner
        returns (bool)
    {
        require(
            balances[msg.sender].sub(_amount) >= 0,
            'FEYToken: exceeding balance'
        );

        totalSupply =
        totalSupply.sub(_amount);

        balances[msg.sender] =
        balances[msg.sender].sub(_amount);

        emit Transfer(
            msg.sender,
            address(0x0),
            _amount
       );

        return true;
    }

    /**
    * @notice Groups common requirements in global, internal function
    * @dev Used by Transfer(), TransferFrom(), OpenStake()
    * @param _sender -- msg.sender of the functions listed above
    * @param _recipient -- recipient of amount
    * @param _amount -- amount that is transferred
    * @param _allowBurnAddress -- boolean to allow burning tokens
    * @return balance[] value of the input address
    */
    function _transferCheck(
        address _sender,
        address _recipient,
        uint256 _amount,
        bool _allowBurnAddress
    )
        internal
        view
        returns (bool)
    {

        if (_allowBurnAddress == false) {
            require(
                _recipient != address(0x0),
                'FEYToken: cannot send to burn address'
            );
        }

        require(
            balances[_sender] >= _amount,
            'FEYToken: exceeding balance'
        );

        require(
            balances[_recipient].add(_amount) >= balances[_recipient],
            'FEYToken: overflow detected'
        );

        return true;
    }

    /**
    * @notice Used to calculate % that is staked out of the totalSupply
    * @dev Used by getYearlyInterestLatest(), getYearlyInterestHistorical(), + twice in getInterest()
    * @param _numerator -- numerator, typically globals.totalStakedAmount
    * @param _denominator -- denominator, typically totalSupply
    * @param _precision -- number of decimal points, fixed at 4
    * @return quotient -- calculated value
    */
    function getPercent(
        uint256 _numerator,
        uint256 _denominator,
        uint256 _precision
    )
        public
        pure
        returns(uint256 quotient)
    {
        uint256 numerator = _numerator * 10 ** (_precision + 1);
        quotient = ((numerator / _denominator) + 5) / 10;
    }

    /**
    * @notice Used to reduce value by a set percentage amount
    * @dev Used to calculate penaltyAmount
    * @param _value -- initial value, typically _stakeElement.stakedAmount
    * @param _perc -- percentage reduction that will be applied
    * @return percentageValue -- value reduced by the input percentage
    */
    function percentCalculator(
        uint256 _value,
        uint256 _perc
    )
        public
        pure
        returns (uint256 percentageValue)
    {
        percentageValue = _value
            .mul(_perc)
            .div(10000);
    }

}
Migrations.sol 24 lines
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.8.0;

contract Migrations {
    address public owner;
    uint public last_completed_migration;

    constructor() {
        owner = msg.sender;
    }

    modifier restricted() {
        if (msg.sender == owner) _;
    }

    function setCompleted(uint completed) public restricted {
        last_completed_migration = completed;
    }

    function upgrade(address new_address) public restricted {
        Migrations upgraded = Migrations(new_address);
        upgraded.setCompleted(last_completed_migration);
    }
}
Ownable.sol 48 lines
// SPDX-License-Identifier: -- ? --

pragma solidity ^0.7.3;

contract Ownable {

    address public owner;

    event ownershipChanged(
        address indexed _invoker,
        address indexed _newOwner
    );

    constructor() {
        owner = msg.sender;
    }

    modifier onlyOwner() {
        require(
            msg.sender == owner,
            'Ownable: must be the owner'
        );
        _;
    }

    function changeOwner(
        address _newOwner
    )
        external
        onlyOwner
        returns (bool)
    {
        
        require(
            _newOwner != address(0),
            'Ownable: new owner must not be the blackhole address'
        );
        
        owner = _newOwner;

        emit ownershipChanged(
            msg.sender,
            _newOwner
        );

        return true;
    }
}
SafeMath.sol 40 lines
// SPDX-License-Identifier: -- ? --

pragma solidity ^0.7.0;

library SafeMath {

    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, 'SafeMath: addition overflow');
        return c;
    }

    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b <= a, 'SafeMath: subtraction overflow');
        uint256 c = a - b;
        return c;
    }

    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

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

    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b > 0, 'SafeMath: division by zero');
        uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold
        return c;
    }

    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b != 0, 'SafeMath: modulo by zero');
        return a % b;
    }
}
Snapshot.sol 77 lines
// SPDX-License-Identifier: -- ? --

pragma solidity ^0.7.3;

import "./Helper.sol";

abstract contract Snapshot is Helper {

    using SafeMath for uint;


    /**
    * @notice modifier to capture snapshots when a stake is opened
    * @dev used in OpenStake() in FeyToken 
    */
    modifier snapshotTriggerOnOpen() 
    {
        _;
        _dailySnapshotPoint(
            _currentFeyDay()
        );
    }
    
    
    /**
    * @notice modifier to capture snapshots when a stake is closed
    * @dev used in CloseStake() in FeyToken 
    */
    modifier snapshotTriggerOnClose() 
    {
        _dailySnapshotPoint(
            _currentFeyDay()
        );
        _;
    }

    /**
    * @notice Manually capture snapshot
    */
    function manualDailySnapshot() 
        external
    {
        _dailySnapshotPoint(
            _currentFeyDay()
        );
    }

    /**
    * @notice takes in todays feyday + updates all missing snapshot days with todays data
    * @param _updateDay -- current FeyDay as outputted from timing's _currentFeyDay() function
    * Emits SnapshotCaptured event
    */
    function _dailySnapshotPoint(
        uint64 _updateDay
    )
        private
    {
        for (uint256 _day = globals.currentFeyDay; _day < _updateDay; _day++) {

            SnapShot memory s = snapshots[_day];

            s.totalSupply = totalSupply;
            s.totalStakedAmount = globals.totalStakedAmount;
            

            snapshots[_day] = s;

            globals.currentFeyDay++;
        }

        emit SnapshotCaptured(
            totalSupply,
            globals.totalStakedAmount,
            _updateDay
        );
    }
}
Timing.sol 65 lines
// SPDX-License-Identifier: -- ? --

pragma solidity ^0.7.3;

import './Declaration.sol';

abstract contract Timing is Declaration {

    /**
    * @notice external view function to get current FeyDay, unless called at LAUNCH_TIME, in which case it will return 0 to save gas
    * @dev called by _currentFeyDay
    * @return current FeyDay
    */
    function currentFeyDay()
        public
        view
        returns (uint64)
    {
        return getNow() >= LAUNCH_TIME
            ? _currentFeyDay()
            : 0;
    }

    /**
    * @notice internal view function to calculate current FeyDay by using _feyDayFromStamp()
    * @dev called by snapshotTrigger(), manualDailySnapshot(), + getStakeInterest()
    * @return current FeyDay
    */
    function _currentFeyDay()
        internal
        view
        returns (uint64)
    {
        return _feyDayFromStamp(getNow());
    }

    /**
    * @notice calculates difference between passed timestamp + original LAUNCH_TIME, set when contract was deployed
    * @dev called by _currentFeyDay
    * @param _timestamp -- timestamp to use for difference
    * @return number of days between timestamp param + LAUNCH_TIME 
    */
    function _feyDayFromStamp(
        uint256 _timestamp
    )
        internal
        view
        returns (uint64)
    {
        return uint64((_timestamp - LAUNCH_TIME) / SECONDS_IN_DAY);
    }
    
    /**
    * @dev called by getStakeAge(), getStakePenalty, closeStake(), openStake(), + _currentFeyDay
    * @return current block.timestamp
    */
    function getNow()
        public
        view
        returns (uint256)
    {
        return block.timestamp;
    }

}
Token.sol 166 lines
// SPDX-License-Identifier: -- ? --

pragma solidity ^0.7.3;

import "./Snapshot.sol";

contract Token is Snapshot {

    using SafeMath for uint256;

    /**
    * @notice Moves amount tokens from the caller’s account to recipient.
    * Returns a boolean value indicating whether the operation succeeded.
    * @dev See {IERC20-transfer}.
    * Emits an {Transfer} event indicating a successful transfer.
    * @param _receiver -- recipient of amount
    * @param _amount -- amount that is transferred
    * @return true if transfer() succeeds
    */
    function transfer(
        address _receiver,
        uint256 _amount
    )
        external
        returns (bool)
    {
        require(
            _transferCheck(
                msg.sender,
                _receiver,
                _amount,
                false
            ),
            'Token: _transferCheck failed'
        );

        balances[msg.sender] =
        balances[msg.sender].sub(_amount);

        balances[_receiver] =
        balances[_receiver].add(_amount);

        emit Transfer(
            msg.sender,
            _receiver,
            _amount
        );

        return true;
    }

    /**
    * @notice 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.
    * @dev See {IERC20-transferFrom}.
    * Emits an {Transfer} event indicating a successful transfer.
    * @param _owner -- address who is sending the transfer amount
    * @param _receiver -- recipient of amount
    * @param _amount -- amount that is transferred
    * @return true if transferFrom() succeeds
     */
    function transferFrom(
        address _owner,
        address _receiver,
        uint256 _amount
    )
        external
        returns (bool)
    {
        require(
            _transferCheck(
                _owner,
                _receiver,
                _amount,
                false
            ),
            'Token: _transferCheck failed'
        );

        require(
            allowances[_owner][msg.sender] >= _amount,
            'Token: exceeding allowance'
        );

        allowances[_owner][msg.sender] =
        allowances[_owner][msg.sender].sub(_amount);

        balances[_owner] =
        balances[_owner].sub(_amount);

        balances[_receiver] =
        balances[_receiver].add(_amount);

        emit Transfer(
            _owner,
            _receiver,
            _amount
        );

        return true;
    }

    /**
    * @notice Sets amount as the allowance of spender over the caller’s tokens.
    * @dev See {IERC20-approve}.
    * Emits an {Approval} event indicating how much was approved and whom is the spender
    * @param _spender -- approved address
    * @param _amount -- amount that they are approved to spend
    * @return true if Approve() succeeds
    */
    function approve(
        address _spender,
        uint256 _amount
    )
        external
        returns (bool)
    {

        allowances[msg.sender][_spender] = _amount;

        emit Approval(
            msg.sender,
            _spender,
            _amount
        );

        return true;
    }

    /**
    * @notice Returns the amount of tokens owned by account.
    * @dev See {IERC20-approve}.
    * @param _address -- address whose balance will be returned
    * @return balance[] value of the input address
    */
    function balanceOf(
        address _address
    )
        external
        view
        returns (uint256)
    {
        return balances[_address];
    }

    /**
    * @notice 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.
    * @dev See {IERC20-allowance}.
    * @param _owner -- owner address
    * @param _spender -- address that is approved to spend tokens
    * @return allowances[] value of the input addresses to reflect the value mapped to the _spender's address
    */
    function allowance(
        address _owner,
        address _spender
    )
        external
        view
        returns (uint256)
    {
        return allowances[_owner][_spender];
    }
}

Read Contract

LAUNCH_TIME 0x022466b5 → uint256
MAX_STAKE_DAYS 0x26986d3f → uint256
MINIMUM_STAKE 0x08dbbb03 → uint256
SECONDS_IN_DAY 0x61a52a36 → uint256
YEARLY_INTEREST 0x0eb1bc08 → uint256
allowance 0xdd62ed3e → uint256
allowances 0x55b6ed5c → uint256
balanceOf 0x70a08231 → uint256
balances 0x27e235e3 → uint256
currentFeyDay 0x8f2dbc21 → uint64
decimals 0x313ce567 → uint256
estimateReturn 0x58ff4ddd → uint256
getInterest 0x1df5b4d2 → uint256
getInterestRateYearly 0xe498484c → uint256
getNow 0xbbe4fd50 → uint256
getPercent 0x291ab43b → uint256
getStakeAge 0xf67e6756 → uint256, uint256
getStakeInterest 0x3a6088db → uint256
getStakePenalty 0x17f4cb8b → uint256
getStaking 0x31eb3f37 → uint256, address, uint256, uint256, uint256, bool
getYearlyInterestHistorical 0x1c89edc7 → uint256, uint256
getYearlyInterestLatest 0xd2e6bcfa → uint256, uint256
globals 0xc3124525 → uint256, uint256, uint256
name 0x06fdde03 → string
owner 0x8da5cb5b → address
percentCalculator 0x99d0cfa1 → uint256
snapshots 0xd6565a2d → uint256, uint256
stakeList 0x4c86259e → address, uint256, uint256, uint256, uint256, bool
symbol 0x95d89b41 → string
totalSupply 0x18160ddd → uint256

Write Contract 9 functions

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

approve 0x095ea7b3
address _spender
uint256 _amount
returns: bool
burn 0x42966c68
uint256 _amount
returns: bool
changeOwner 0xa6f9dae1
address _newOwner
returns: bool
closeGhostStake 0x25c01505
uint256 _stakingId
closeStake 0xbd5bf4ce
uint256 _stakingId
returns: uint256, uint256, uint256
manualDailySnapshot 0x613fc9fd
No parameters
openStake 0xf7d623bb
uint256 _amount
returns: bool
transfer 0xa9059cbb
address _receiver
uint256 _amount
returns: bool
transferFrom 0x23b872dd
address _owner
address _receiver
uint256 _amount
returns: bool

Recent Transactions

No transactions found for this address