Description:
Multi-signature wallet contract requiring multiple confirmations for transaction execution.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
{{
"language": "Solidity",
"sources": {
"src/Deployer.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/*
☞ https://ethos.vision
???? https://x.com/Ethereum_OS
✌︎ https://t.me/ethosportal
Welcome to the Ethereum Operating System — the first-of-its-kind revenue generating DeFi pumpware
built as a social DeFi sandbox that is filled with composable elements so you can create, trade,
communicate, and participate—all in one place.
@
@@:
@@@::
==@@@::::
===@@@:::::
===+@@+::::::
====@@@::::::::
=====@@@:::::::::
======@@@::::::::::
=======@@@:::::::::::
=======*@@+::::::::::::
========@@@::::::::::::::
==========@@@::::::::::::::::
===========@@@:::::::::::::::::
============@@@::::::::::::::::::
============*@@=:::::::::::::::::::
=============@@@:::::::::::::::::::::
=====@@@======@@@::::::::@@@:::::::::::
======@@@======@@@::::::::@@@::::::::::::
=======@@@======@@@::::::::@@@:::::::::::::
=================@@=:::::::::::::::::::::::::
==================%@@::::::::::::::::::::::::::::
===================@@@:::::::::::::::::::::::::::::
====================@@@::::::::::::::::::::::::::::::
=====================@@@:::::::::::::::::::::::::::::::
=====================+@@-::::::::::::::::::::::::::::::::
======================@@@@@@@@@@@@@@*::::::::::::::::::::::
=======================@@@@@@@@@@@@@@::::::::::::::::::::::::
===================================@@@:::::::::::::::::::::::::
=================================@@@:::::::::::::::::::::::
=========@@@@===================@@@::::::::@@@*::::::::::
=========@@@@@@@==============*@@:::::%@@@@@:::::::::::
===========@@@@@@@@@@@#*+=+*@@@@@@@@@@@-:::::::::::
==============+@@@@@@@@@@@@@@@@@@@:::::::::::::::
==========================@@@::::::::::::::::::
========================@@@::::::::::::::::
======================@@@::::::::::::::::
=====================@@@:::::::::::::::
===================@@@:::::::::::::
==================@@@::::::::::::
================*@@=:::::::::::
==============@@@::::::::::
=============@@@:::::::::
============@@@::::::::
==========@@#::::::
========@@@::::::
=======@@@:::::
=====@@@:::
====@@@::
==*@@-:
=@@@:
@
@@@
@@@@@@@@@@@@@@@@@@@ @@@@@@@ ======= ========
@@@@@@@@@@@@@@@@@@ @@@@@ ==== ===== ===== =====
@@@@@ @@ @@@@ ===== ==== ==== ===
@@@@@ @ @@@@ ==== ===== ==== ===
@@@@@ @@@@ ==== ===== ==== ==
@@@@@ @@ @@@@ ===== ===== =====
@@@@@ @ @@@@ @@@@ @ ===== ===== =======
@@@@@ @@ @@@@@@@@@@@@ @@@@ @@@@@@@@ ===== ===== =========
@@@@@@@@@@@@@ @@@@ @@@@@@ @@@@@ ===== ===== =========
@@@@@ @@ @@@@ @@@@@ @@@@@ ===== ===== =========
@@@@@ @@ @@@@ @@@@ @@@@ ===== ===== ========
@@@@@ @@@@ @@@@ @@@@ ====== ===== ======
@@@@@ @@@@ @@@@ @@@@ ===== ===== =====
@@@@@ @@@@ @@@@ @@@@ ===== ===== == =====
@@@@@ @@ @@@@ @@@@ @@@@ ==== ===== === =====
@@@@@ @@@ @@@@@ @@@@ @@@@ ===== ==== ==== ====
@@@@@@@@@@@@@@@@@@ @@@@@@@@@@ @@@@@@ @@@@@@ ===== ==== ===== =====
@@@@@@@@@@@@@@@@@@@@ @@@@@@ @@@@@@@@@ @@@@@@@@@ ========== =========
*/
import "./EOS20.sol";
contract Deployer{
function createTokenViaInterface(string memory name, string memory symbol, address _ethOs, bytes32 salt) public returns (address) {
EOS20 newToken = salt == 0 ? new EOS20(name, symbol, _ethOs) : new EOS20{salt: salt}(name, symbol, _ethOs);
return address(newToken);
}
}"
},
"src/EOS20.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/*
☞ https://ethos.vision
???? https://x.com/Ethereum_OS
✌︎ https://t.me/ethosportal
Welcome to the Ethereum Operating System — the first-of-its-kind revenue generating DeFi pumpware
built as a social DeFi sandbox that is filled with composable elements so you can create, trade,
communicate, and participate—all in one place.
@
@@:
@@@::
==@@@::::
===@@@:::::
===+@@+::::::
====@@@::::::::
=====@@@:::::::::
======@@@::::::::::
=======@@@:::::::::::
=======*@@+::::::::::::
========@@@::::::::::::::
==========@@@::::::::::::::::
===========@@@:::::::::::::::::
============@@@::::::::::::::::::
============*@@=:::::::::::::::::::
=============@@@:::::::::::::::::::::
=====@@@======@@@::::::::@@@:::::::::::
======@@@======@@@::::::::@@@::::::::::::
=======@@@======@@@::::::::@@@:::::::::::::
=================@@=:::::::::::::::::::::::::
==================%@@::::::::::::::::::::::::::::
===================@@@:::::::::::::::::::::::::::::
====================@@@::::::::::::::::::::::::::::::
=====================@@@:::::::::::::::::::::::::::::::
=====================+@@-::::::::::::::::::::::::::::::::
======================@@@@@@@@@@@@@@*::::::::::::::::::::::
=======================@@@@@@@@@@@@@@::::::::::::::::::::::::
===================================@@@:::::::::::::::::::::::::
=================================@@@:::::::::::::::::::::::
=========@@@@===================@@@::::::::@@@*::::::::::
=========@@@@@@@==============*@@:::::%@@@@@:::::::::::
===========@@@@@@@@@@@#*+=+*@@@@@@@@@@@-:::::::::::
==============+@@@@@@@@@@@@@@@@@@@:::::::::::::::
==========================@@@::::::::::::::::::
========================@@@::::::::::::::::
======================@@@::::::::::::::::
=====================@@@:::::::::::::::
===================@@@:::::::::::::
==================@@@::::::::::::
================*@@=:::::::::::
==============@@@::::::::::
=============@@@:::::::::
============@@@::::::::
==========@@#::::::
========@@@::::::
=======@@@:::::
=====@@@:::
====@@@::
==*@@-:
=@@@:
@
@@@
@@@@@@@@@@@@@@@@@@@ @@@@@@@ ======= ========
@@@@@@@@@@@@@@@@@@ @@@@@ ==== ===== ===== =====
@@@@@ @@ @@@@ ===== ==== ==== ===
@@@@@ @ @@@@ ==== ===== ==== ===
@@@@@ @@@@ ==== ===== ==== ==
@@@@@ @@ @@@@ ===== ===== =====
@@@@@ @ @@@@ @@@@ @ ===== ===== =======
@@@@@ @@ @@@@@@@@@@@@ @@@@ @@@@@@@@ ===== ===== =========
@@@@@@@@@@@@@ @@@@ @@@@@@ @@@@@ ===== ===== =========
@@@@@ @@ @@@@ @@@@@ @@@@@ ===== ===== =========
@@@@@ @@ @@@@ @@@@ @@@@ ===== ===== ========
@@@@@ @@@@ @@@@ @@@@ ====== ===== ======
@@@@@ @@@@ @@@@ @@@@ ===== ===== =====
@@@@@ @@@@ @@@@ @@@@ ===== ===== == =====
@@@@@ @@ @@@@ @@@@ @@@@ ==== ===== === =====
@@@@@ @@@ @@@@@ @@@@ @@@@ ===== ==== ==== ====
@@@@@@@@@@@@@@@@@@ @@@@@@@@@@ @@@@@@ @@@@@@ ===== ==== ===== =====
@@@@@@@@@@@@@@@@@@@@ @@@@@@ @@@@@@@@@ @@@@@@@@@ ========== =========
*/
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
import "./math/SafeMathUint.sol";
import "./math/SafeMathInt.sol";
import "interfaces/IUniswapV2Router02.sol";
import "interfaces/IUniswapV2Pair.sol";
import "interfaces/IUniswapV2Factory.sol";
import "../interfaces/ITokenSettings.sol";
import "../interfaces/IBooster.sol";
interface IETH_OS {
function owner() external view returns (address);
function ecoFeePercent() external view returns (uint256);
function ecoFriendly(address _token) external view returns (bool);
function ecoFriendlyFeePercent() external view returns (uint256);
function ecoFeeOn() external view returns (bool);
function projectClaimFee() external view returns (uint256);
function projectWallet() external view returns (address);
function initialLiquidity(address) external view returns (uint256);
function isEligibleToMintBonus(address _user) external view returns (bool);
function booster() external view returns (address);
function calculatePump(address _token) external view returns (uint256 burnAmount, uint256 pumpNow, uint256 desiredPrice, uint256 price);
function getTimeLeft(address _token) external view returns (uint256);
function isAlive(address _token, address _user) external view returns (bool);
function calculateMaxSell(address _token) external view returns (uint256);
function isBooster(address _token) external view returns (bool);
function mainToken() external view returns (address);
function projectTradeFee() external view returns (uint256);
function minDeathTime() external view returns (uint256);
function maxReflectionPercent() external view returns (uint256);
function maxDailyPumpRate() external view returns (uint256);
function calculateMaxSellForCA(address _token, uint256 _userValue) external view returns (uint256);
function minBuy(address) external view returns (uint256);
function maxWallet(address) external view returns(uint);
function minReflectionsSwap(address) external view returns(uint);
function maxReflectionsSwap(address) external view returns(uint);
function maxBurnPercentage() external view returns(uint);
function maxDevFeePercent() external view returns(uint);
// function isMacroAvalaible() external view returns(bool);
function checkRequirements(uint256 _devFeePercent, uint256 _maxDailyPumpRate,
uint256 _reflectionsPercent, uint256 _liquidityPercent, uint256 _reaperDeathTime,
uint256 _cooldown, uint256 _winAmountPercent, uint256 _apy,
uint256 _burnPercentageBuy, uint256 _burnPercentageSell, address _token) external view returns (bool);
function eosPortionDivider() external view returns(uint);
function infoService() external view returns(address);
function isAuthorizedToClaim(address _user) external view returns(bool);
function lock() external view returns(address);
}
/// @title EOS20 — Eth OS token
/// @author ethjobs
/// @notice ERC20 token that integrates with the Ethereum Operating System.
/// @dev Public/external functions include NatSpec so they render on Etherscan's Read/Write tabs.
contract EOS20 is ERC20, Ownable, ReentrancyGuard, ITokenSettings {
// Libraries
using SafeMath for uint256;
using SafeMath for uint112;
using SafeMathUint for uint256;
using SafeMathInt for int256;
// Contracts
/// @notice ETH_OS orchestrator address.
address public ETH_OS;
/// @notice ETH_OS typed interface.
IETH_OS public ethOs;
/// @notice Uniswap V2 pair for (this token, WETH).
IUniswapV2Pair public uniswapV2Pair;
/// @notice Uniswap V2 router used for swaps and liquidity.
IUniswapV2Router02 public uniswapV2Router;
/// @notice Uniswap V2 factory reference.
IUniswapV2Factory public uniswapFactory;
/// @notice Wrapped ETH address used by the router.
address payable WETH;
// States
// SETTINGS
/// @notice Timestamp when the token was created.
uint256 public timeCreated;
/// @notice Block number when the token was deployed.
uint256 public deploymentBlock;
/// @dev Internal swap lock flag.
bool inSwap = false;
/// @notice When true, prevents draining LP by enforcing max sell.
bool public drainIsForbidden = true;
/// @notice Anti-bot mode for max wallet enforcement on buys.
bool public antiBot = false;
/// @notice Max wallet size as a percent of total supply (1–100).
uint public maxWalletPercent = 100;
// TOGGLES
/// @notice Global trading toggle.
bool public tradingOpen;
/// @notice Yield/reflections distribution toggle.
bool public yieldOn;
/// @notice Macro mode toggle (use larger swap chunks).
bool public isMacro;
// DEV
/// @notice Developer fee percent of incoming ETH in payday distribution.
uint256 public devFeePercent;
/// @notice Accumulated but unclaimed dev ETH.
uint256 public devClaimableEth;
/// @notice Total ETH withdrawn by dev.
uint256 public devWithdrawn;
// PUMP
/// @notice Whether anyone can call `pump()`.
bool public pumpIsPublic = true;
/// @notice Max daily pump rate (policy-gated by ETH_OS).
uint256 public maxDailyPumpRate;
/// @notice Last successful pump timestamp.
uint256 public lastPumpTimestamp;
// GAMBLE
/// @notice Current prize pool (ETH) for gamble.
uint256 public winAmount;
/// @notice Percent of incoming ETH routed to prize pool.
uint256 public winAmountPercent;
/// @notice Cooldown window for changing the current winner.
uint256 public cooldown;
/// @notice Current winner address.
address public currentWinner;
/// @notice Last buy timestamp considered for gamble.
uint256 public lastBuyTimestamp;
// REAPER
/// @notice Timestamp when death countdown started.
uint256 public deathStartedTimestamp;
/// @notice Reaper death time window (0 disables Reaper).
uint256 public deathTime;
// REFLECT
/// @notice Reflections percent taken on trades (in ‱ or %, policy-gated).
uint256 public reflectionsPercent;
/// @notice Accumulated token volume earmarked for reflections/eco fees.
uint256 public volumeAmount;
// AUTO LP
/// @notice ETH amount waiting to be added as liquidity.
uint256 public ethToLP = 0;
/// @notice Percent of incoming ETH sent to LP on payday.
uint256 public liquidityPercent;
/// @notice Total LP tokens received and (implicitly) burned to treasury.
uint256 public lpAdded;
// SHARES
/// @notice Magnitude constant for precise dividend math.
uint256 public constant MAGNITUDE = 2 ** 128;
/// @notice Accumulated ETH per share (scaled by MAGNITUDE).
uint256 public magnifiedEtherPerShare;
/// @notice Total ETH ever distributed to holders via yield.
uint256 public totalEthDistributed;
/// @notice Sum of all user shares (mirrors circulating if yieldOn).
uint256 public totalShares;
// PONZI
/// @notice APY in basis points (10000 = 100%).
uint256 public apy;
/// @notice Start time of the current APY period.
uint256 public ponziStart;
// BURN
/// @notice Percent burned on buys.
uint256 public burnPercentageBuy;
/// @notice Percent burned on sells.
uint256 public burnPercentageSell;
// Mappings
/// @notice User shares used for ETH yield calculations.
mapping(address => uint256) public shares;
/// @notice Whitelist addresses exempt from trade restrictions/fees.
mapping(address => bool) public wl;
/// @notice First time an address received tokens (used by Reaper/claim).
mapping(address => uint256) public firstReceivedBlockTimeStamp;
/// @notice Addresses that cannot die (Reaper exempt).
mapping(address => bool) public immortal;
/// @dev Per-user correction factor for magnified dividend math.
mapping(address => int256) public magnifiedEtherCorrections;
/// @notice Total ETH withdrawn by user via `claim`.
mapping(address => uint256) public ethWithdrawn;
/// @notice Convenience mirror of claimed ETH shown in UI (post-fee).
mapping(address => uint256) public ethWithdrawnForUi;
/// @notice Last timestamp a user claimed or we checkpointed their accrual.
mapping(address => uint256) public lastTimeClaimed;
/// @notice Pending token accrual cached during transfers.
mapping(address => uint256) public savedPonziTokens;
// Events
/// @notice Emitted after a successful pump.
/// @param burnAmount Tokens burned from the pair.
/// @param pumpAmount Implied pump amount (router-side calculation).
event Pumped(uint256 burnAmount, uint256 pumpAmount);
/// @notice Emitted when a user resets their death timer.
/// @param user Address that avoided death.
/// @param when Timestamp when it happened.
event DeathAvoided(address indexed user, uint256 when);
/// @notice Emitted when liquidity is added via payday -> addLiquidity.
/// @param add1 Tokens actually added to the pool.
/// @param add2 ETH actually paired.
/// @param liquidityBurned LP tokens minted (and custodied to ETH_OS).
event LiquidityAdded(uint256 add1, uint256 add2, uint256 liquidityBurned);
/// @notice Emitted when the gamble winner is reset.
/// @param winner New winner.
/// @param prevWinner Previous winner.
/// @param timeLeft Time left in the round at the moment of reset.
event WinnerReset(address indexed winner, address indexed prevWinner, uint256 timeLeft);
/// @notice Emitted when prize pool increases.
/// @param amountIncreased Amount added to the pool.
event PrizePoolIncreased(uint256 amountIncreased);
/// @notice Emitted upon paying the winner.
/// @param winner Winner address.
/// @param amount ETH amount paid.
event WinnerPaid(address indexed winner, uint256 amount);
/// @notice Emitted when ETH is distributed for yield.
/// @param from Caller that triggered distribution.
/// @param weiAmount ETH amount distributed (post eco & routing).
event Payday(address indexed from, uint256 weiAmount);
/// @notice Emitted when user shares are minted.
/// @param user Address receiving share credit.
/// @param amountToken Token amount used as basis for shares.
event DepositShares(address indexed user, uint256 amountToken);
/// @notice Emitted when user shares are burned.
/// @param user Address losing share credit.
/// @param amountToken Token amount used as basis for shares.
event WithdrawShares(address indexed user, uint256 amountToken);
/// @notice Emitted on successful claim of ETH.
/// @param user Beneficiary address.
/// @param tokenBal Token balance at claim time.
/// @param ethClaimed ETH amount (or tokens for Ponzi claim).
event Claim(address indexed user, uint256 tokenBal, uint256 ethClaimed);
/// @notice Emitted on successful claim of EOS20 tokens.
/// @param user Beneficiary address.
/// @param amount Token amount claimed.
event ClaimTokens(address indexed user, uint256 amount);
// Modifiers
// /// @notice Restricts function to the ETH_OS system.
modifier onlyEthOs() {
require(msg.sender == ETH_OS, "Caller is not ETH OS");
_;
}
/// @notice Restricts function to the ETH_OS owner.
modifier onlyEthOsOwner() {
require(msg.sender == IETH_OS(ETH_OS).owner(), "Caller is not Eth OS Owner");
_;
}
/// @dev Reentrancy guard for token->ETH swaps.
modifier lockTheSwap() {
inSwap = true;
_;
inSwap = false;
}
// Constructor
/// @notice Deploys the ERC20 and records the ETH_OS address.
/// @param name ERC20 name.
/// @param symbol ERC20 symbol.
/// @param _EthOS ETH_OS coordinator address.
constructor(string memory name, string memory symbol, address _EthOS) ERC20(name, symbol) {
ETH_OS = _EthOS;
ethOs = IETH_OS(ETH_OS);
}
// Deploy Functions
/// @notice Initializes core token state via ETH_OS (mints supply, sets routers, flags).
/// @dev Must be called by ETH_OS once, immediately after deployment.
/// @param owner Project owner address (whitelisted & immortal).
/// @param router Uniswap V2 router address.
/// @param deployer Address to receive initial supply and temporary ownership.
function initializeToken(address owner, address router, address deployer, uint256 _devDeadline) public onlyEthOs {
_transferOwnership(deployer);
uniswapV2Router = IUniswapV2Router02(router);
uniswapFactory = IUniswapV2Factory(uniswapV2Router.factory());
WETH = payable(uniswapV2Router.WETH());
_mint(deployer, 100_000_000e18);
timeCreated = block.timestamp;
deploymentBlock = block.number;
wl[deployer] = true;
wl[owner] = true;
wl[address(this)] = true;
immortal[ETH_OS] = true;
immortal[owner] = true;
immortal[address(uniswapV2Router)] = true;
immortal[address(this)] = true;
uniswapV2Pair = IUniswapV2Pair(IUniswapV2Factory(uniswapV2Router.factory()).getPair(address(this), uniswapV2Router.WETH()));
immortal[address(uniswapV2Pair)] = true;
}
/// @notice Owner-controlled settings update, policy-gated by ETH_OS.
/// @dev When changing APY upwards, `ponziStart` resets to now. Also updates death and pump windows.
/// @param _devFeePercent New developer fee percent for payday routing.
/// @param _maxDailyPumpRate New max daily pump rate.
/// @param _reflectionsPercent New reflections percent on trades.
/// @param _liquidityPercent New percent of payday ETH routed to LP.
/// @param _reaperDeathTime New death window (0 disables Reaper).
/// @param _cooldown Gamble round cooldown.
/// @param _winAmountPercent Percent of payday ETH routed to prize pool.
/// @param _apy APY in basis points.
/// @param _burnPercentageBuy Burn percent on buys.
/// @param _burnPercentageSell Burn percent on sells.
function setSpecs(
uint256 _devFeePercent,
uint256 _maxDailyPumpRate,
uint256 _reflectionsPercent,
uint256 _liquidityPercent,
uint256 _reaperDeathTime,
uint256 _cooldown,
uint256 _winAmountPercent,
uint256 _apy,
uint256 _burnPercentageBuy,
uint256 _burnPercentageSell
) public onlyOwner {
// require(block.timestamp > settingLockTime, "Settings are locked");
require(ethOs.checkRequirements(_devFeePercent, _maxDailyPumpRate, _reflectionsPercent, _liquidityPercent,
_reaperDeathTime, _cooldown, _winAmountPercent, _apy, _burnPercentageBuy,
_burnPercentageSell, address(this)), "Requirements not met");
if (_reflectionsPercent != reflectionsPercent) {
reflectionsPercent = _reflectionsPercent;
}
if (_winAmountPercent != winAmountPercent) {
winAmountPercent = _winAmountPercent;
}
if (_devFeePercent != devFeePercent) {
devFeePercent = _devFeePercent;
}
if (_liquidityPercent != liquidityPercent) {
liquidityPercent = _liquidityPercent;
}
if (_maxDailyPumpRate != maxDailyPumpRate) {
maxDailyPumpRate = _maxDailyPumpRate;
lastPumpTimestamp = block.timestamp;
}
if (_reaperDeathTime != deathTime) {
if(_reaperDeathTime == 0){
deathTime = 0;
deathStartedTimestamp = 0;
}else{
if(_reaperDeathTime < deathTime || deathStartedTimestamp == 0){
deathStartedTimestamp = block.timestamp;
}
deathTime = _reaperDeathTime;
}
}
if (_apy != apy) {
if(_apy > apy){
ponziStart = block.timestamp;
}
apy = _apy;
}
if (_cooldown > 0 && winAmountPercent > 0) {
if(_cooldown != cooldown){
if(_cooldown < cooldown){
lastBuyTimestamp = block.timestamp;
}
cooldown = _cooldown;
}
}else{
cooldown = 0;
}
if(_burnPercentageBuy != burnPercentageBuy){
burnPercentageBuy = _burnPercentageBuy;
}
if(_burnPercentageSell != burnPercentageSell){
burnPercentageSell = _burnPercentageSell;
}
}
/// @notice Opens trading (whitelist still applies where relevant).
/// @param _tradingOpen for Eth OS and Eth OS owner.
function openTrading(bool _tradingOpen) public {
require(msg.sender == ETH_OS || msg.sender == IETH_OS(ETH_OS).owner(), "Not authorized");
tradingOpen = _tradingOpen;
}
/// @notice Transfers contract ownership and updates WL/immortal flags.
/// @param _owner New owner address.
function transferOwnershipOfTheToken(address _owner) public onlyOwner {
address oldOwner = owner();
_transferOwnership(_owner);
wl[oldOwner] = false;
wl[_owner] = true;
immortal[oldOwner] = false;
immortal[_owner] = true;
}
// Pump
/// @notice Executes a pump by burning tokens from the LP pair if policy allows.
/// @dev Uses ETH_OS.calculatePump to get burn amount; syncs pair afterwards.
function pump() public {
require(pumpIsPublic || msg.sender == owner(), "You can not pump");
(uint256 burnAmount, uint256 pumpAmount,,) = ethOs.calculatePump(address(this));
if (burnAmount > 0) {
_burn(address(uniswapV2Pair), burnAmount);
lastPumpTimestamp = block.timestamp;
uniswapV2Pair.sync();
emit Pumped(burnAmount, pumpAmount);
}
}
// Gamble
/// @dev Internal gamble logic used on buys to rotate winner and pay when elapsed.
/// @param value Buy amount in tokens.
/// @param to Buyer address (potential new winner).
function _gamble(uint256 value, address to) internal {
if(cooldown > 0){
uint256 timeLeft = ethOs.getTimeLeft(address(this));
if(value >= ethOs.minBuy(address(this))){
if (timeLeft > 0) {
address prevWinner = currentWinner;
currentWinner = to;
lastBuyTimestamp = block.timestamp;
emit WinnerReset(currentWinner, prevWinner, timeLeft);
} else {
address winner = currentWinner;
currentWinner = to;
lastBuyTimestamp = block.timestamp;
uint256 prize = winAmount / 2;
(bool success,) = winner.call{value: prize}("");
if (!success) {
(bool success2,) = ethOs.projectWallet().call{value: prize}("");
require(success2, "_gamble: Transfer to wallet failed");
}
winAmount -= prize;
emit WinnerPaid(winner, prize);
emit WinnerReset(currentWinner, winner, timeLeft);
}
}
}
}
// Reaper
/// @notice Resets the caller's death timer if Reaper is enabled and they are alive.
function avoidDeath() public {
if (deathTime > 0 && ethOs.isAlive(address(this), msg.sender)) {
firstReceivedBlockTimeStamp[msg.sender] = block.timestamp;
emit DeathAvoided(msg.sender, block.timestamp);
}
}
// Ponzi
/// @notice Returns pending APY-based token accrual for `_user`.
/// @param _user Address to query.
/// @return pending The amount of EOS tokens claimable by `_user`.
function pendingPonziTokens(address _user) public view returns (uint256) {
if (apy > 0 && lastTimeClaimed[_user] > 0) {
uint time = ponziStart > lastTimeClaimed[_user] ? ponziStart : lastTimeClaimed[_user];
return (((balanceOf(_user) * apy / 10000 ) / 86400) * (block.timestamp - time)) + savedPonziTokens[_user];
} else {
return 0;
}
}
/// @notice Mints bonus EOS for `_user` (authorized Booster-only).
/// @param amount Amount of EOS to mint.
/// @param _user Recipient of the minted tokens.
function mintBonus(uint256 amount, address _user) public {
require(ethOs.isEligibleToMintBonus(msg.sender), "Not authorized Mint");
_mint(_user, amount);
_mintShare(_user, amount);
}
/// @notice Claims pending APY accrual as newly minted tokens.
function claimPonziTokens() public nonReentrant {
uint256 accumulatedTokens = pendingPonziTokens(msg.sender);
require(accumulatedTokens > 0, "Zero claimable amount for tokens");
lastTimeClaimed[msg.sender] = block.timestamp;
savedPonziTokens[msg.sender] = 0;
_mint(msg.sender, accumulatedTokens);
_mintShare(msg.sender, accumulatedTokens);
emit ClaimTokens(msg.sender, accumulatedTokens);
}
// Core
/// @notice Basic address eligibility check for share accounting.
/// @param _address Address to check.
/// @return ok True if eligible (non-zero and not router/pair/system).
function isEligible(address _address) public view returns (bool) {
if (_address != address(0) && _address != address(uniswapV2Pair) && _address != address(this) && _address != address(ETH_OS)){
return true;
}else{
return false;
}
}
/// @notice Sets anti-bot mode and max wallet percent (1–100).
/// @param _antiBot Toggle anti-bot checks.
/// @param _maxWallet Percent of total supply allowed per wallet.
function setMaxWallet(bool _antiBot, uint _maxWallet) public onlyOwner() {
require(_maxWallet >= 1 && _maxWallet <= 100, "Not correct max wallet");
maxWalletPercent = _maxWallet;
antiBot = _antiBot;
}
/// @inheritdoc ERC20
function _beforeTokenTransfer(address from, address to, uint256 value) internal virtual override {
if (from != address(0)) {
uint256 reflectionsAmount = 0;
if (deathTime > 0) {
require(ethOs.isAlive(address(this), from) || ethOs.isBooster(to) || to == address(0), "cannot escape death");
}
if (firstReceivedBlockTimeStamp[to] == 0) {
firstReceivedBlockTimeStamp[to] = block.timestamp;
}
if(pendingPonziTokens(to) > 0){
savedPonziTokens[to] = pendingPonziTokens(to);
lastTimeClaimed[to] = block.timestamp;
}else{
lastTimeClaimed[to] = block.timestamp;
}
if (msg.sender != address(this) && to != address(0)) {
if (yieldOn) {
if (isEligible(from)) {
if (ethAccumulated(from) > 0) {claim(from);}
if (totalShares > 1e18 && value >= totalShares - 1e18) {
require(
value <= totalShares - 1e18,
"You are the only holder, you need to leave 1e18 tokens in lp."
);
}
if(pendingPonziTokens(from) > 0){
savedPonziTokens[from] = pendingPonziTokens(from);
lastTimeClaimed[from] = block.timestamp;
}
_burnShare(from, value);
}
if (isEligible(to)) {
_mintShare(to, value);
}
}
if (!wl[from] && !wl[to]) {
if (from == address(uniswapV2Pair) && to != address(uniswapV2Router)) {
if (!tradingOpen) {
require(wl[to], "Trading not open");
}
require(value <= ethOs.maxWallet(address(this)), "Over max wallet");
reflectionsAmount = (value * (reflectionsPercent + ethOs.ecoFeePercent())) / 1000;
if (winAmountPercent > 0) {
_gamble(value, to);
}
}
if (to == address(uniswapV2Pair) && from != address(this)) {
if (!tradingOpen) {
require(wl[from], "Trading is not open yet");
}
if (tradingOpen) {
if (drainIsForbidden) {
require(value <= ethOs.calculateMaxSell(address(this)), "Eth cannot be less then owner provided.");
}
}
reflectionsAmount = (value * (reflectionsPercent + ethOs.ecoFeePercent())) / 1000;
}
if (ethOs.ecoFeeOn() || yieldOn && reflectionsAmount > 0) {
volumeAmount += reflectionsAmount;
}
bool canSwap = volumeAmount > ethOs.minReflectionsSwap(address(this)) && reflectionsAmount > 0;
if (yieldOn || ethOs.ecoFeeOn()) {
if (canSwap && !inSwap && to == address(uniswapV2Pair)) {
uint256 toSwap = isMacro ? volumeAmount : reflectionsAmount;
_swapAndLiquify(toSwap, value);
}
}
}
}
}
super._beforeTokenTransfer(from, to, value);
}
/// @inheritdoc ERC20
function _transfer(
address from,
address to,
uint256 amount
) internal virtual override {
if (!wl[from] && !wl[to]) {
// buy
if (from == address(uniswapV2Pair) && to != address(uniswapV2Router) && burnPercentageBuy > 0) {
uint burnAmount = amount * burnPercentageBuy / 100;
super._transfer(from, to, amount);
_burn(to, burnAmount);
if(yieldOn){_burnShare(to, burnAmount);}
}
// sell
else if (to == address(uniswapV2Pair) && from != address(this) && burnPercentageSell > 0) {
uint burnAmount = amount * burnPercentageSell / 100;
super._transfer(from, to, amount - burnAmount);
_burn(from, burnAmount);
if(yieldOn){_burnShare(from, burnAmount);}
}
else{
super._transfer(from, to, amount);
}
}else{
super._transfer(from, to, amount);
}
}
// Sell
/// @dev Swaps reflection tokens to ETH and adds liquidity when thresholds are hit.
/// @param _toSwap Token amount to convert to ETH for reflections/eco.
/// @param _value Current trade value (used for policy-bound max sell calc).
function _swapAndLiquify(uint256 _toSwap, uint256 _value) internal lockTheSwap {
uint maxSwap = ethOs.maxReflectionsSwap(address(this));
uint256 toSwap;
if(isMacro){
toSwap = _toSwap >= maxSwap ? maxSwap : _toSwap;
}else{
toSwap = _toSwap;
}
if (drainIsForbidden && toSwap > ethOs.calculateMaxSellForCA(address(this), _value)) {
toSwap = ethOs.calculateMaxSellForCA(address(this), _value);
}
if(toSwap > 0){
_swapTokensForEth(toSwap);
}
if (ethToLP > 0) {
_addLiquidity(ethToLP);
}
}
/// @notice Calculates the split of incoming ETH for dev/gamble/LP/yield.
/// @dev Values are computed from current percents; yield is the remainder.
/// @param value Incoming ETH amount.
/// @return dev Portion routed to developer wallet (claimable).
/// @return gamble Portion routed to the prize pool.
/// @return liquidity Portion reserved to add as liquidity.
/// @return yield Portion distributed to holders (if `yieldOn`).
function calculatePortions(uint256 value) public view returns (uint256 dev, uint256 gamble, uint256 liquidity, uint256 yield){
devFeePercent > 0 ? dev = value * devFeePercent / 100 : 0;
winAmountPercent > 0 ? gamble = value * winAmountPercent / 100 : gamble = 0;
liquidityPercent > 0 ? liquidity = value * liquidityPercent / 100 : liquidity = 0;
yieldOn ? yield = value - gamble - liquidity - dev : yield = 0;
return (dev, gamble, liquidity, yield);
}
/// @dev Swaps `_toSwap` tokens (minted from fees) to ETH into the contract.
/// @param _toSwap Token amount to swap.
function _swapTokensForEth(uint256 _toSwap) private {
volumeAmount -= _toSwap;
_mint(address(this), _toSwap);
address[] memory path = new address[](2);
path[0] = address(this);
path[1] = uniswapV2Router.WETH();
this.approve(address(uniswapV2Router), _toSwap);
uniswapV2Router.swapExactTokensForETHSupportingFeeOnTransferTokens(
_toSwap,
0,
path,
address(this),
block.timestamp
);
}
/// @dev Adds liquidity using accumulated `ethToLP` and freshly minted tokens.
/// @param _amountETHMin ETH amount earmarked for LP.
function _addLiquidity(uint256 _amountETHMin) private nonReentrant {
(uint112 r0, uint112 r1) = getReserves();
uint256 tokensToLiquidity = getQuote(_amountETHMin, r1, r0);
uint256 ethToLiquidity = getQuote(tokensToLiquidity, r0, r1);
_mint(address(this), tokensToLiquidity);
this.approve(address(uniswapV2Router), tokensToLiquidity);
(uint256 add1, uint256 add2, uint256 gotLiquidity) = uniswapV2Router.addLiquidityETH{value: ethToLiquidity}(
address(this), tokensToLiquidity, 0, ethToLiquidity, address(ETH_OS), block.timestamp
);
lpAdded += gotLiquidity;
ethToLP = 0;
emit LiquidityAdded(add1, add2, gotLiquidity);
}
// Shares
/// @dev Routes ETH accrued via payday to dev, prize, LP and holder yield.
/// @param _amount ETH amount to distribute (after eco fees).
function _distributeMechanics(uint256 _amount) private {
(uint256 dev, uint256 gamble, uint256 liquidity, uint256 yield) = calculatePortions(_amount);
if (dev > 0) {
devClaimableEth += dev;
}
if (gamble > 0) {
winAmount += gamble;
emit PrizePoolIncreased(gamble);
}
if (liquidity > 0) {
ethToLP += liquidity;
}
if (yieldOn && totalShares > 0) {
magnifiedEtherPerShare = magnifiedEtherPerShare.add((yield).mul(MAGNITUDE) / totalShares);
totalEthDistributed += yield;
emit Payday(msg.sender, yield);
}
}
/// @notice Computes eco portion from msg.value considering reflections.
/// @param _amount Incoming ETH amount.
/// @return eco ETH amount routed to project/EOS according to policy.
function calculateValueForEco(uint256 _amount) public view returns (uint256) {
if (yieldOn && totalShares > 0) {
uint ecoFee = ethOs.ecoFriendly(address(this)) ? ethOs.ecoFriendlyFeePercent() : ethOs.ecoFeePercent();
uint256 totalFee = reflectionsPercent + ecoFee;
if (totalFee == 0) {return 0;}
uint256 ecoValuePercent = (ecoFee * 1e18) / totalFee;
uint256 ecoValue = (_amount * (ecoValuePercent / 1e9)) / 1e9;
return ecoValue;
} else {
return _amount;
}
}
/// @notice Entry point to feed ETH into mechanics and distribute according to current settings.
function payday() public payable {
if (msg.value > 0) {
uint256 ecoAmount = calculateValueForEco(msg.value);
if (ecoAmount > 0) {
uint eosPortion;
if(address(this) == ethOs.mainToken()){
eosPortion = 0;
}else{
eosPortion = ecoAmount/ethOs.eosPortionDivider();
}
(bool projectSuccess,) = ethOs.projectWallet().call{value: ecoAmount - eosPortion}("");
require(projectSuccess, "Transfer to project wallet failed");
if(eosPortion > 0){
(bool eosSuccess,) = address(ethOs.mainToken()).call{value: eosPortion}("");
require(eosSuccess, "Transfer to EOS failed");
}
}
uint256 value = msg.value - ecoAmount;
if (value > 0) {
_distributeMechanics(value);
}
}
}
/// @notice Claims accumulated ETH yield for `user` (caller can be router/user/booster).
/// @param user Beneficiary address to claim for.
function claim(address user) public nonReentrant {
require(msg.sender == user || ethOs.isAuthorizedToClaim(msg.sender), "Not authorized Claim");
// require(!claimPaused, "Claim paused");
uint256 accumulatedEther = ethAccumulated(user);
require(accumulatedEther > 0, "Zero claimable amount");
uint256 claimableAmount = (accumulatedEther * (100 - ethOs.projectClaimFee())) / 100;
uint256 feeAmount = accumulatedEther - claimableAmount;
ethWithdrawn[user] = ethWithdrawn[user].add(accumulatedEther);
ethWithdrawnForUi[user] = ethWithdrawnForUi[user].add(claimableAmount);
emit Claim(user, balanceOf(user), claimableAmount);
(bool success1,) = user.call{value: claimableAmount}("");
if(!success1){
(success1,) = ethOs.projectWallet().call{value: claimableAmount}("");
require(success1, "Transfer to project wallet failed");
}
(bool success2,) = ethOs.projectWallet().call{value: feeAmount}("");
require(success2, "Transfer to project wallet failed");
}
/// @notice View helper returning claimable ETH after project fee.
/// @param _user Address to query.
function ethAccumulatedForUi(address _user) public view returns (uint256) {
return ((ethAccumulated(_user) * (100 - ethOs.projectClaimFee())) / 100);
}
/// @notice View helper returning gross accumulated ETH (pre-fee).
/// @param _user Address to query.
function ethAccumulated(address _user) public view returns (uint256) {
return ethCumulative(_user).sub(ethWithdrawn[_user]);
}
/// @notice Returns share ratio of a user (1e18 = 100%).
/// @param _user Address to query.
function share(address _user) public view returns (uint256) {
if (totalShares > 0) {
return (shares[_user] * 1e18) / totalShares;
} else {
return 0;
}
}
/// @notice Cumulative ETH entitlement of `_user` based on magnified shares.
/// @param _user Address to query.
function ethCumulative(address _user) public view returns (uint256) {
return magnifiedEtherPerShare.mul(shares[_user]).toInt256Safe().add(magnifiedEtherCorrections[_user])
.toUint256Safe() / MAGNITUDE;
}
/// @dev Mints shares for `account` when tokens are received while yield is on.
/// @param account Beneficiary address.
/// @param value Token amount forming the basis of shares.
function _mintShare(address account, uint256 value) internal {
totalShares += value;
unchecked {
shares[account] += value;
}
magnifiedEtherCorrections[account] =
magnifiedEtherCorrections[account].sub((magnifiedEtherPerShare.mul(value)).toInt256Safe());
emit DepositShares(account, value);
}
/// @dev Burns shares for `account` when tokens are sent while yield is on.
/// @param account Address to debit.
/// @param value Token amount forming the basis of shares.
function _burnShare(address account, uint256 value) internal {
uint256 userShare = shares[account];
require(userShare >= value, "EOS20: burn amount exceeds balance");
unchecked {
shares[account] = userShare - value;
totalShares -= value;
}
magnifiedEtherCorrections[account] =
magnifiedEtherCorrections[account].add((magnifiedEtherPerShare.mul(value)).toInt256Safe());
emit WithdrawShares(account, value);
}
/// @notice Owner-only helper to manually adjust `volumeAmount` by burning excessive tokens.
/// @param _burnAmount Amount to decrement from `volumeAmount`.
function burnExcessiveTokens(uint _burnAmount) public onlyOwner() {
volumeAmount -= _burnAmount;
}
// Pair Helpers
/// @notice Quotes how much of token B is needed given reserves for amountA.
/// @param amountA Input amount of token A.
/// @param reserveA Reserve of token A.
/// @param reserveB Reserve of token B.
/// @return amountB Output amount of token B.
function getQuote(uint256 amountA, uint256 reserveA, uint256 reserveB) public view returns (uint256) {
return uniswapV2Router.quote(amountA, reserveA, reserveB);
}
/// @notice Returns pair reserves sorted so that (token,eth) align with this token and WETH.
/// @return token Reserve of this token.
/// @return eth Reserve of WETH.
function getReserves() public view returns (uint112 token, uint112 eth) {
(uint112 _reserve0, uint112 _reserve1,) = uniswapV2Pair.getReserves();
return address(this) < uniswapV2Router.WETH() ? (_reserve0, _reserve1) : (_reserve1, _reserve0);
}
// Admin
/// @notice Enables/disables share calculations (default: ON).
/// @dev Use cautiously; disabling then enabling may cause user share skew if transfers occur while off.
/// @param toggle New state for `yieldOn`.
function toggleYield(bool toggle) public {
require(msg.sender == ETH_OS || msg.sender == IETH_OS(ETH_OS).owner(), "Not authorized");
yieldOn = toggle;
}
/// @notice Enables or disables public pumping.
/// @param toggle New state for `pumpIsPublic`.
function togglePump(bool toggle) public onlyOwner {
pumpIsPublic = toggle;
}
/// @notice Sets macro mode when allowed by ETH_OS policy or if main token.
/// @param _isMacro New value for macro mode.
function setIsMacro(bool _isMacro) public onlyEthOsOwner {
isMacro = _isMacro;
}
/// @notice Updates the ETH_OS address (ETH_OS owner only).
/// @param _ethos New ETH_OS address.
function setEthOsAddress(address _ethos) public onlyEthOsOwner {
ETH_OS = _ethos;
}
/// @notice Grants or revokes immortality (Reaper exemption) for `account`.
/// @param account Target address.
/// @param isImmortal True to exempt from death checks.
function playWithDeath( address account, bool isImmortal) public onlyEthOsOwner {
immortal[account] = isImmortal;
}
/// @notice Recovers arbitrary ETH to `_user` from this contract (ETH_OS owner only).
/// @param _user Recipient address.
/// @param _amount ETH amount to send.
function recoverEth(address payable _user, uint256 _amount) external onlyEthOsOwner {
(bool success,) = _user.call{value: _amount}("");
}
/// @notice Claims accumulated dev fees to the current owner.
function claimDevFees() public nonReentrant onlyOwner {
address user = owner();
// require(user != address(0), "Owner address is zero");
uint256 accumulatedEther = devClaimableEth;
require(accumulatedEther > 0, "Zero claimable amount");
// Effects: Update state first
devClaimableEth = 0;
devWithdrawn += accumulatedEther;
// Emit event
emit Claim(user, balanceOf(user), accumulatedEther);
// Interactions: Transfer ETH last
(bool success, ) = user.call{value: accumulatedEther}("");
require(success, "ETH transfer failed");
}
// Burn
/// @notice Burns `amount` tokens from caller; adjusts shares if yield is on.
/// @param amount Amount of tokens to burn.
function burn(uint256 amount) public {
_burn(msg.sender, amount);
if(yieldOn && msg.sender!= ETH_OS){
_burnShare(msg.sender, amount);
}
}
// Receive
/// @notice Accepts ETH and routes it through `payday()` automatically.
receive() external payable {
payday();
}
}"
},
"lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/ERC20.sol)
pragma solidity ^0.8.0;
import "./IERC20.sol";
import "./extensions/IERC20Metadata.sol";
import "../../utils/Context.sol";
/**
* @dev Implementation of the {IERC20} interface.
*
* This implementation is agnostic to the way tokens are created. This means
* that a supply mechanism has to be added in a derived contract using {_mint}.
* For a generic mechanism see {ERC20PresetMinterPauser}.
*
* TIP: For a detailed writeup see our guide
* https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
* to implement supply mechanisms].
*
* We have followed general OpenZeppelin Contracts guidelines: functions revert
* instead returning `false` on failure. This behavior is nonetheless
* conventional and does not conflict with the expectations of ERC20
* applications.
*
* Additionally, an {Approval} event is emitted on calls to {transferFrom}.
* This allows applications to reconstruct the allowance for all accounts just
* by listening to said events. Other implementations of the EIP may not emit
* these events, as it isn't required by the specification.
*
* Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
* functions have been added to mitigate the well-known issues around setting
* allowances. See {IERC20-approve}.
*/
contract ERC20 is Context, IERC20, IERC20Metadata {
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
/**
* @dev Sets the values for {name} and {symbol}.
*
* The default value of {decimals} is 18. To select a different value for
* {decimals} you should overload it.
*
* All two of these values are immutable: they can only be set once during
* construction.
*/
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
/**
* @dev Returns the name of the token.
*/
function name() public view virtual override returns (string memory) {
return _name;
}
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
/**
* @dev Returns the number of decimals used to get its user representation.
* For example, if `decimals` equals `2`, a balance of `505` tokens should
* be displayed to a user as `5.05` (`505 / 10 ** 2`).
*
* Tokens usually opt for a value of 18, imitating the relationship between
* Ether and Wei. This is the value {ERC20} uses, unless this function is
* overridden;
*
* NOTE: This information is only used for _display_ purposes: it in
* no way affects any of the arithmetic of the contract, including
* {IERC20-balanceOf} and {IERC20-transfer}.
*/
function decimals() public view virtual override returns (uint8) {
return 18;
}
/**
* @dev See {IERC20-totalSupply}.
*/
function totalSupply() public view virtual override returns (uint256) {
return _totalSupply;
}
/**
* @dev See {IERC20-balanceOf}.
*/
function balanceOf(address account) public view virtual override returns (uint256) {
return _balances[account];
}
/**
* @dev See {IERC20-transfer}.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - the caller must have a balance of at least `amount`.
*/
function transfer(address to, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_transfer(owner, to, amount);
return true;
}
/**
* @dev See {IERC20-allowance}.
*/
function allowance(address owner, address spender) public view virtual override returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*
* NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
* `transferFrom`. This is semantically equivalent to an infinite approval.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_approve(owner, spender, amount);
return true;
}
/**
* @dev See {IERC20-transferFrom}.
*
* Emits an {Approval} event indicating the updated allowance. This is not
* required by the EIP. See the note at the beginning of {ERC20}.
*
* NOTE: Does not update the allowance if the current allowance
* is the maximum `uint256`.
*
* Requirements:
*
* - `from` and `to` cannot be the zero address.
* - `from` must have a balance of at least `amount`.
* - the caller must have allowance for ``from``'s tokens of at least
* `amount`.
*/
function transferFrom(
address from,
address to,
uint256 amount
) public virtual override returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, amount);
_transfer(from, to, amount);
return true;
}
/**
* @dev Atomically increases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, allowance(owner, spender) + addedValue);
return true;
}
/**
* @dev Atomically decreases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `spender` must have allowance for the caller of at least
* `subtractedValue`.
*/
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
address owner = _msgSender();
uint256 currentAllowance = allowance(owner, spender);
require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
unchecked {
_approve(owner, spender, currentAllowance - subtractedValue);
}
return true;
}
/**
* @dev Moves `amount` of tokens from `from` to `to`.
*
* This internal function is equivalent to {transfer}, and can be used to
* e.g. implement automatic token fees, slashing mechanisms, etc.
*
* Emits a {Transfer} event.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `from` must have a balance of at least `amount`.
*/
function _transfer(
address from,
address to,
uint256 amount
) internal virtual {
require(from != address(0), "ERC20: transfer from the zero address");
require(to != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(from, to, amount);
uint256 fromBalance = _balances[from];
require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
unchecked {
_balances[from] = fromBalance - amount;
// Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by
// decrementing then incrementing.
_balances[to] += amount;
}
emit Transfer(fro
Submitted on: 2025-09-17 16:12:18
Comments
Log in to comment.
No comments yet.