Transaction Hash:
Block:
22364275 at Apr-28-2025 01:27:35 AM +UTC
Transaction Fee:
0.0000231435 ETH
$0.06
Gas Used:
46,287 Gas / 0.5 Gwei
Emitted Events:
165 |
TEXAN.Approval( owner=[Sender] 0x6499dbce7751de048ced08b6a9fb0b8f182ee862, spender=0xaaaaaaae...d26D23D4d, value=1000000000000000000000000 )
|
Account State Difference:
Address | Before | After | State Difference | ||
---|---|---|---|---|---|
0x6499dBCe...f182Ee862 |
0.000059370197576619 Eth
Nonce: 16
|
0.000036226697576619 Eth
Nonce: 17
| 0.0000231435 | ||
0x95222290...5CC4BAfe5
Miner
| (beaverbuild) | 16.275344961435007919 Eth | 16.275350729964232391 Eth | 0.000005768529224472 | |
0xcFCFfE43...77B2A88d7 |
Execution Trace
TEXAN.approve( spender=0xaaaaaaae92Cc1cEeF79a038017889fDd26D23D4d, amount=1000000000000000000000000 ) => ( True )
{"Context.sol":{"content":"// SPDX-License-Identifier: UNLICENSED\r\n// @title Stakeable Endowment Token\r\n// @author Origin Addrress\r\n\r\npragma solidity ^0.8.13;\r\n\r\n// @dev Provides information about the current execution context, including the\r\n// sender of the transaction and its data. While these are generally available\r\n// via msg.sender and msg.data, they should not be accessed in such a direct\r\n// manner, since when dealing with meta-transactions the account sending and\r\n// paying for execution may not be the actual sender (as far as an application\r\n// is concerned).\r\n// This contract is only required for intermediate, library-like contracts.\r\nabstract contract Context {\r\n function _msgSender()\r\n internal\r\n view\r\n virtual\r\n returns (address)\r\n {\r\n return msg.sender;\r\n }\r\n\r\n function _msgData()\r\n internal\r\n view\r\n virtual\r\n returns (bytes calldata)\r\n {\r\n return msg.data;\r\n }\r\n}"},"ERC20.sol":{"content":"// SPDX-License-Identifier: UNLICENSED\r\n// @title Stakeable Endowment Token\r\n// @author Origin Addrress\r\n\r\npragma solidity ^0.8.13;\r\n\r\n// Import Context\r\nimport \"./IERC20Metadata.sol\";\r\n\r\n/**\r\n * @dev Implementation of the {IERC20} interface.\r\n *\r\n * This implementation is agnostic to the way tokens are created. This means\r\n * that a supply mechanism has to be added in a derived contract using {_mint}.\r\n * For a generic mechanism see {ERC20PresetMinterPauser}.\r\n *\r\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\r\n * instead returning `false` on failure. This behavior is nonetheless\r\n * conventional and does not conflict with the expectations of ERC20\r\n * applications.\r\n *\r\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\r\n * This allows applications to reconstruct the allowance for all accounts just\r\n * by listening to said events. Other implementations of the EIP may not emit\r\n * these events, as it isn\u0027t required by the specification.\r\n *\r\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\r\n * functions have been added to mitigate the well-known issues around setting\r\n * allowances. See {IERC20-approve}.\r\n */\r\n\r\ncontract ERC20 is Context, IERC20, IERC20Metadata {\r\n mapping(address =\u003e uint256) private _balances;\r\n\r\n mapping(address =\u003e mapping(address =\u003e uint256)) private _allowances;\r\n\r\n uint256 private _totalSupply;\r\n\r\n string private _tokenName;\r\n string private _tokenSymbol;\r\n\r\n function setNameAndSymbol(string memory nameOfToken, string memory symbolOfToken) internal {\r\n _tokenName = nameOfToken;\r\n _tokenSymbol = symbolOfToken;\r\n }\r\n\r\n\r\n /**\r\n * @dev Returns the name of the token.\r\n */\r\n function name() public view virtual override returns (string memory) {\r\n return _tokenName;\r\n }\r\n\r\n /**\r\n * @dev Returns the symbol of the token, usually a shorter version of the\r\n * name.\r\n */\r\n function symbol() public view virtual override returns (string memory) {\r\n return _tokenSymbol;\r\n }\r\n\r\n /**\r\n * @dev Returns the number of decimals used to get its user representation.\r\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\r\n * be displayed to a user as `5.05` (`505 / 10 ** 2`).\r\n *\r\n * Tokens usually opt for a value of 18, imitating the relationship between\r\n * Ether and Wei. This is the value {ERC20} uses, unless this function is\r\n * overridden;\r\n *\r\n * NOTE: This information is only used for _display_ purposes: it in\r\n * no way affects any of the arithmetic of the contract, including\r\n * {IERC20-balanceOf} and {IERC20-transfer}.\r\n */\r\n function decimals() public view virtual override returns (uint8) {\r\n return 18;\r\n }\r\n\r\n /**\r\n * @dev See {IERC20-totalSupply}.\r\n */\r\n function totalSupply() public view virtual override returns (uint256) {\r\n return _totalSupply;\r\n }\r\n\r\n /**\r\n * @dev See {IERC20-balanceOf}.\r\n */\r\n function balanceOf(address account) public view virtual override returns (uint256) {\r\n return _balances[account];\r\n }\r\n\r\n /**\r\n * @dev See {IERC20-transfer}.\r\n *\r\n * Requirements:\r\n *\r\n * - `recipient` cannot be the zero address.\r\n * - the caller must have a balance of at least `amount`.\r\n */\r\n function transfer(address recipient, uint256 amount) public virtual override returns (bool) {\r\n _transfer(_msgSender(), recipient, amount);\r\n return true;\r\n }\r\n\r\n /**\r\n * @dev See {IERC20-allowance}.\r\n */\r\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\r\n return _allowances[owner][spender];\r\n }\r\n\r\n /**\r\n * @dev See {IERC20-approve}.\r\n *\r\n * Requirements:\r\n *\r\n * - `spender` cannot be the zero address.\r\n */\r\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\r\n _approve(_msgSender(), spender, amount);\r\n return true;\r\n }\r\n\r\n /**\r\n * @dev See {IERC20-transferFrom}.\r\n *\r\n * Emits an {Approval} event indicating the updated allowance. This is not\r\n * required by the EIP. See the note at the beginning of {ERC20}.\r\n *\r\n * Requirements:\r\n *\r\n * - `sender` and `recipient` cannot be the zero address.\r\n * - `sender` must have a balance of at least `amount`.\r\n * - the caller must have allowance for ``sender``\u0027s tokens of at least\r\n * `amount`.\r\n */\r\n function transferFrom(\r\n address sender,\r\n address recipient,\r\n uint256 amount\r\n ) public virtual override returns (bool) {\r\n _transfer(sender, recipient, amount);\r\n\r\n uint256 currentAllowance = _allowances[sender][_msgSender()];\r\n require(currentAllowance \u003e= amount, \"ERC20: transfer amount exceeds allowance\");\r\n unchecked {\r\n _approve(sender, _msgSender(), currentAllowance - amount);\r\n }\r\n\r\n return true;\r\n }\r\n\r\n /**\r\n * @dev Atomically increases the allowance granted to `spender` by the caller.\r\n *\r\n * This is an alternative to {approve} that can be used as a mitigation for\r\n * problems described in {IERC20-approve}.\r\n *\r\n * Emits an {Approval} event indicating the updated allowance.\r\n *\r\n * Requirements:\r\n *\r\n * - `spender` cannot be the zero address.\r\n */\r\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\r\n _approve(_msgSender(), spender, _allowances[_msgSender()][spender] + addedValue);\r\n return true;\r\n }\r\n\r\n /**\r\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\r\n *\r\n * This is an alternative to {approve} that can be used as a mitigation for\r\n * problems described in {IERC20-approve}.\r\n *\r\n * Emits an {Approval} event indicating the updated allowance.\r\n *\r\n * Requirements:\r\n *\r\n * - `spender` cannot be the zero address.\r\n * - `spender` must have allowance for the caller of at least\r\n * `subtractedValue`.\r\n */\r\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\r\n uint256 currentAllowance = _allowances[_msgSender()][spender];\r\n require(currentAllowance \u003e= subtractedValue, \"ERC20: decreased allowance below zero\");\r\n unchecked {\r\n _approve(_msgSender(), spender, currentAllowance - subtractedValue);\r\n }\r\n\r\n return true;\r\n }\r\n\r\n /**\r\n * @dev Moves `amount` of tokens from `sender` to `recipient`.\r\n *\r\n * This internal function is equivalent to {transfer}, and can be used to\r\n * e.g. implement automatic token fees, slashing mechanisms, etc.\r\n *\r\n * Emits a {Transfer} event.\r\n *\r\n * Requirements:\r\n *\r\n * - `sender` cannot be the zero address.\r\n * - `recipient` cannot be the zero address.\r\n * - `sender` must have a balance of at least `amount`.\r\n */\r\n function _transfer(\r\n address sender,\r\n address recipient,\r\n uint256 amount\r\n ) internal virtual {\r\n require(sender != address(0), \"ERC20: transfer from the zero address\");\r\n require(recipient != address(0), \"ERC20: transfer to the zero address\");\r\n\r\n _beforeTokenTransfer(sender, recipient, amount);\r\n\r\n uint256 senderBalance = _balances[sender];\r\n require(senderBalance \u003e= amount, \"ERC20: transfer amount exceeds balance\");\r\n unchecked {\r\n _balances[sender] = senderBalance - amount;\r\n }\r\n _balances[recipient] += amount;\r\n\r\n emit Transfer(sender, recipient, amount);\r\n\r\n _afterTokenTransfer(sender, recipient, amount);\r\n }\r\n\r\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\r\n * the total supply.\r\n *\r\n * Emits a {Transfer} event with `from` set to the zero address.\r\n *\r\n * Requirements:\r\n *\r\n * - `account` cannot be the zero address.\r\n */\r\n function _mint(address account, uint256 amount) internal virtual {\r\n require(account != address(0), \"ERC20: mint to the zero address\");\r\n\r\n _beforeTokenTransfer(address(0), account, amount);\r\n\r\n _totalSupply += amount;\r\n _balances[account] += amount;\r\n emit Transfer(address(0), account, amount);\r\n\r\n _afterTokenTransfer(address(0), account, amount);\r\n }\r\n\r\n /**\r\n * @dev Destroys `amount` tokens from `account`, reducing the\r\n * total supply.\r\n *\r\n * Emits a {Transfer} event with `to` set to the zero address.\r\n *\r\n * Requirements:\r\n *\r\n * - `account` cannot be the zero address.\r\n * - `account` must have at least `amount` tokens.\r\n */\r\n function _burn(address account, uint256 amount) internal virtual {\r\n require(account != address(0), \"ERC20: burn from the zero address\");\r\n\r\n _beforeTokenTransfer(account, address(0), amount);\r\n\r\n uint256 accountBalance = _balances[account];\r\n require(accountBalance \u003e= amount, \"ERC20: burn amount exceeds balance\");\r\n unchecked {\r\n _balances[account] = accountBalance - amount;\r\n }\r\n _totalSupply -= amount;\r\n\r\n emit Transfer(account, address(0), amount);\r\n\r\n _afterTokenTransfer(account, address(0), amount);\r\n }\r\n\r\n /**\r\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\r\n *\r\n * This internal function is equivalent to `approve`, and can be used to\r\n * e.g. set automatic allowances for certain subsystems, etc.\r\n *\r\n * Emits an {Approval} event.\r\n *\r\n * Requirements:\r\n *\r\n * - `owner` cannot be the zero address.\r\n * - `spender` cannot be the zero address.\r\n */\r\n function _approve(\r\n address owner,\r\n address spender,\r\n uint256 amount\r\n ) internal virtual {\r\n require(owner != address(0), \"ERC20: approve from the zero address\");\r\n require(spender != address(0), \"ERC20: approve to the zero address\");\r\n\r\n _allowances[owner][spender] = amount;\r\n emit Approval(owner, spender, amount);\r\n }\r\n\r\n /**\r\n * @dev Hook that is called before any transfer of tokens. This includes\r\n * minting and burning.\r\n *\r\n * Calling conditions:\r\n *\r\n * - when `from` and `to` are both non-zero, `amount` of ``from``\u0027s tokens\r\n * will be transferred to `to`.\r\n * - when `from` is zero, `amount` tokens will be minted for `to`.\r\n * - when `to` is zero, `amount` of ``from``\u0027s tokens will be burned.\r\n * - `from` and `to` are never both zero.\r\n *\r\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\r\n */\r\n function _beforeTokenTransfer(\r\n address from,\r\n address to,\r\n uint256 amount\r\n ) internal virtual {}\r\n\r\n /**\r\n * @dev Hook that is called after any transfer of tokens. This includes\r\n * minting and burning.\r\n *\r\n * Calling conditions:\r\n *\r\n * - when `from` and `to` are both non-zero, `amount` of ``from``\u0027s tokens\r\n * has been transferred to `to`.\r\n * - when `from` is zero, `amount` tokens have been minted for `to`.\r\n * - when `to` is zero, `amount` of ``from``\u0027s tokens have been burned.\r\n * - `from` and `to` are never both zero.\r\n *\r\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\r\n */\r\n function _afterTokenTransfer(\r\n address from,\r\n address to,\r\n uint256 amount\r\n ) internal virtual {}\r\n}\r\n"},"IERC20.sol":{"content":"// SPDX-License-Identifier: UNLICENSED\r\n// @title Stakeable Endowment Token\r\n// @author Origin Addrress\r\n\r\npragma solidity ^0.8.13;\r\n\r\n// Import Context\r\nimport \"./Context.sol\";\r\n\r\n/**\r\n * @dev Interface of the ERC20 standard as defined in the EIP.\r\n */\r\ninterface IERC20 {\r\n /**\r\n * @dev Returns the amount of tokens in existence.\r\n */\r\n function totalSupply() external view returns (uint256);\r\n\r\n /**\r\n * @dev Returns the amount of tokens owned by `account`.\r\n */\r\n function balanceOf(address account) external view returns (uint256);\r\n\r\n /**\r\n * @dev Moves `amount` tokens from the caller\u0027s account to `recipient`.\r\n *\r\n * Returns a boolean value indicating whether the operation succeeded.\r\n *\r\n * Emits a {Transfer} event.\r\n */\r\n function transfer(address recipient, uint256 amount) external returns (bool);\r\n\r\n /**\r\n * @dev Returns the remaining number of tokens that `spender` will be\r\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\r\n * zero by default.\r\n *\r\n * This value changes when {approve} or {transferFrom} are called.\r\n */\r\n function allowance(address owner, address spender) external view returns (uint256);\r\n\r\n /**\r\n * @dev Sets `amount` as the allowance of `spender` over the caller\u0027s tokens.\r\n *\r\n * Returns a boolean value indicating whether the operation succeeded.\r\n *\r\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\r\n * that someone may use both the old and the new allowance by unfortunate\r\n * transaction ordering. One possible solution to mitigate this race\r\n * condition is to first reduce the spender\u0027s allowance to 0 and set the\r\n * desired value afterwards:\r\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\r\n *\r\n * Emits an {Approval} event.\r\n */\r\n function approve(address spender, uint256 amount) external returns (bool);\r\n\r\n /**\r\n * @dev Moves `amount` tokens from `sender` to `recipient` using the\r\n * allowance mechanism. `amount` is then deducted from the caller\u0027s\r\n * allowance.\r\n *\r\n * Returns a boolean value indicating whether the operation succeeded.\r\n *\r\n * Emits a {Transfer} event.\r\n */\r\n function transferFrom(\r\n address sender,\r\n address recipient,\r\n uint256 amount\r\n ) external returns (bool);\r\n\r\n /**\r\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\r\n * another (`to`).\r\n *\r\n * Note that `value` may be zero.\r\n */\r\n event Transfer(address indexed from, address indexed to, uint256 value);\r\n\r\n /**\r\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\r\n * a call to {approve}. `value` is the new allowance.\r\n */\r\n event Approval(address indexed owner, address indexed spender, uint256 value);\r\n}"},"IERC20Metadata.sol":{"content":"// SPDX-License-Identifier: UNLICENSED\r\n// @title Stakeable Endowment Token\r\n// @author Origin Addrress\r\n\r\npragma solidity ^0.8.13;\r\n\r\n// Import Context\r\nimport \"./IERC20.sol\";\r\n\r\n/**\r\n * @dev Interface for the optional metadata functions from the ERC20 standard.\r\n *\r\n * _Available since v4.1._\r\n */\r\ninterface IERC20Metadata is IERC20 {\r\n /**\r\n * @dev Returns the name of the token.\r\n */\r\n function name() external view returns (string memory);\r\n\r\n /**\r\n * @dev Returns the symbol of the token.\r\n */\r\n function symbol() external view returns (string memory);\r\n\r\n /**\r\n * @dev Returns the decimals places of the token.\r\n */\r\n function decimals() external view returns (uint8);\r\n}"},"StakableEndowmentToken.sol":{"content":"// SPDX-License-Identifier: UNLICENSED\r\n// @title Stakeable Endowment Token\r\n// @author Origin Addrress\r\n// @notice This contract is proprietary and may not be copied or used without permission.\r\n// @dev Stakable Endowment Main Functions for Staking, Scraping, and Ending Stakes\r\n// @notice These are the main public functions for the token.\r\n\r\npragma solidity ^0.8.13;\r\n\r\nimport \"./ERC20.sol\";\r\n\r\nabstract contract StakableEndowmentToken is ERC20 {\r\n // Launch timeTime \r\n // Dec 22 12AM GMT\r\n uint256 internal constant LAUNCH_TIME = 1671667200; //The time of launch\r\n \r\n // Global Constants Constants\r\n uint256 internal constant MIN_STAKE_DAYS = 1;\r\n uint256 internal constant MAX_STAKE_DAYS = 8036; // Approx 22 years and half a day\r\n uint256 internal constant MAX_STAKE_YEARS = 22; //\r\n\r\n uint256 internal constant MIN_STAKE_AMOUNT = 10000;\r\n uint256 internal constant MAX_STAKE_AMOUNT = 1e29; // 100B Stake is the max (100000000000000000000000000000)\r\n\r\n // This is the Endowment Supply. For security reasons we made this an \r\n // internal variable that only this contract can change.\r\n \r\n // The initial supply is 97 Trillion locked in the contract\r\n uint256 internal _endowmentSupply = (97 * 1e30);\r\n\r\n // Global Variables\r\n uint256 g_latestStakeId = 0; // the global stake id starting at zero so first take will be 1\r\n uint256 g_stakedStars = 0; // the amount of wei that is already staked\r\n uint256 g_stakedPrincipleStars = 0; // the amount of principle that is staked in wei\r\n uint256 g_penalizedStars = 0; // these are the Stars that have been set aside from penalties\r\n uint256 g_stakedCount = 0; // current count of active stakes based on + and - in startStake and endStake\r\n\r\n // For Calculations\r\n uint256 constant PRECISION = 1e18; // 18 decimals\r\n uint256 constant YEARDIVIDER = 36525; // must use yearprecision multiplier with this (100)\r\n uint256 constant YEARPRECISION = 100; // because of integers only multiple by precision, divide by precision\r\n\r\n\r\n\r\n // @notice This contract has the utilities necessary for the Staking Endowment Token below\r\n event StartStake(\r\n address indexed stakeAddress, // Address\r\n uint256 indexed stakeId,\r\n uint256 indexed eventName,\r\n uint256 startDay,\r\n uint256 stakedDays,\r\n uint256 principle,\r\n uint256 possibleInterest\r\n );\r\n\r\n event ScrapeStake(\r\n address indexed stakeAddress,\r\n uint256 indexed stakeId,\r\n uint256 indexed eventName,\r\n uint256 scrapeDay,\r\n uint256 previousScrapedInterest,\r\n uint256 oldPossibleInterest,\r\n uint256 scrapedInterest,\r\n uint possibleInterest\r\n );\r\n\r\n event EndStake(\r\n address indexed stakeAddress,\r\n uint256 indexed stakeId,\r\n uint256 indexed eventName,\r\n uint256 endStakeDay,\r\n uint256 principle,\r\n uint256 oldPossibleInterest,\r\n uint256 scrapedInterest,\r\n uint256 penalties,\r\n uint256 stakeTotal\r\n );\r\n\r\n // @dev Memory resident Stake for temporary use\r\n // @param uint256 _stakeId\r\n // @param uint256 _stakedPrinciple\r\n // @param uint256 _startDay\r\n // @param uint256 _scrapeDay\r\n // @param uint256 _stakedDays\r\n // @param uint256 _scrapedInterest\r\n // @param uint256 _possibleStars\r\n struct TempStake {\r\n uint256 _stakeId;\r\n uint256 _stakedPrinciple;\r\n uint256 _startDay;\r\n uint256 _scrapeDay;\r\n uint256 _stakedDays;\r\n uint256 _scrapedInterest;\r\n uint256 _possibleStars;\r\n }\r\n\r\n // @dev Permenant Stake for Storage\r\n // @param uint256 stakeId The stake ID\r\n // @param uint256 stakedPrinciple The initial principle staked\r\n // @param uint256 startDay The day the stake was started\r\n // @param uint256 scrapeDay The day the stake was scraped\r\n // @param uint256 stakedDays The days of the stake commitment\r\n // @param uint256 scrapedInterest The interest that has been scraped if any\r\n // @param uint256 possibleStars The potential amount of stars for this stake\r\n struct PermStake {\r\n uint256 stakeId;\r\n uint256 stakedPrinciple;\r\n uint256 startDay;\r\n uint256 scrapeDay;\r\n uint256 stakedDays;\r\n uint256 scrapedInterest;\r\n uint256 possibleStars;\r\n }\r\n\r\n // initialize the Store of Stakes.\r\n mapping(address =\u003e PermStake[]) public Stakes;\r\n\r\n // @dev Private: This emits the event\r\n // and was moved due to stack limits\r\n // @param uint256 stakeId - the stake id\r\n // @param uint256 interestDays the days of interest applied in this case\r\n // @param uint256 previousInterest - the amount of interest previously scraped\r\n // @param uint256 previousPossibleStars - what the previous amount of interest was before the scrape\r\n // @param uint256 scrapedInterest - the amount of interest scraped by this action\r\n // @param uint256 newPossibleIntest - the possible interest\r\n function emitScrapeEvent(uint256 stakeId, uint256 interestDays, uint256 previousInterest, uint256 previousPossibleStars, uint256 scrapedInterest, uint256 newPossibleInterest ) \r\n internal \r\n {\r\n // Emit the stake scrape event\r\n emit ScrapeStake(\r\n msg.sender, // event Sender set here\r\n stakeId, // stake Id\r\n uint(2), // event id is 2\r\n interestDays,\r\n previousInterest,\r\n previousPossibleStars,\r\n scrapedInterest,\r\n newPossibleInterest\r\n );\r\n }\r\n\r\n // @dev Public Function: Open a stake.\r\n // @param uint256 stakedPrinciple Number of Stars to stake\r\n // @param uint256 stakedDays length of days in the stake\r\n function startStake(uint256 stakedPrinciple, uint256 stakedDays)\r\n external\r\n {\r\n // make sure the stake params are within guidelines or throw an error\r\n _assurePrincipleAndStakedDaysAreValid(stakedPrinciple, stakedDays);\r\n \r\n //Calculate possible payout\r\n uint256 possibleInterest = _calculateInterest(stakedPrinciple, stakedDays);\r\n \r\n // Create total possible stars\r\n uint256 possibleStars = possibleInterest + stakedPrinciple; // ALL possible interest AND principle\r\n \r\n require(_endowmentSupply \u003e possibleInterest, \"There is not enough to cover your stake\");\r\n\r\n // Start the stake\r\n _startStake(stakedPrinciple, stakedDays, possibleStars);\r\n \r\n\r\n // the principle is burned from token supply, and the possible interest is pulled from the endowmentSupply\r\n _endowmentSupply = _endowmentSupply - possibleInterest; \r\n \r\n \r\n // Add to global counter\r\n // Add principle only\r\n g_stakedPrincipleStars += stakedPrinciple;\r\n // Add all possible interest and principle to stakedStars.\r\n g_stakedStars += possibleStars;\r\n // Stake is official Ready to go\r\n }\r\n\r\n // @dev Public Function: Scrape stake\r\n // @dev This will calculate the eligible days since the previous stake\r\n // and mint the interest back to the user. This will also recalculate\r\n // the possible amount of interest.\r\n // @param uint256 stakeIndex the index of the stake based on the order of active stakes\r\n // @param uint256 myStakeId The stake\u0027s id that is unique to the stake\r\n function scrapeStake(uint256 stakeIndex, uint256 myStakeId)\r\n external\r\n {\r\n PermStake[] storage permStakes = Stakes[msg.sender];\r\n require(permStakes.length != 0, \"Empty stake list\");\r\n require(stakeIndex \u003c permStakes.length, \"stakeIndex invalid\");\r\n \r\n // load a copy of temporary stake \r\n TempStake memory stake = TempStake(0,0,0,0,0,0,0);\r\n\r\n _loadStake(permStakes[stakeIndex], myStakeId, stake);\r\n // load up the stake reference also\r\n PermStake storage permStakeRef = Stakes[msg.sender][stakeIndex];\r\n // Defaults\r\n uint256 previousInterest = stake._scrapedInterest;\r\n uint256 previousPossibleStars = stake._possibleStars;\r\n // Calculate Days\r\n uint[6] memory calcDays = _calculateStakeDays(stake._startDay, stake._stakedDays, stake._scrapeDay);\r\n // Returns Calculated Days in an array like below\r\n // 0 curDay - Current Day\r\n // 1 startDay - Start Day\r\n // 2 scrapeDay - The previous day this was scraped - (default to startDay, and is set when scraped)\r\n // 3 endOfStakeDay - The final day of this stake (startDay + stakedDays or total days in stake)\r\n // 4 interestDays - Days that are used to CALCULATE INTEREST\r\n // 5 possibleDays - (endOfStakeDays - currentDay)\r\n // scrapeServedDays // days that are interest bearing days\r\n uint256 currentInterest = 0;\r\n uint256 lostInterest = 0;\r\n uint256 newPossibleInterest = 0;\r\n uint256 curDay = calcDays[0];\r\n // the stake start day must be \u003c the currentDay\r\n require(curDay \u003e stake._startDay, \"Scraping is not allowed, stake must start first\");\r\n // make sure the curDay is within the scope of \"scrapeable days\"\r\n require(curDay \u003c= calcDays[3], \"Scraping is not allowed, must end stake\");\r\n\r\n \r\n // Scraping is allowed only if the curDay is greater than the scrapeDay\r\n //PER SEI-04 - to save possible gas for the user\r\n require(curDay \u003e calcDays[2], \"Scraping is not allowed until 1 or more staked days has completed\");\r\n\r\n // we will require this check so it doesn\u0027t waste resource by running these other calcs\r\n // you can\u0027t scrape twice on the same day so current Day must greater than previous scraped day\r\n // will equal 0 or previous accumulated amount\r\n previousInterest = stake._scrapedInterest;\r\n // total possible interest that was reserved for your stake\r\n // previousPossibleStars = stake._possibleStars; //includes principle\r\n // Calculate total based on interestDays\r\n currentInterest = _calculateInterest(stake._stakedPrinciple, calcDays[4]);\r\n // Calculate NEW possibleInterest based on EndofStake Days - currentDay\r\n newPossibleInterest = _calculateInterest(stake._stakedPrinciple, (calcDays[3]-calcDays[0]));\r\n uint newPossibleInterestPlusPrinciple = newPossibleInterest + stake._stakedPrinciple;\r\n // Lost interest = the interest you could have had - what you have now\r\n // What I have: \r\n // previousPossibleStars - (includes principle)\r\n // newPossibleInterestPlusPrinciple - newPossibleInterest also include principle\r\n // currentInterest - what we are minting for interest\r\n // just in case the previous possible interest is less than the new possible interest\r\n uint previousStarsAndCurrentInterest = previousPossibleStars \u003e currentInterest ? (previousPossibleStars - currentInterest) : 0;\r\n if (previousStarsAndCurrentInterest \u003e newPossibleInterestPlusPrinciple) {\r\n // lost interest gets minted back to the OA\r\n lostInterest = previousStarsAndCurrentInterest - newPossibleInterestPlusPrinciple;\r\n }\r\n // Now do the work based on values above calculate actual payout\r\n // penalties do not happen here, because there is a force closed function.\r\n // If there is accrued interest, send this back to the user\r\n // If there is no accrued interest, then nothing changes and all stays the same.\r\n if (currentInterest != 0) {\r\n\r\n // Mint this back to message sender\r\n _mint(msg.sender, currentInterest);\r\n \r\n // Mint lost interest back to the endowment supply\r\n if (lostInterest \u003e 0) {\r\n _endowmentSupply = _endowmentSupply + lostInterest;\r\n }\r\n\r\n\r\n // Set the total amount of accrued interest\r\n stake._scrapedInterest = previousInterest + currentInterest;\r\n // set the new possible interest in the stake... should continually get smaller and smaller\r\n stake._possibleStars = newPossibleInterestPlusPrinciple;\r\n // Set the Scrape day to today\r\n stake._scrapeDay = curDay;\r\n //update the current stake to the new values\r\n _updateStake(permStakeRef, stake);\r\n // Emit the stake scrape event\r\n emitScrapeEvent(\r\n stake._stakeId,\r\n uint256(calcDays[4]),\r\n uint256(previousInterest),\r\n previousPossibleStars,\r\n stake._scrapedInterest,\r\n newPossibleInterest\r\n );\r\n // update global values\r\n // Adds back previous possible interest to the global variable\r\n g_stakedStars -= previousPossibleStars;\r\n // Removes the new current possible interest \r\n g_stakedStars += newPossibleInterestPlusPrinciple;\r\n }\r\n }\r\n\r\n // @dev Public Function: End the Stake: This will calculate the amount of\r\n // interest, mint it back to the user, and remove the stake from the stakeList Map\r\n // @param uint256 stakeIndex the index of the stake based on order and may change based on active stakes\r\n // @param uint256 myStakeId The stake\u0027s id\r\n function endStake(uint256 stakeIndex, uint256 myStakeId)\r\n external\r\n {\r\n PermStake[] storage permStakes = Stakes[msg.sender];\r\n require(permStakes.length != 0, \"Stake List is Empty\");\r\n require(stakeIndex \u003c permStakes.length, \"not a valid stakeIndex\");\r\n \r\n // get temporary stake into memory\r\n TempStake memory stake = TempStake(0,0,0,0,0,0,0);\r\n\r\n _loadStake(permStakes[stakeIndex], myStakeId, stake);\r\n // Defaults\r\n uint256 servedDays = 0;\r\n uint256 stakeTotal;\r\n uint256 interestAccrued = 0;\r\n uint256 penalty = 0;\r\n // Calculate Days - returns Calculated Days in an array like below\r\n // 0 curDay - Current Day\r\n // 1 startDay - Start Day\r\n // 2 scrapeDay - The previous day this was scraped - (default to startDay, and is set when scraped)\r\n // 3 endOfStakeDay - The final day of this stake (startDay + stakedDays or total days in stake)\r\n // 4 interestDays - Days that are used to CALCULATE INTEREST\r\n // 5 possibleDays - (endOfStakeDays - currentDay)\r\n uint[6] memory calcDays = _calculateStakeDays(stake._startDay, stake._stakedDays, stake._scrapeDay);\r\n // Stake Insurance - in case someone makes a mistake\r\n // if The stake has not started, then mint all possible back to the OA (removed)\r\n // if The stake has not started, then mint all possible back to the Endowment Supply\r\n if (calcDays[0] \u003c calcDays[1]) {\r\n\r\n // Add the possible stars back to the endowment supply (minus the principle of course)\r\n _endowmentSupply = _endowmentSupply + (stake._possibleStars - stake._stakedPrinciple);\r\n\r\n \r\n // make sure that stakeTotal and penalty = 0 \r\n stakeTotal = 0;\r\n penalty = 0;\r\n // Add principle back to user\r\n _mint(msg.sender, stake._stakedPrinciple);\r\n // remove this from global stats\r\n g_stakedStars -= stake._possibleStars;\r\n \r\n\r\n // remove from the global principle stats\r\n g_stakedPrincipleStars -= stake._stakedPrinciple;\r\n \r\n } else {\r\n // served days is day from start day\r\n servedDays = calcDays[0] - calcDays[1];\r\n // calculate stake performance\r\n (stakeTotal, interestAccrued, penalty) = _calculateStakeTotal(stake);\r\n\r\n // Check for penalties\r\n if (penalty \u003e 0) {\r\n // Zero interest gets returned\r\n // Possible Interest should get sent back to Endowment Supply\r\n _endowmentSupply += (stake._possibleStars - stake._stakedPrinciple);\r\n \r\n // Update global variables - to keep track of penalizedStars\r\n g_penalizedStars += penalty;\r\n\r\n // Remove possible stars from the global variable g_stakedStars\r\n if(g_stakedStars \u003e= (stake._possibleStars)){\r\n g_stakedStars -= (stake._possibleStars);\r\n }\r\n \r\n // Remove the principle amount from global variable g_stakedPrincipleStars\r\n if(g_stakedPrincipleStars \u003e= stake._stakedPrinciple){\r\n g_stakedPrincipleStars -= stake._stakedPrinciple;\r\n }\r\n\r\n } else {\r\n // This is a good stake\r\n // There are no possible stars anymore\r\n // There is only interestAccrued, so remove that from global variable g_stakedStars\r\n\r\n // Remove all possible stars from g_stakedstars\r\n if (g_stakedStars \u003e= interestAccrued){\r\n g_stakedStars -= interestAccrued; \r\n }\r\n // Possible Stars has Principle Included... InterestAccrued does not.\r\n // so we need to back out the principle also\r\n if (g_stakedStars \u003e= stake._stakedPrinciple){\r\n g_stakedStars -= stake._stakedPrinciple; \r\n }\r\n\r\n // NOTE: Stake Total is Both the interestAccrued + Principle and that \r\n // goes back to the user\r\n\r\n // Speaking of principle, let\u0027s also remove it from g_stakedPrincipleStars\r\n if(g_stakedPrincipleStars \u003e= stake._stakedPrinciple){\r\n g_stakedPrincipleStars -= stake._stakedPrinciple; \r\n }\r\n }\r\n\r\n // Calculations are done, so let\u0027s mint back to the user,\r\n // Stake total could equal principle + stars, or principle - penalty\r\n if (stakeTotal != 0) {\r\n // We do not mint penalties back\r\n // This amount should be principle + any Interest Earned\r\n // OR if penalties, then this is principle minus penalties\r\n \r\n _mint(msg.sender, stakeTotal);\r\n \r\n // minted stake total back to user\r\n // ready to end the stake, so continue\r\n\r\n }\r\n } // end else\r\n \r\n // emit the stake end event and remove the stake from Stakes\r\n emit EndStake(\r\n msg.sender,\r\n stake._stakeId,\r\n uint256(3), // stake event id\r\n uint256(calcDays[3]),\r\n uint256(stake._stakedPrinciple),\r\n uint256(stake._possibleStars),\r\n uint256(stake._scrapedInterest),\r\n uint256(penalty),\r\n uint256(stakeTotal)\r\n );\r\n // Remove the Stake from your stake list\r\n uint256 lastIndex = permStakes.length - 1;\r\n // If it\u0027s the last element, then skip\r\n if (stakeIndex != lastIndex) {\r\n permStakes[stakeIndex] = permStakes[lastIndex];\r\n }\r\n permStakes.pop();\r\n // stake remove is finished - remove from the the global Active Stakes Count\r\n\r\n g_stakedCount = g_stakedCount - 1;\r\n }\r\n\r\n // @dev get the allocated supply of the token\r\n function allocatedSupply()\r\n external\r\n view\r\n returns (\r\n uint256\r\n )\r\n {\r\n return _allocatedSupply();\r\n }\r\n\r\n // @dev Public Function: Returns the current Day since the launch date\r\n // @return current day number\r\n function currentDay()\r\n external\r\n view\r\n returns (\r\n uint\r\n )\r\n {\r\n return _currentDay();\r\n }\r\n\r\n // @dev Reports Global gives a list of global variables for reporting\r\n // returns:\r\n // uint256 staked_stars, sum of interest + principle\r\n // uint256 staked_principle_stars // total staked based only on principle, what users actually staked,\r\n // uint256 total_supply, \r\n // uint256 allocated_supply,\r\n // uint256 penalized_stars,\r\n // uint256 current_day,\r\n // uint256 latest_stake_id\r\n // uint256 staked_count total active stakes + and - at the end of startStake and endStake\r\n function reportGlobals()\r\n external\r\n view\r\n returns (\r\n uint256 staked_stars, \r\n uint256 staked_principle_stars,\r\n uint256 total_supply,\r\n uint256 allocated_supply,\r\n uint256 penalized_stars,\r\n uint256 current_day,\r\n uint256 latest_stake_id,\r\n uint256 staked_count,\r\n uint256 endowment_supply\r\n )\r\n {\r\n staked_stars = g_stakedStars;\r\n staked_principle_stars = g_stakedPrincipleStars;\r\n \r\n\r\n total_supply = super.totalSupply() + g_stakedStars + _endowmentSupply;\r\n \r\n\r\n allocated_supply = _allocatedSupply();\r\n penalized_stars = g_penalizedStars;\r\n current_day = _currentDay();\r\n latest_stake_id = g_latestStakeId;\r\n staked_count = g_stakedCount;\r\n endowment_supply = _endowmentSupply;\r\n\r\n return (staked_stars, staked_principle_stars, total_supply, allocated_supply, penalized_stars, current_day, latest_stake_id, staked_count, endowment_supply);\r\n }\r\n\r\n // @dev Public Function: Return the count of stakes in the stakeList map\r\n // @param address userAddress - address of staker\r\n function countStakes(address userAddress)\r\n external\r\n view\r\n returns (\r\n uint256\r\n )\r\n {\r\n return Stakes[userAddress].length;\r\n }\r\n\r\n // Calculate Days\r\n // Returns Calculated Days in an array like below\r\n // 0 curDay - Current Day\r\n // 1 startDay - Start Day\r\n // 2 scrapeDay - The previous day this was scraped - (default to startDay, and is set when scraped)\r\n // 3 endOfStakeDay - The final day of this stake (startDay + stakedDays or total days in stake)\r\n // 4 interestDays - Days that are used to CALCULATE INTEREST\r\n // 5 possibleDays - (endOfStakeDays - currentDay)\r\n // @param uint256 tempStartDay\r\n // @param uint256 tempStakedDays\r\n // @param uint256 tempScrapeDay\r\n function calculateStakeDays(uint256 tempStartDay, uint256 tempStakedDays, uint256 tempScrapeDay)\r\n external\r\n view\r\n returns (\r\n uint[6] memory\r\n )\r\n {\r\n uint[6] memory calcDays = _calculateStakeDays(tempStartDay, tempStakedDays, tempScrapeDay);\r\n return (calcDays);\r\n }\r\n\r\n // @dev Calculate the interest of a scenario\r\n // @param uint256 stakedPrinciple The amount of principle for the stake\r\n // @param uint256 stakedDays the number of days to commit to a stake\r\n function calculateInterest(uint256 stakedPrinciple, uint256 stakedDays)\r\n external\r\n pure\r\n returns(\r\n uint256 interest\r\n )\r\n {\r\n _assurePrincipleAndStakedDaysAreValid(stakedPrinciple, stakedDays);\r\n interest = _calculateInterest(stakedPrinciple, stakedDays);\r\n\r\n return (interest);\r\n }\r\n\r\n // @dev This give the totalsupply plus the totalstaked. Total staked also\r\n // includes the interest that may be accrued from time and principle.\r\n // @return Allocated Supply in Stars\r\n function _allocatedSupply()\r\n private\r\n view\r\n returns (\r\n uint256\r\n )\r\n {\r\n\r\n return super.totalSupply() + g_stakedStars;\r\n\r\n }\r\n\r\n // @dev Private function that calculates the current day from day 1\r\n // @return Current day number\r\n function _currentDay()\r\n internal\r\n view\r\n returns (\r\n uint256 temp_currentDay\r\n )\r\n {\r\n return (block.timestamp - LAUNCH_TIME) / 1 days;\r\n }\r\n\r\n // @dev Private Function to load the stake into memory\r\n // Takes stake store and pushes the values into it\r\n // @param PermStake stakeRef reference of values to get\r\n // @param uint256 myStakeId or the globalStakeId\r\n // @param TempStake stake to load into memory as st or current stake\r\n // Requirements:\r\n // `stakeId must exist in the list`, so both the position (zero index AND stakeID must be correct)\r\n function _loadStake(PermStake storage stakeRef, uint256 myStakeId, TempStake memory stake)\r\n internal\r\n view\r\n {\r\n //require current stake index is valid\r\n require(myStakeId == stakeRef.stakeId, \"myStakeId not in stake\");\r\n stake._stakeId = stakeRef.stakeId;\r\n stake._stakedPrinciple = stakeRef.stakedPrinciple;\r\n stake._startDay = stakeRef.startDay;\r\n stake._scrapeDay = stakeRef.scrapeDay;\r\n stake._stakedDays = stakeRef.stakedDays;\r\n stake._scrapedInterest = stakeRef.scrapedInterest;\r\n stake._possibleStars = stakeRef.possibleStars;\r\n }\r\n\r\n // @dev Private Function for updating the stake\r\n // returns nothing, it just updates the stake passed to it\r\n // @param PermStake stakeRef the reference to the original mapping of the stake store\r\n // @param TempStake stake the new instance to update from\r\n function _updateStake(PermStake storage stakeRef, TempStake memory stake)\r\n internal\r\n {\r\n stakeRef.stakeId = stake._stakeId;\r\n stakeRef.stakedPrinciple = uint256(stake._stakedPrinciple);\r\n stakeRef.startDay = uint256(stake._startDay);\r\n stakeRef.scrapeDay = uint256(stake._scrapeDay);\r\n stakeRef.stakedDays = uint256(stake._stakedDays);\r\n stakeRef.scrapedInterest = uint256(stake._scrapedInterest);\r\n stakeRef.possibleStars = uint256(stake._possibleStars);\r\n }\r\n\r\n // @dev Internal Function Start a Stake Internal Function\r\n // @param uint256 stakedPrinciple\r\n // @param uint256 stakedDays length of days in the stake\r\n // @param uint256 possibleStars allocated total for this stake\r\n function _startStake(\r\n uint256 stakedPrinciple,\r\n uint256 stakedDays,\r\n uint256 possibleStars\r\n )\r\n private\r\n {\r\n // Get the current day\r\n uint256 cday = _currentDay();\r\n // starts the next day\r\n uint256 startDay = cday + 1;\r\n // automaticall set scrape day to start day\r\n uint256 scrapeDay = startDay;\r\n // Burn the tokens from the sender\r\n _burn(msg.sender, stakedPrinciple);\r\n // Get the global stake id and create the stake\r\n uint256 newStakeId = ++g_latestStakeId;\r\n // push the new stake into the sender\u0027s stake list\r\n Stakes[msg.sender].push(\r\n PermStake(\r\n newStakeId,\r\n stakedPrinciple,\r\n startDay,\r\n scrapeDay,\r\n stakedDays,\r\n uint256(0),\r\n possibleStars\r\n )\r\n );\r\n // emit the stake start event\r\n emit StartStake(\r\n msg.sender,\r\n uint256(newStakeId),\r\n uint256(1),\r\n startDay,\r\n stakedDays,\r\n stakedPrinciple,\r\n possibleStars\r\n );\r\n // Add to the global Active Stakes\r\n g_stakedCount = g_stakedCount + 1;\r\n }\r\n\r\n // @dev Require and validate the basic min/max stake parameters\r\n // @param uint256 principle\r\n // @param uint256 servedDays\r\n function _assurePrincipleAndStakedDaysAreValid(uint256 principle, uint256 servedDays)\r\n internal\r\n pure\r\n {\r\n // validate the stake days and principle \r\n require(servedDays \u003e= MIN_STAKE_DAYS, \"Stake length is too small\");\r\n require(servedDays \u003c= MAX_STAKE_DAYS, \"Stake length is too large\");\r\n require(principle \u003e= MIN_STAKE_AMOUNT, \"Principle is not high enough\");\r\n require(principle \u003c= MAX_STAKE_AMOUNT, \"Principle is too high\");\r\n }\r\n\r\n // @dev Calculate Interest Function\r\n // @notice This calculates the amount of interest for the number of servedDays.\r\n // This divides up served days into buckets of yearly increments based on 365.25 days\r\n // Then applies the rate of return based on the interestTable.\r\n // @param uint256 principle - the principle to apply\r\n // @param uint256 servedDays - the number of days to calculate.\r\n function _calculateInterest(uint256 principle, uint256 servedDays)\r\n internal\r\n pure\r\n returns(\r\n uint256 totalInterest\r\n )\r\n {\r\n // year is 365.25, but we need to multiply by 100 to keep it integer\u0027istic\r\n uint256 workingDays = servedDays * YEARPRECISION;\r\n // This will fill up based on the days.\r\n // Daily Interest Table is based on 18 decimals so\r\n uint[23] memory dailyInterestTable = _getDailyInterestTable();\r\n // Set an index to increment for the while loops\r\n uint256 workingidx = 0;\r\n uint256 appliedInterestRate = 0;\r\n uint256 tempInterestAmount = 0;\r\n uint256 current = 0;\r\n\r\n while (workingidx \u003c MAX_STAKE_YEARS) {\r\n if (workingDays \u003e YEARDIVIDER) {\r\n current = YEARDIVIDER;\r\n workingDays -= YEARDIVIDER;\r\n } else {\r\n // x is less than than MaxStakeYears, so set the remainder to this.\r\n current = workingDays; // this will give the days left over\r\n workingDays = 0;\r\n }\r\n // apply this years interest rate to the days inside that year\r\n appliedInterestRate = dailyInterestTable[workingidx];\r\n \r\n // days (36525) * interest for this year divided by 100 multiplied by principle then divide py precision\r\n \r\n // tempInterestAmount = (((current * appliedInterestRate) / YEARPRECISION) * principle) / (PRECISION * PRECISION); //36 decimals\r\n \r\n uint tempInterestAmountNumerator = 0;\r\n tempInterestAmountNumerator = ((current * appliedInterestRate) * principle) / YEARPRECISION;\r\n tempInterestAmount = tempInterestAmountNumerator / (PRECISION * PRECISION); //36\r\n\r\n // apply the principle and add it to the running total of interest\r\n totalInterest += tempInterestAmount; // divide by 100 because of our days... days return as 36525 and not 365.25\r\n workingidx = workingidx + 1; // keep running for the full 22 years.\r\n if (workingDays == 0) {\r\n break;\r\n }\r\n }\r\n\r\n return (totalInterest);\r\n }\r\n\r\n // @dev CalculatePenalty\r\n // @notice This calculates the penalty if there is one.\r\n // The rules for penalty:\r\n // - if a stake is less than 50% complete, then you get 50% of your principle returned\r\n // - if a stake is greater than 50%, you get the percentage back for each day from 100%\r\n // example: Stake is 60% complete. You should receive 60% of your principle back.\r\n // @param TempStake stake the stake to calculate penalties for\r\n function _calculatePenalty(TempStake memory stake)\r\n internal\r\n view\r\n returns(\r\n uint256 penaltyAmount\r\n )\r\n {\r\n // calculate the penalty for forcing and end stake\r\n uint[6] memory calcDays = _calculateStakeDays(stake._startDay, stake._stakedDays, stake._scrapeDay);\r\n uint256 pct = 0;\r\n uint256 pctleft = 0;\r\n uint256 pctprecision = 100;\r\n uint256 daysSinceStart = 0;\r\n uint256 totalStakeDays = stake._stakedDays * pctprecision;\r\n // Check served days to make sure it\u0027s at least 1\r\n if (totalStakeDays \u003c= 0) {\r\n totalStakeDays = 1 * pctprecision; //sets minimum amt for calculation \r\n }\r\n if (calcDays[0] \u003c calcDays[1]) {\r\n // should never happen... condition handled in parent\r\n } else if (calcDays[0] == calcDays[1]) {\r\n daysSinceStart = (1 * pctprecision);\r\n } else {\r\n // number of days since start day\r\n daysSinceStart = (calcDays[0] - calcDays[1]) * pctprecision;\r\n }\r\n // basic pct made here\r\n pct = (daysSinceStart * pctprecision) / totalStakeDays;\r\n // decision time - anything 50 or less is counted as 50\r\n if (pct \u003c= 50) {\r\n pctleft = 50;\r\n } else if (pct \u003e 50 \u0026\u0026 pct \u003c 100) {\r\n pctleft = 100 - pct;\r\n } else {\r\n pctleft = 0;\r\n }\r\n // calculate penalties from pctleft\r\n penaltyAmount = (stake._stakedPrinciple * pctleft) / 100;\r\n // This cannot be less than zero\r\n if (penaltyAmount \u003c= 0) {\r\n penaltyAmount = 0;\r\n }\r\n // this should never exceed the amount, but just in case lets test for it anyway\r\n if (penaltyAmount \u003e stake._stakedPrinciple) {\r\n penaltyAmount = stake._stakedPrinciple;\r\n }\r\n\r\n return (penaltyAmount);\r\n }\r\n\r\n // @param TempStake stake\r\n function _calculateStakeTotal(TempStake memory stake)\r\n internal\r\n view\r\n returns (\r\n uint256 stakeTotal,\r\n uint256 currentInterest,\r\n uint256 penalty\r\n )\r\n {\r\n penalty = 0;\r\n stakeTotal = 0; // total return of the stake\r\n currentInterest = 0;\r\n uint256 appliedPrinciple = 0;\r\n uint256 previousInterest = stake._scrapedInterest;\r\n uint[6] memory calcDays = _calculateStakeDays(stake._startDay, stake._stakedDays, stake._scrapeDay);\r\n // Returns Calculated Days in an array like below\r\n // 0 curDay - Current Day\r\n // 1 startDay - Start Day\r\n // 2 scrapeDay - The previous day this was scraped - (default to startDay, and is set when scraped)\r\n // 3 endOfStakeDay - The final day of this stake (startDay + stakedDays or total days in stake)\r\n // 4 interestDays - Days that are used to CALCULATE INTEREST\r\n // 5 possibleDays - (endOfStakeDays - currentDay)\r\n // if InterestDays is less than staked days\r\n // if (calcDays[4] \u003c stake._stakedDays) {\r\n // if currentDay is less than endofstake day\r\n if (calcDays[0] \u003c calcDays[3]) {\r\n // calculate the penalty if any\r\n penalty = _calculatePenalty(stake);\r\n if (penalty \u003e stake._stakedPrinciple) {\r\n // this should never happen but if it does, then set to 50% of the principle\r\n appliedPrinciple = stake._stakedPrinciple / 2;\r\n } else {\r\n // this should return a \"prorated\" amount of principle from 51% to 99%\r\n appliedPrinciple = (stake._stakedPrinciple - penalty);\r\n }\r\n // A broken stake will only give you the portion of your principle back, not your interest.\r\n stakeTotal = appliedPrinciple;\r\n currentInterest = 0;\r\n } else {\r\n // There is no penalty if stake is completed\r\n currentInterest = _calculateInterest(stake._stakedPrinciple, calcDays[4]);\r\n // Set the total amount of accrued interest\r\n stake._scrapedInterest = previousInterest + currentInterest;\r\n // stake is finished, so we set this to zero\r\n stake._possibleStars = 0;\r\n // total amount of stake to be returned to user\r\n stakeTotal = currentInterest + stake._stakedPrinciple;\r\n penalty = 0;\r\n }\r\n }\r\n\r\n // This returns days in this order:\r\n // 0 curDay - Current Day\r\n // 1 startDay - Start Day\r\n // 2 scrapeDay - The previous day this was scraped - (default to startDay, and is set when scraped)\r\n // 3 endOfStakeDay - The final day of this stake (startDay + stakedDays or total days in stake)\r\n // 4 interestDays - Days that are used to CALCULATE INTEREST\r\n // 5 possibleDays - (endOfStakeDays - currentDay)\r\n // @dev Calculate Days\r\n // @notice This returns an array of calculated days of your stake based on the current day.\r\n // @param uint256 startDay\r\n // @param uint256 stakedDays length of days in the stake\r\n // @param uint256 scrapeDay\r\n function _calculateStakeDays(uint256 startDay, uint256 stakedDays, uint256 scrapeDay)\r\n internal\r\n view\r\n returns (uint[6] memory)\r\n {\r\n // if the stakedDays is less than the minimum, throw an error\r\n require(stakedDays \u003e= MIN_STAKE_DAYS, \"stake days must be greater than 1\");\r\n uint256 curDay = _currentDay(); //ex. day 25\r\n uint256 endOfStakeDay = startDay + stakedDays; //ex. Day 52\r\n // find the higher of the two days ( startDay or a more recent scrapeDay )\r\n uint256 targetStartDay = scrapeDay \u003e= startDay ? scrapeDay : startDay;\r\n // the possible interest bearing days\r\n uint256 possibleDays = endOfStakeDay - targetStartDay;\r\n uint256 interestDays = 0;\r\n // if the currentDay is greater than the end stake day, we subtract:\r\n // targetStartDay from the endOfStakeDay giving us the interest days.\r\n // otherwise we take the currentDay and subtract the same targetStartDay because it\u0027s still an active stake.\r\n if (targetStartDay \u003e curDay) {\r\n // probably a new stake so we\u0027ll default to zero\r\n // this also keeps this from subtracting current day from target day\r\n // and for the beginning of a stake, it will be a negative 1\r\n interestDays = 0;\r\n } else {\r\n interestDays = curDay \u003e= endOfStakeDay ? (endOfStakeDay - targetStartDay) : (curDay - targetStartDay);\r\n }\r\n\r\n return [\r\n uint(curDay),\r\n startDay,\r\n scrapeDay,\r\n endOfStakeDay,\r\n interestDays,\r\n possibleDays\r\n ];\r\n }\r\n\r\n // @dev getDailyInterestTable\r\n // @notice This table has precalculated values for the 22 year buckets that calculate the interest\r\n // based on the number of days you have within each year.\r\n function _getDailyInterestTable()\r\n internal\r\n pure\r\n returns (uint[23] memory tableOfInterest)\r\n {\r\n // These values are precalculated and will never change once this is made live.\r\n // based on 36 decimals\r\n tableOfInterest = [\r\n uint(136892539356605065023956194387405), \r\n 164271047227926078028747433264887, \r\n 219028062970568104038329911019849, \r\n 301163586584531143052703627652292, \r\n 410677618069815195071868583162217, \r\n 547570157426420260095824777549623, \r\n 711841204654346338124572210814510, \r\n 903490759753593429158110882956878, \r\n 1122518822724161533196440793976728, \r\n 1368925393566050650239561943874058, \r\n 1642710472279260780287474332648870, \r\n 1943874058863791923340177960301163, \r\n 2272416153319644079397672826830937, \r\n 2628336755646817248459958932238193, \r\n 3011635865845311430527036276522929, \r\n 3422313483915126625598904859685147, \r\n 3860369609856262833675564681724845, \r\n 4325804243668720054757015742642026, \r\n 4818617385352498288843258042436687, \r\n 5338809034907597535934291581108829, \r\n 5886379192334017796030116358658453, \r\n 6461327857631759069130732375085557, \r\n 0\r\n ];\r\n\r\n return (tableOfInterest);\r\n }\r\n\r\n\r\n /**\r\n * @dev See {IERC20-totalSupply}.\r\n */\r\n function totalSupply() public view override returns (uint256) {\r\n // The Endowment Supply is the total amount of token available for staking rewards to the stakers.\r\n // A proper representation of Total Supply is the Endowment Supply + what is in the ERC20 total supply\r\n uint totSupply = super.totalSupply() + g_stakedStars + _endowmentSupply;\r\n\r\n return (totSupply);\r\n }\r\n /**\r\n * @dev Follows same convention as IERC20-totalsupply\r\n */\r\n function endowmentSupply() public view returns (uint256) {\r\n // The Endowment Supply is the total amount of token available for staking rewards to the stakers.\r\n // A proper representation of Total Supply is the Endowment Supply + what is in the ERC20 total supply\r\n return _endowmentSupply;\r\n } \r\n \r\n /**\r\n * @dev Follows same convention as IERC20-totalsupply\r\n */\r\n function originalSupply() public view returns (uint256) {\r\n // The Endowment Supply is the total amount of token available for staking rewards to the stakers.\r\n // A proper representation of Total Supply is the Endowment Supply + what is in the ERC20 total supply\r\n return (super.totalSupply());\r\n }\r\n\r\n}"},"TEXAN.sol":{"content":"/// SPDX-License-Identifier: UNLICENSED\r\n// @title Stakeable Endowment Token\r\n// @author Origin Address\r\n// @notice This contract is proprietary and may not be copied or used without permission.\r\n\r\npragma solidity ^0.8.13;\r\n\r\nimport \"./StakableEndowmentToken.sol\";\r\n\r\ncontract TEXAN is StakableEndowmentToken {\r\n\r\n constructor() {\r\n setNameAndSymbol(\"TEXAN Token\", \"TEXAN\");\r\n\r\n // NOTE: This has been modified so the original Owner Address does NOT hold\r\n // the supply. The Endowment Supply holds 97T stars for available rewards \r\n // and is no longer held by the OA account. We think this is good for security purposes.\r\n //\r\n // These 3T tokens are for initial circulation. (most will be staked)\r\n uint intitialTotalSupply = 3 * 1e30; // 3 Trillion Tokens ( 1e12 * decimals(1e18)) \r\n\r\n _mint(msg.sender, intitialTotalSupply);\r\n }\r\n\r\n receive()\r\n payable\r\n external\r\n {\r\n uint256 fbfail = 1;\r\n require(fbfail == 0, string(abi.encodePacked(name(), \": You can not send ETH to this contract!\")));\r\n }\r\n\r\n fallback() external {}\r\n}"}}