Contract Source Code:
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.19;
import "solmate/tokens/ERC20.sol";
import "solmate/auth/Owned.sol";
import "./IUniswapV2Router01.sol";
import "./IUniswapV2Factory.sol";
import "./SafeMath.sol";
contract EmberERC20 is ERC20, Owned {
using SafeMath for uint256;
uint public max_holding;
uint public max_transfer;
uint public sell_tax_threshold;
uint public buy_tax;
uint public sell_tax;
uint public in_swap = 1; // 1 is false, 2 is true
uint public is_trading_enabled = 1; // 1 is false, 2 is true
address public tax_receiver;
mapping(address => bool) public lps;
mapping(address => bool) public routers;
mapping(address => bool) public anti_whale_exceptions;
mapping(address => bool) public tax_exceptions;
address public weth;
address public uni_router;
address public uni_factory;
constructor(
string memory name,
string memory ticker,
uint8 decimals,
uint _totalSupply,
uint _max_holding,
uint _max_transfer,
uint _buy_tax,
uint _sell_tax,
address _uni_router,
address _weth
) ERC20(name, ticker, decimals) Owned(msg.sender) {
require(_buy_tax <= 30, "buy tax too high");
require(_sell_tax <= 30, "sell tax too high");
if (_max_holding == 0) {
_max_holding = type(uint256).max;
}
if (_max_transfer == 0) {
_max_transfer = type(uint256).max;
}
require(
_max_holding >= _totalSupply.div(100),
"Max Holding Limit cannot be less than 1% of total supply"
);
require(
_max_transfer >= _totalSupply.div(100),
"Max Transfer Limit cannot be less than 1% of total supply"
);
max_holding = _max_holding;
max_transfer = _max_transfer;
sell_tax_threshold = _totalSupply / 100;
buy_tax = _buy_tax;
sell_tax = _sell_tax;
anti_whale_exceptions[address(this)] = true;
anti_whale_exceptions[msg.sender] = true;
uni_router = _uni_router;
uni_factory = IUniswapV2Router01(uni_router).factory();
weth = _weth;
routers[_uni_router] = true;
allowance[address(this)][_uni_router] = type(uint256).max;
anti_whale_exceptions[_uni_router] = true;
allowance[msg.sender][address(this)] = type(uint256).max;
tax_receiver = owner;
_mint(msg.sender, _totalSupply);
}
modifier lockTheSwap() {
in_swap = 2;
_;
in_swap = 1;
}
function transfer(
address to,
uint256 amount
) public override returns (bool) {
_transfer(msg.sender, to, amount);
return true;
}
function transferFrom(
address from,
address to,
uint256 amount
) public override returns (bool) {
uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.
if (allowed != type(uint256).max) {
require(allowed >= amount, "no allowance");
allowance[from][msg.sender] = allowed - amount;
}
_transfer(from, to, amount);
return true;
}
function _transfer(address from, address to, uint amount) private {
require(
is_trading_enabled == 2 || tx.origin == owner,
"trading isnt live"
);
require(from != address(0), "ERC20: transfer from the zero address");
require(to != address(0), "ERC20: transfer to the zero address");
require(amount > 0, "Transfer amount must be greater than zero");
uint256 taxAmount = 0;
if (from != owner && to != owner && tx.origin != owner) {
bool isSelling;
if (lps[from] && !routers[to] && !tax_exceptions[to]) {
require(
max_transfer >= amount || anti_whale_exceptions[to],
"max tx limit"
);
taxAmount = amount.mul(buy_tax).div(100);
}
if (lps[to] && from != address(this) && !tax_exceptions[from]) {
isSelling = true;
require(
max_transfer >= amount || anti_whale_exceptions[from],
"max tx limit"
);
taxAmount = amount.mul(sell_tax).div(100);
}
uint256 contractTokenBalance = balanceOf[address(this)];
if (
in_swap == 1 &&
isSelling &&
contractTokenBalance > sell_tax_threshold
) {
swapTokensForEth(contractTokenBalance);
}
}
if (taxAmount > 0) {
balanceOf[address(this)] = balanceOf[address(this)].add(taxAmount);
emit Transfer(from, address(this), taxAmount);
} else {
require(
max_transfer >= amount || anti_whale_exceptions[from],
"max tx limit"
);
}
balanceOf[from] = balanceOf[from].sub(amount);
balanceOf[to] = balanceOf[to].add(amount.sub(taxAmount));
require(
balanceOf[to] <= max_holding ||
anti_whale_exceptions[to] ||
tx.origin == owner,
"max holding limit"
);
emit Transfer(from, to, amount.sub(taxAmount));
}
function swapTokensForEth(uint amount) private lockTheSwap {
address[] memory path = new address[](2);
path[0] = address(this);
path[1] = weth;
try
IUniswapV2Router01(uni_router)
.swapExactTokensForETHSupportingFeeOnTransferTokens(
amount,
0,
path,
tax_receiver,
99999999999999999999
)
{
//
} catch {
// Ignore, to prevent calls from failing if owner sets invalid router
}
}
function isAntiWhaleEnabled() external view returns (bool) {
return max_holding != 0 || max_transfer != 0;
}
function setLimits(
uint _max_holding,
uint _max_transfer
) external onlyOwner {
if (_max_holding == 0) {
_max_holding = type(uint256).max;
}
if (_max_transfer == 0) {
_max_transfer = type(uint256).max;
}
require(
_max_holding >= totalSupply.div(100),
"Max Holding Limit cannot be less than 1% of total supply"
);
require(
_max_transfer >= totalSupply.div(100),
"Max Transfer Limit cannot be less than 1% of total supply"
);
max_holding = _max_holding;
max_transfer = _max_transfer;
}
function setAntiWhaleException(address user, bool val) external onlyOwner {
anti_whale_exceptions[user] = val;
}
function enableTrading() external onlyOwner {
is_trading_enabled = 2;
}
function setUniRouter(address newRouter, address newFactory) external onlyOwner {
uni_factory = newFactory;
uni_router = newRouter;
routers[newRouter] = true;
allowance[address(this)][newRouter] = type(uint256).max;
anti_whale_exceptions[newRouter] = true;
}
function setAmm(address lp) public onlyOwner {
lps[lp] = true;
anti_whale_exceptions[lp] = true;
}
function addRouter(address router) external onlyOwner {
routers[router] = true;
allowance[address(this)][router] = type(uint256).max;
anti_whale_exceptions[router] = true;
}
function setExcludeFromFee(address addy, bool val) external onlyOwner {
tax_exceptions[addy] = val;
}
function setSwapThreshold(uint newThreshold) external onlyOwner {
sell_tax_threshold = newThreshold;
}
function setTaxes(uint _buy_tax, uint _sell_tax) external onlyOwner {
require(_buy_tax <= 30, "buy tax too high");
require(_sell_tax <= 30, "sell tax too high");
buy_tax = _buy_tax;
sell_tax = _sell_tax;
}
function setTaxReceiver(address _tax_receiver) external onlyOwner {
tax_receiver = _tax_receiver;
}
function addLp(uint amount) external payable onlyOwner {
is_trading_enabled = 2;
_transfer(owner, address(this), amount);
uint balance = address(this).balance;
address pair = uniV2Pair();
IUniswapV2Router01(uni_router).addLiquidityETH{value: balance}(
address(this),
amount,
amount,
balance,
owner,
block.timestamp
);
setAmm(pair);
is_trading_enabled = 1;
}
function uniV2Pair() public view returns (address pair) {
pair = pairFor(weth, address(this));
}
// calculates the CREATE2 address for a pair without making any external calls
function pairFor(
address tokenA,
address tokenB
) internal view returns (address pair) {
(address token0, address token1) = sortTokens(tokenA, tokenB);
pair = address(
uint160(
uint(
keccak256(
abi.encodePacked(
hex"ff",
uni_factory,
keccak256(abi.encodePacked(token0, token1)),
hex"96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f" // init code hash
)
)
)
)
);
}
function sortTokens(
address tokenA,
address tokenB
) internal pure returns (address token0, address token1) {
(token0, token1) = tokenA < tokenB
? (tokenA, tokenB)
: (tokenB, tokenA);
}
receive() external payable {}
function withdraw() external onlyOwner {
(bool sent, ) = owner.call{value: address(this).balance}("");
require(sent, "Failed to send Ether");
}
function version() public pure returns (uint) {
return 2;
}
}
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol)
/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)
/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.
abstract contract ERC20 {
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/
event Transfer(address indexed from, address indexed to, uint256 amount);
event Approval(address indexed owner, address indexed spender, uint256 amount);
/*//////////////////////////////////////////////////////////////
METADATA STORAGE
//////////////////////////////////////////////////////////////*/
string public name;
string public symbol;
uint8 public immutable decimals;
/*//////////////////////////////////////////////////////////////
ERC20 STORAGE
//////////////////////////////////////////////////////////////*/
uint256 public totalSupply;
mapping(address => uint256) public balanceOf;
mapping(address => mapping(address => uint256)) public allowance;
/*//////////////////////////////////////////////////////////////
EIP-2612 STORAGE
//////////////////////////////////////////////////////////////*/
uint256 internal immutable INITIAL_CHAIN_ID;
bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;
mapping(address => uint256) public nonces;
/*//////////////////////////////////////////////////////////////
CONSTRUCTOR
//////////////////////////////////////////////////////////////*/
constructor(
string memory _name,
string memory _symbol,
uint8 _decimals
) {
name = _name;
symbol = _symbol;
decimals = _decimals;
INITIAL_CHAIN_ID = block.chainid;
INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
}
/*//////////////////////////////////////////////////////////////
ERC20 LOGIC
//////////////////////////////////////////////////////////////*/
function approve(address spender, uint256 amount) public virtual returns (bool) {
allowance[msg.sender][spender] = amount;
emit Approval(msg.sender, spender, amount);
return true;
}
function transfer(address to, uint256 amount) public virtual returns (bool) {
balanceOf[msg.sender] -= amount;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += amount;
}
emit Transfer(msg.sender, to, amount);
return true;
}
function transferFrom(
address from,
address to,
uint256 amount
) public virtual returns (bool) {
uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.
if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;
balanceOf[from] -= amount;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += amount;
}
emit Transfer(from, to, amount);
return true;
}
/*//////////////////////////////////////////////////////////////
EIP-2612 LOGIC
//////////////////////////////////////////////////////////////*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) public virtual {
require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED");
// Unchecked because the only math done is incrementing
// the owner's nonce which cannot realistically overflow.
unchecked {
address recoveredAddress = ecrecover(
keccak256(
abi.encodePacked(
"\x19\x01",
DOMAIN_SEPARATOR(),
keccak256(
abi.encode(
keccak256(
"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
),
owner,
spender,
value,
nonces[owner]++,
deadline
)
)
)
),
v,
r,
s
);
require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER");
allowance[recoveredAddress][spender] = value;
}
emit Approval(owner, spender, value);
}
function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();
}
function computeDomainSeparator() internal view virtual returns (bytes32) {
return
keccak256(
abi.encode(
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
keccak256(bytes(name)),
keccak256("1"),
block.chainid,
address(this)
)
);
}
/*//////////////////////////////////////////////////////////////
INTERNAL MINT/BURN LOGIC
//////////////////////////////////////////////////////////////*/
function _mint(address to, uint256 amount) internal virtual {
totalSupply += amount;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += amount;
}
emit Transfer(address(0), to, amount);
}
function _burn(address from, uint256 amount) internal virtual {
balanceOf[from] -= amount;
// Cannot underflow because a user's balance
// will never be larger than the total supply.
unchecked {
totalSupply -= amount;
}
emit Transfer(from, address(0), amount);
}
}
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
/// @notice Simple single owner authorization mixin.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/auth/Owned.sol)
abstract contract Owned {
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/
event OwnershipTransferred(address indexed user, address indexed newOwner);
/*//////////////////////////////////////////////////////////////
OWNERSHIP STORAGE
//////////////////////////////////////////////////////////////*/
address public owner;
modifier onlyOwner() virtual {
require(msg.sender == owner, "UNAUTHORIZED");
_;
}
/*//////////////////////////////////////////////////////////////
CONSTRUCTOR
//////////////////////////////////////////////////////////////*/
constructor(address _owner) {
owner = _owner;
emit OwnershipTransferred(address(0), _owner);
}
/*//////////////////////////////////////////////////////////////
OWNERSHIP LOGIC
//////////////////////////////////////////////////////////////*/
function transferOwnership(address newOwner) public virtual onlyOwner {
owner = newOwner;
emit OwnershipTransferred(msg.sender, newOwner);
}
}
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.2;
// https://uniswap.org/docs/v2/smart-contracts/router01/
// https://github.com/Uniswap/uniswap-v2-periphery/blob/master/contracts/UniswapV2Router01.sol implementation
// UniswapV2Router01 is deployed at 0xf164fC0Ec4E93095b804a4795bBe1e041497b92a on the Ethereum mainnet, and the Ropsten, Rinkeby, Görli, and Kovan testnets
interface IUniswapV2Router01 {
function factory() external pure returns (address);
function WETH() external pure returns (address);
function addLiquidity(
address tokenA,
address tokenB,
uint amountADesired,
uint amountBDesired,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) external returns (uint amountA, uint amountB, uint liquidity);
function addLiquidityETH(
address token,
uint amountTokenDesired,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) external payable returns (uint amountToken, uint amountETH, uint liquidity);
function removeLiquidity(
address tokenA,
address tokenB,
uint liquidity,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) external returns (uint amountA, uint amountB);
function swapExactTokensForETHSupportingFeeOnTransferTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external;
function removeLiquidityETH(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) external returns (uint amountToken, uint amountETH);
function removeLiquidityWithPermit(
address tokenA,
address tokenB,
uint liquidity,
uint amountAMin,
uint amountBMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external returns (uint amountA, uint amountB);
function removeLiquidityETHWithPermit(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external returns (uint amountToken, uint amountETH);
function swapExactTokensForTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external returns (uint[] memory amounts);
function swapTokensForExactTokens(
uint amountOut,
uint amountInMax,
address[] calldata path,
address to,
uint deadline
) external returns (uint[] memory amounts);
function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline)
external
payable
returns (uint[] memory amounts);
function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline)
external
returns (uint[] memory amounts);
function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline)
external
returns (uint[] memory amounts);
function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline)
external
payable
returns (uint[] memory amounts);
function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB);
function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut);
function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn);
function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts);
function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts);
}
pragma solidity ^0.8.0;
interface IUniswapV2Factory {
function allPairs(uint256) external view returns (address);
function allPairsLength() external view returns (uint256);
function createPair(address tokenA, address tokenB)
external
returns (address pair);
function feeTo() external view returns (address);
function feeToSetter() external view returns (address);
function getPair(address, address) external view returns (address);
function setFeeTo(address _feeTo) external;
function setFeeToSetter(address _feeToSetter) external;
}
pragma solidity ^0.8.19;
/**
* @title SafeMath
* @dev Math operations with safety checks that throw on error
*/
library SafeMath {
/**
* @dev Multiplies two numbers, throws on overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256 c) {
if (a == 0) {
return 0;
}
c = a * b;
assert(c / a == b);
return c;
}
/**
* @dev Integer division of two numbers, truncating the quotient.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
// assert(b > 0); // Solidity automatically throws when dividing by 0
// uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return a / b;
}
/**
* @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
assert(b <= a);
return a - b;
}
/**
* @dev Adds two numbers, throws on overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256 c) {
c = a + b;
assert(c >= a);
return c;
}
}