Address Contract Partially Verified
Address
0xe8E06a5613dC86D459bC8Fb989e173bB8b256072
Balance
0 ETH
Nonce
1
Code Size
8156 bytes
Creator
0xe84412f9...c929 at tx 0x5fb6fc3a...eb58b3
Indexed Transactions
0
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