Skip to content

Instantly share code, notes, and snippets.

@jdunn7
Created August 5, 2021 04:49
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save jdunn7/b36a3771cd799677b6c404a46df54aa1 to your computer and use it in GitHub Desktop.
Save jdunn7/b36a3771cd799677b6c404a46df54aa1 to your computer and use it in GitHub Desktop.
please help me fix this code, trying to have a 5% tax, 3% in BNB rewards and 1% to burn, 1% to liquidity
// SPDX-License-Identifier: Unlicensed
pragma solidity ^0.6.2;
import "./DividendPayingToken.sol";
import "./SafeMath.sol";
import "./IterableMapping.sol";
import "./Ownable.sol";
import "./IUniswapV2Pair.sol";
import "./IUniswapV2Factory.sol";
import "./IUniswapV2Router.sol";
contract GoldenShibaInu is ERC20, Ownable {
using SafeMath for uint256;
IUniswapV2Router02 public uniswapV2Router;
address public immutable uniswapV2Pair;
address public immutable deadAddress = 0x000000000000000000000000000000000000dEaD;
mapping (address => bool) public _isBlacklisted;
bool private swapping;
GSHIBDividendTracker public dividendTracker;
address public liquidityWallet;
uint256 public maxSellTransactionAmount = 1000000000 * (10**9);
uint256 public swapTokensAtAmount = 3000000 * (10**9);
uint256 public BNBRewardsFee;
uint256 public buyBackFee;
uint256 public liquidityFee;
uint256 public totalFees;
uint256 public buyBackUpperLimit = 1 * 10**9;
bool public buyBackEnabled = true;
bool public swapEnabled = false;
// use by default 300,000 gas to process auto-claiming dividends
uint256 public gasForProcessing = 300000;
mapping (address => bool) private _isExcludedFromFees;
// store addresses that a automatic market maker pairs. Any transfer *to* these addresses
// could be subject to a maximum transfer amount
mapping (address => bool) public automatedMarketMakerPairs;
event UpdateDividendTracker(address indexed newAddress, address indexed oldAddress);
event UpdateUniswapV2Router(address indexed newAddress, address indexed oldAddress);
event ExcludeFromFees(address indexed account, bool isExcluded);
event ExcludeMultipleAccountsFromFees(address[] accounts, bool isExcluded);
event SetAutomatedMarketMakerPair(address indexed pair, bool indexed value);
event LiquidityWalletUpdated(address indexed newLiquidityWallet, address indexed oldLiquidityWallet);
event GasForProcessingUpdated(uint256 indexed newValue, uint256 indexed oldValue);
event SwapAndLiquify(
uint256 tokensSwapped,
uint256 ethReceived,
uint256 tokensIntoLiqudity
);
event SwapETHForTokens(
uint256 amountIn,
address[] path
);
event SendDividends(
uint256 tokensSwapped,
uint256 amount
);
event ProcessedDividendTracker(
uint256 iterations,
uint256 claims,
uint256 lastProcessedIndex,
bool indexed automatic,
uint256 gas,
address indexed processor
);
modifier lockTheSwap {
swapping = true;
_;
swapping = false;
}
constructor() public ERC20("Golden Shiba Inu", "GSHIB") {
uint256 _BNBRewardsFee = 3;
uint256 _buyBackFee = 1;
uint256 _liquidityFee = 1;
BNBRewardsFee = _BNBRewardsFee;
buyBackFee = _buyBackFee;
liquidityFee = _liquidityFee;
totalFees = _BNBRewardsFee.add(_buyBackFee).add(_liquidityFee);
dividendTracker = new GSHIBDividendTracker();
liquidityWallet = owner();
IUniswapV2Router02 _uniswapV2Router = IUniswapV2Router02(0xD99D1c33F9fC3444f8101754aBC46c52416550D1);
// Create a uniswap pair for this new token
address _uniswapV2Pair = IUniswapV2Factory(_uniswapV2Router.factory())
.createPair(address(this), _uniswapV2Router.WETH());
uniswapV2Router = _uniswapV2Router;
uniswapV2Pair = _uniswapV2Pair;
_setAutomatedMarketMakerPair(_uniswapV2Pair, true);
// exclude from receiving dividends
dividendTracker.excludeFromDividends(address(dividendTracker));
dividendTracker.excludeFromDividends(address(this));
dividendTracker.excludeFromDividends(owner());
dividendTracker.excludeFromDividends(address(_uniswapV2Router));
// exclude from paying fees or having max transaction amount
excludeFromFees(liquidityWallet, true);
excludeFromFees(address(this), true);
/*
_mint is an internal function in ERC20.sol that is only called here,
and CANNOT be called ever again
*/
_mint(owner(), 1000000000 * (10**9));
}
receive() external payable {
}
function updateDividendTracker(address newAddress) public onlyOwner {
require(newAddress != address(dividendTracker), "GSHIB: The dividend tracker already has that address");
GSHIBDividendTracker newDividendTracker = GSHIBDividendTracker(payable(newAddress));
require(newDividendTracker.owner() == address(this), "GSHIB: The new dividend tracker must be owned by the GSHIB token contract");
newDividendTracker.excludeFromDividends(address(newDividendTracker));
newDividendTracker.excludeFromDividends(address(this));
newDividendTracker.excludeFromDividends(owner());
newDividendTracker.excludeFromDividends(address(uniswapV2Router));
emit UpdateDividendTracker(newAddress, address(dividendTracker));
dividendTracker = newDividendTracker;
}
function updateUniswapV2Router(address newAddress) public onlyOwner {
require(newAddress != address(uniswapV2Router), "GSHIB: The router already has that address");
emit UpdateUniswapV2Router(newAddress, address(uniswapV2Router));
uniswapV2Router = IUniswapV2Router02(newAddress);
}
function excludeFromFees(address account, bool excluded) public onlyOwner {
require(_isExcludedFromFees[account] != excluded, "GSHIB: Account is already the value of 'excluded'");
_isExcludedFromFees[account] = excluded;
emit ExcludeFromFees(account, excluded);
}
function excludeMultipleAccountsFromFees(address[] calldata accounts, bool excluded) public onlyOwner {
for(uint256 i = 0; i < accounts.length; i++) {
_isExcludedFromFees[accounts[i]] = excluded;
}
emit ExcludeMultipleAccountsFromFees(accounts, excluded);
}
function setAutomatedMarketMakerPair(address pair, bool value) public onlyOwner {
require(pair != uniswapV2Pair, "GSHIB: The PancakeSwap pair cannot be removed from automatedMarketMakerPairs");
_setAutomatedMarketMakerPair(pair, value);
}
function _setAutomatedMarketMakerPair(address pair, bool value) private {
require(automatedMarketMakerPairs[pair] != value, "GSHIB: Automated market maker pair is already set to that value");
automatedMarketMakerPairs[pair] = value;
if(value) {
dividendTracker.excludeFromDividends(pair);
}
emit SetAutomatedMarketMakerPair(pair, value);
}
function updateLiquidityWallet(address newLiquidityWallet) public onlyOwner {
require(newLiquidityWallet != liquidityWallet, "GSHIB: The liquidity wallet is already this address");
excludeFromFees(newLiquidityWallet, true);
emit LiquidityWalletUpdated(newLiquidityWallet, liquidityWallet);
liquidityWallet = newLiquidityWallet;
}
function updateGasForProcessing(uint256 newValue) public onlyOwner {
require(newValue >= 200000 && newValue <= 500000, "GSHIB: gasForProcessing must be between 200,000 and 500,000");
require(newValue != gasForProcessing, "GSHIB: Cannot update gasForProcessing to same value");
emit GasForProcessingUpdated(newValue, gasForProcessing);
gasForProcessing = newValue;
}
function updateClaimWait(uint256 claimWait) external onlyOwner {
dividendTracker.updateClaimWait(claimWait);
}
function getClaimWait() external view returns(uint256) {
return dividendTracker.claimWait();
}
function getTotalDividendsDistributed() external view returns (uint256) {
return dividendTracker.totalDividendsDistributed();
}
function isExcludedFromFees(address account) public view returns(bool) {
return _isExcludedFromFees[account];
}
function withdrawableDividendOf(address account) public view returns(uint256) {
return dividendTracker.withdrawableDividendOf(account);
}
function dividendTokenBalanceOf(address account) public view returns (uint256) {
return dividendTracker.balanceOf(account);
}
function getAccountDividendsInfo(address account)
external view returns (
address,
int256,
int256,
uint256,
uint256,
uint256,
uint256,
uint256) {
return dividendTracker.getAccount(account);
}
function getAccountDividendsInfoAtIndex(uint256 index)
external view returns (
address,
int256,
int256,
uint256,
uint256,
uint256,
uint256,
uint256) {
return dividendTracker.getAccountAtIndex(index);
}
function withdraw(uint256 weiAmount) external onlyOwner {
require(address(this).balance >= weiAmount);
msg.sender.transfer(weiAmount);
}
function processDividendTracker(uint256 gas) external {
(uint256 iterations, uint256 claims, uint256 lastProcessedIndex) = dividendTracker.process(gas);
emit ProcessedDividendTracker(iterations, claims, lastProcessedIndex, false, gas, tx.origin);
}
function claim() external {
dividendTracker.processAccount(msg.sender, false);
}
function getLastProcessedIndex() external view returns(uint256) {
return dividendTracker.getLastProcessedIndex();
}
function getNumberOfDividendTokenHolders() external view returns(uint256) {
return dividendTracker.getNumberOfTokenHolders();
}
function setMaxSellTxAMount(uint256 amount) external onlyOwner{
maxSellTransactionAmount = amount;
}
function setSwapTokensAmt(uint256 amt) external onlyOwner{
swapTokensAtAmount = amt;
}
function setBNBRewardsFee(uint256 value) external onlyOwner{
BNBRewardsFee = value;
}
function setLiquidityFee(uint256 value) external onlyOwner{
liquidityFee = value;
}
function addToBlackList(address[] calldata addresses) external onlyOwner {
for (uint256 i; i < addresses.length; ++i) {
_isBlacklisted[addresses[i]] = true;
}
}
function removeFromBlackList(address account) external onlyOwner {
_isBlacklisted[account] = false;
}
function setSwapEnabled(bool value) external onlyOwner{
swapEnabled = value;
}
function setBuyBackFee(uint256 value) external onlyOwner{
buyBackFee = value;
}
function _transfer(
address from,
address to,
uint256 amount
) internal override {
require(from != address(0), "ERC20: transfer from the zero address");
require(to != address(0), "ERC20: transfer to the zero address");
require(!_isBlacklisted[from] && !_isBlacklisted[to], "This address is blacklisted");
if(amount == 0) {
super._transfer(from, to, 0);
return;
}
if(
!swapping &&
automatedMarketMakerPairs[to] && // sells only by detecting transfer to automated market maker pair
from != address(uniswapV2Router) && //router -> pair is removing liquidity which shouldn't have max
!_isExcludedFromFees[to] //no max for those excluded from fees
) {
require(amount <= maxSellTransactionAmount, "Sell transfer amount exceeds the maxSellTransactionAmount.");
}
uint256 contractTokenBalance = balanceOf(address(this));
bool overMinimumTokenBalance = contractTokenBalance >= swapTokensAtAmount;
if(swapEnabled && !swapping && to == uniswapV2Pair ) {
uint256 balance = address(this).balance;
if (buyBackEnabled && balance > uint256(1 * 10**15)) {
if (balance > buyBackUpperLimit)
balance = buyBackUpperLimit;
buyBackTokens(balance.div(100));
}
if (overMinimumTokenBalance) {
contractTokenBalance = swapTokensAtAmount;
uint256 swapTokens = contractTokenBalance.mul(liquidityFee).div(totalFees);
swapAndLiquify(swapTokens);
contractTokenBalance = balanceOf(address(this));
uint256 buyBackTokens = contractTokenBalance.mul(buyBackFee).div(totalFees);
swapBuyBackTokens(buyBackTokens);
uint256 sellTokens = balanceOf(address(this));
swapAndSendDividends(sellTokens);
}
}
bool takeFee = true;
// if any account belongs to _isExcludedFromFee account then remove the fee
if(_isExcludedFromFees[from] || _isExcludedFromFees[to]) {
takeFee = false;
}
if(takeFee) {
uint256 fees = amount.mul(totalFees).div(100);
amount = amount.sub(fees);
super._transfer(from, address(this), fees);
}
super._transfer(from, to, amount);
try dividendTracker.setBalance(payable(from), balanceOf(from)) {} catch {}
try dividendTracker.setBalance(payable(to), balanceOf(to)) {} catch {}
if(!swapping) {
uint256 gas = gasForProcessing;
try dividendTracker.process(gas) returns (uint256 iterations, uint256 claims, uint256 lastProcessedIndex) {
emit ProcessedDividendTracker(iterations, claims, lastProcessedIndex, true, gas, tx.origin);
}
catch {
}
}
}
function swapAndLiquify(uint256 tokens) private {
// split the contract balance into halves
uint256 half = tokens.div(2);
uint256 otherHalf = tokens.sub(half);
// capture the contract's current ETH balance.
// this is so that we can capture exactly the amount of ETH that the
// swap creates, and not make the liquidity event include any ETH that
// has been manually sent to the contract
uint256 initialBalance = address(this).balance;
// swap tokens for ETH
swapTokensForEth(half); // <- this breaks the ETH -> HATE swap when swap+liquify is triggered
// how much ETH did we just swap into?
uint256 newBalance = address(this).balance.sub(initialBalance);
// add liquidity to uniswap
addLiquidity(otherHalf, newBalance);
emit SwapAndLiquify(half, newBalance, otherHalf);
}
function swapTokensForEth(uint256 tokenAmount) private {
// generate the uniswap pair path of token -> weth
address[] memory path = new address[](2);
path[0] = address(this);
path[1] = uniswapV2Router.WETH();
_approve(address(this), address(uniswapV2Router), tokenAmount);
// make the swap
uniswapV2Router.swapExactTokensForETHSupportingFeeOnTransferTokens(
tokenAmount,
0, // accept any amount of ETH
path,
address(this),
block.timestamp
);
}
function buyBackTokens(uint256 amount) private lockTheSwap{
if (amount > 0) {
swapETHForTokens(amount);
}
}
function swapETHForTokens(uint256 amount) private {
// generate the uniswap pair path of token -> weth
address[] memory path = new address[](2);
path[0] = uniswapV2Router.WETH();
path[1] = address(this);
// make the swap
uniswapV2Router.swapExactETHForTokensSupportingFeeOnTransferTokens{value: amount}(
0, // accept any amount of Tokens
path,
deadAddress, // Burn address
block.timestamp.add(300)
);
emit SwapETHForTokens(amount, path);
}
function swapBuyBackTokens(uint256 tokens) private lockTheSwap{
swapTokensForEth(tokens);
}
function setBuyBackEnabled(bool _enabled) public onlyOwner {
buyBackEnabled = _enabled;
}
function setBuybackUpperLimit(uint256 buyBackLimit) external onlyOwner() {
buyBackUpperLimit = buyBackLimit * 10**9;
}
function addLiquidity(uint256 tokenAmount, uint256 ethAmount) private {
// approve token transfer to cover all possible scenarios
_approve(address(this), address(uniswapV2Router), tokenAmount);
// add the liquidity
uniswapV2Router.addLiquidityETH{value: ethAmount}(
address(this),
tokenAmount,
0, // slippage is unavoidable
0, // slippage is unavoidable
liquidityWallet,
block.timestamp
);
}
function swapAndSendDividends(uint256 tokens) private lockTheSwap{
uint256 initialBalance = address(this).balance;
swapTokensForEth(tokens);
uint256 dividends = address(this).balance.sub(initialBalance);
(bool success,) = address(dividendTracker).call{value: dividends}("");
if(success) {
emit SendDividends(tokens, dividends);
}
}
}
contract GSHIBDividendTracker is DividendPayingToken, Ownable {
using SafeMath for uint256;
using SafeMathInt for int256;
using IterableMapping for IterableMapping.Map;
IterableMapping.Map private tokenHoldersMap;
uint256 public lastProcessedIndex;
mapping (address => bool) public excludedFromDividends;
mapping (address => uint256) public lastClaimTimes;
uint256 public claimWait;
uint256 public immutable minimumTokenBalanceForDividends;
event ExcludeFromDividends(address indexed account);
event ClaimWaitUpdated(uint256 indexed newValue, uint256 indexed oldValue);
event Claim(address indexed account, uint256 amount, bool indexed automatic);
constructor() public DividendPayingToken("GSHIB_Dividend_Tracker", "GSHIB_Dividend_Tracker") {
claimWait = 3600;
minimumTokenBalanceForDividends = 10000 * (10**9); //must hold 10000+ tokens
}
function _transfer(address, address, uint256) internal override {
require(false, "GSHIB_Dividend_Tracker: No transfers allowed");
}
function withdrawDividend() public override {
require(false, "GSHIB_Dividend_Tracker: withdrawDividend disabled. Use the 'claim' function on the main GSHIB contract.");
}
function excludeFromDividends(address account) external onlyOwner {
require(!excludedFromDividends[account]);
excludedFromDividends[account] = true;
_setBalance(account, 0);
tokenHoldersMap.remove(account);
emit ExcludeFromDividends(account);
}
function updateClaimWait(uint256 newClaimWait) external onlyOwner {
require(newClaimWait >= 3600 && newClaimWait <= 604800, "GSHIB_Dividend_Tracker: claimWait must be updated to between 1hr and 7 days");
require(newClaimWait != claimWait, "GSHIB_Dividend_Tracker: Cannot update claimWait to same value");
emit ClaimWaitUpdated(newClaimWait, claimWait);
claimWait = newClaimWait;
}
function getLastProcessedIndex() external view returns(uint256) {
return lastProcessedIndex;
}
function getNumberOfTokenHolders() external view returns(uint256) {
return tokenHoldersMap.keys.length;
}
function getAccount(address _account)
public view returns (
address account,
int256 index,
int256 iterationsUntilProcessed,
uint256 withdrawableDividends,
uint256 totalDividends,
uint256 lastClaimTime,
uint256 nextClaimTime,
uint256 secondsUntilAutoClaimAvailable) {
account = _account;
index = tokenHoldersMap.getIndexOfKey(account);
iterationsUntilProcessed = -1;
if(index >= 0) {
if(uint256(index) > lastProcessedIndex) {
iterationsUntilProcessed = index.sub(int256(lastProcessedIndex));
}
else {
uint256 processesUntilEndOfArray = tokenHoldersMap.keys.length > lastProcessedIndex ?
tokenHoldersMap.keys.length.sub(lastProcessedIndex) :
0;
iterationsUntilProcessed = index.add(int256(processesUntilEndOfArray));
}
}
withdrawableDividends = withdrawableDividendOf(account);
totalDividends = accumulativeDividendOf(account);
lastClaimTime = lastClaimTimes[account];
nextClaimTime = lastClaimTime > 0 ?
lastClaimTime.add(claimWait) :
0;
secondsUntilAutoClaimAvailable = nextClaimTime > block.timestamp ?
nextClaimTime.sub(block.timestamp) :
0;
}
function getAccountAtIndex(uint256 index)
public view returns (
address,
int256,
int256,
uint256,
uint256,
uint256,
uint256,
uint256) {
if(index >= tokenHoldersMap.size()) {
return (0x0000000000000000000000000000000000000000, -1, -1, 0, 0, 0, 0, 0);
}
address account = tokenHoldersMap.getKeyAtIndex(index);
return getAccount(account);
}
function canAutoClaim(uint256 lastClaimTime) private view returns (bool) {
if(lastClaimTime > block.timestamp) {
return false;
}
return block.timestamp.sub(lastClaimTime) >= claimWait;
}
function setBalance(address payable account, uint256 newBalance) external onlyOwner {
if(excludedFromDividends[account]) {
return;
}
if(newBalance >= minimumTokenBalanceForDividends) {
_setBalance(account, newBalance);
tokenHoldersMap.set(account, newBalance);
}
else {
_setBalance(account, 0);
tokenHoldersMap.remove(account);
}
processAccount(account, true);
}
function process(uint256 gas) public returns (uint256, uint256, uint256) {
uint256 numberOfTokenHolders = tokenHoldersMap.keys.length;
if(numberOfTokenHolders == 0) {
return (0, 0, lastProcessedIndex);
}
uint256 _lastProcessedIndex = lastProcessedIndex;
uint256 gasUsed = 0;
uint256 gasLeft = gasleft();
uint256 iterations = 0;
uint256 claims = 0;
while(gasUsed < gas && iterations < numberOfTokenHolders) {
_lastProcessedIndex++;
if(_lastProcessedIndex >= tokenHoldersMap.keys.length) {
_lastProcessedIndex = 0;
}
address account = tokenHoldersMap.keys[_lastProcessedIndex];
if(canAutoClaim(lastClaimTimes[account])) {
if(processAccount(payable(account), true)) {
claims++;
}
}
iterations++;
uint256 newGasLeft = gasleft();
if(gasLeft > newGasLeft) {
gasUsed = gasUsed.add(gasLeft.sub(newGasLeft));
}
gasLeft = newGasLeft;
}
lastProcessedIndex = _lastProcessedIndex;
return (iterations, claims, lastProcessedIndex);
}
function processAccount(address payable account, bool automatic) public onlyOwner returns (bool) {
uint256 amount = _withdrawDividendOfUser(account);
if(amount > 0) {
lastClaimTimes[account] = block.timestamp;
emit Claim(account, amount, automatic);
return true;
}
return false;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment