Contract Source Code:
pragma solidity 0.8.28;
// SPDX-License-Identifier: Unlicensed
contract DappToken {
string public name = "Sonic Test Token";
string public symbol = "STT";
string public standard = "Sonic Test Token v1.0";
uint256 private _totalSupply;
uint256 public decimals = 18;
address public immutable owner;
address public liquidityPool;
// Distribution tracking
uint256 public taxPool;
uint256 public lastDistribution;
uint256 public constant DISTRIBUTION_INTERVAL = 5 minutes;
uint256 public reflectionFee = 5; // Default 5% fee
// Reflection system
uint256 private constant POINT_MULTIPLIER = 10 ** 18;
uint256 private totalDividendPoints;
uint256 private unclaimedDividends;
uint256 private blackListAmount;
// Add new variables for tax distribution
uint256 private constant TAX_DENOMINATOR = 100;
uint256 private lastTaxDistribution;
struct Account {
uint256 balance;
uint256 lastDividendPoints;
}
// State variables
mapping(address => Account) public accounts;
mapping(address => mapping(address => uint256)) public allowance;
mapping(address => bool) private _isExcluded;
mapping(address => bool) private isBlackListed;
// Native token distribution tracking
uint256 private nativeTokenPool;
// Holder tracking
address[] private holders;
mapping(address => bool) private isHolder;
event Transfer(address indexed _from, address indexed _to, uint256 _value);
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
event RewardsDistributed(uint256 amount);
event LiquidityPoolSet(address indexed newPool);
event BlacklistUpdated(address indexed user, bool isBlacklisted);
event NativeTokensReceived(uint256 amount);
event NativeTokensDistributed(address indexed holder, uint256 amount);
modifier onlyOwner() {
require(msg.sender == owner, "Only owner can call");
_;
}
modifier updateAccount(address account) {
uint256 owing = dividendsOwing(account);
if (owing > 0) {
unclaimedDividends -= owing;
accounts[account].balance += owing;
}
accounts[account].lastDividendPoints = totalDividendPoints;
_;
}
constructor() {
owner = msg.sender;
_totalSupply = 1000000000000000;
accounts[msg.sender].balance = _totalSupply;
_isExcluded[msg.sender] = true;
lastDistribution = block.timestamp;
emit Transfer(address(0), msg.sender, _totalSupply);
}
function totalSupply() public view returns (uint256) {
return _totalSupply;
}
function _transfer(address _from, address _to, uint256 _value)
internal
updateAccount(_from)
updateAccount(_to)
{
// Determine transaction type
bool isBuy = _from == liquidityPool;
bool isSell = _to == liquidityPool;
uint256 currentFee;
// Apply 5% tax only on buy/sell transactions
if (_isExcluded[_from]) {
currentFee = 0;
} else {
currentFee = (isBuy || isSell) ? reflectionFee : 0;
}
uint256 rAmount = (_value * currentFee) / TAX_DENOMINATOR;
uint256 amount = _value - rAmount;
// Update balances
accounts[_from].balance -= _value;
accounts[_to].balance += amount;
// Accumulate taxes and update dividend points
if (rAmount > 0) {
// Update dividend points when tax is collected
uint256 totalCirculating = _totalSupply - blackListAmount;
if (totalCirculating > 0) {
totalDividendPoints += (rAmount * POINT_MULTIPLIER) / totalCirculating;
unclaimedDividends += rAmount;
}
}
// Update blacklist tracking
if (isBlackListed[_from]) {
blackListAmount -= _value;
}
if (isBlackListed[_to]) {
blackListAmount += amount;
}
// Track holders for native token distribution
if (accounts[_to].balance == 0 && amount > 0) {
_addHolder(_to);
}
emit Transfer(_from, _to, amount);
}
// Add this new function to set liquidity pool address
function setLiquidityPool(address _pool) external onlyOwner {
require(_pool != address(0), "Invalid pool address");
liquidityPool = _pool;
_isExcluded[_pool] = true;
emit LiquidityPoolSet(_pool);
}
// Modified distribution function with time-based triggering
function distributeRewards() external {
require(
block.timestamp >= lastDistribution + DISTRIBUTION_INTERVAL,
"Must wait 5 minutes between distributions"
);
require(unclaimedDividends > 0 || nativeTokenPool > 0, "No rewards to distribute");
// Distribute token rewards first
if (unclaimedDividends > 0) {
_distributeTaxedTokens();
}
// Then distribute native tokens
if (nativeTokenPool > 0) {
distributeNativeTokens();
}
lastDistribution = block.timestamp;
}
function _distributeTaxedTokens() private {
uint256 totalCirculating = _totalSupply - blackListAmount;
require(totalCirculating > 0, "No eligible holders");
for (uint256 i = 0; i < holders.length; i++) {
address holder = holders[i];
if (!isBlackListed[holder] && !_isExcluded[holder]) {
uint256 owing = dividendsOwing(holder);
if (owing > 0) {
accounts[holder].balance += owing;
unclaimedDividends -= owing;
emit RewardsDistributed(owing);
}
}
}
}
function distributeNativeTokens() private {
uint256 totalCirculating = _totalSupply - blackListAmount;
require(totalCirculating > 0, "No eligible holders");
for (uint256 i = 0; i < holders.length; i++) {
address holder = holders[i];
if (!isBlackListed[holder] && !_isExcluded[holder]) {
uint256 share = (accounts[holder].balance * nativeTokenPool) / totalCirculating;
if (share > 0) {
(bool success, ) = holder.call{value: share}("");
require(success, "Native token transfer failed");
emit NativeTokensDistributed(holder, share);
}
}
}
nativeTokenPool = 0;
}
// Keep existing functions below (unchanged from original except for context) */
function transfer(address _to, uint256 _value) public returns (bool) {
require(accounts[msg.sender].balance >= _value);
_transfer(msg.sender, _to, _value);
return true;
}
function approve(address _spender, uint256 _value) public returns (bool) {
allowance[msg.sender][_spender] = _value;
emit Approval(msg.sender, _spender, _value);
return true;
}
function transferFrom(address _from, address _to, uint256 _value) public returns (bool) {
require(_value <= accounts[_from].balance);
require(_value <= allowance[_from][msg.sender]);
allowance[_from][msg.sender] -= _value;
_transfer(_from, _to, _value);
return true;
}
function dividendsOwing(address account) internal view returns (uint256) {
if (isBlackListed[account]) return 0;
uint256 newDividendPoints = totalDividendPoints - accounts[account].lastDividendPoints;
return (accounts[account].balance * newDividendPoints) / POINT_MULTIPLIER;
}
function balanceOf(address account) public view returns (uint256) {
uint256 owing = dividendsOwing(account);
return accounts[account].balance + owing;
}
function mint(address recipient, uint256 amount) public onlyOwner updateAccount(recipient) {
accounts[recipient].balance += amount;
_totalSupply += amount;
}
function blackList(address user) public onlyOwner updateAccount(user) {
require(user != address(0), "Invalid address");
require(user != owner, "Cannot blacklist owner");
if (!isBlackListed[user]) {
isBlackListed[user] = true;
blackListAmount += accounts[user].balance;
emit BlacklistUpdated(user, true);
}
}
function unBlackList(address user) public onlyOwner updateAccount(user) {
require(user != address(0), "Invalid address");
if (isBlackListed[user]) {
isBlackListed[user] = false;
blackListAmount -= accounts[user].balance;
emit BlacklistUpdated(user, false);
}
}
// Add function to update reflection fee
function setReflectionFee(uint256 _fee) external onlyOwner {
require(_fee <= 10, "Fee cannot exceed 10%");
reflectionFee = _fee;
}
function _addHolder(address account) private {
if (!isHolder[account] && account != address(0) && account != liquidityPool) {
holders.push(account);
isHolder[account] = true;
}
}
// Function to receive native tokens
receive() external payable {
nativeTokenPool += msg.value;
emit NativeTokensReceived(msg.value);
}
}