一、说明
在bsc链上常见的持币分红usdt的原理如下:
通过用户钱包地址里持有的本币数量,映射分红派发器铸造mint的分红tracker跟踪币BABYTOKENDividendTracker。通过筛选条件需要限制持币数量达到指定值时才能接收到持币分红兑换的usdt,因此不能直接以持有的本币作为分发的权重指标,必须mint一个分红跟踪tracker币BABYTOKENDividendTracker,满足分红usdt条件的钱包地址就mint铸造BABYTOKENDividendTracker币种,以BABYTOKENDividendTracker币种的数量和权重作为usdt分发的依据。
随着bsc链上交易手续费gas的升高,每笔本币的交易不但需要执行本币的transfer方法还需要执行BABYTOKENDividendTracker币种的mint或者burn方法,以保证BABYTOKENDividendTracker币种的数量和权重与本币的数量和权重比例对应统一一致。这就会导致交易的gas费用急剧升高。为了降低交易的整体gas费用,同时实现持币分红usdt的功能,通过以下完整版合约代码实现上述功能。
二、持币分红usdt合约核心代码,功能说明
- 代币构造函数及输入参数格式如下:
constructor(
string memory name_,
string memory symbol_,
uint256 totalSupply_,
address[4] memory addrs, // reward, router, marketing wallet, dividendTracker
uint256[4] memory buyFeeSetting_, // rewards,lp,market,dead
uint256[4] memory sellFeeSetting_,// rewards,lp,market,dead
uint256 tokenBalanceForReward_,
address serviceFeeReceiver_,
uint256 serviceFee_
) payable ERC20(name_, symbol_) {
rewardToken = addrs[0];
_marketingWalletAddress = addrs[2];
buyTokenRewardsFee = buyFeeSetting_[0];
buyLiquidityFee = buyFeeSetting_[1];
buyMarketingFee = buyFeeSetting_[2];
buyDeadFee = buyFeeSetting_[3];
sellTokenRewardsFee = sellFeeSetting_[0];
sellLiquidityFee = sellFeeSetting_[1];
sellMarketingFee = sellFeeSetting_[2];
sellDeadFee = sellFeeSetting_[3];
require(buyTokenRewardsFee.add(buyLiquidityFee).add(buyMarketingFee).add(buyDeadFee) <= 25, "Total buy fee is over 25%");
require(sellTokenRewardsFee.add(sellLiquidityFee).add(sellMarketingFee).add(sellDeadFee) <= 25, "Total sell fee is over 25%");
uint256 totalSupply = totalSupply_ * (10**18);
swapTokensAtAmount = totalSupply.mul(2).div(10**6); // 0.002%
// use by default 300,000 gas to process auto-claiming dividends
gasForProcessing = 300000;
dividendTracker = BABYTOKENDividendTracker(
payable(Clones.clone(addrs[3]))
);
dividendTracker.initialize(
rewardToken,
tokenBalanceForReward_
);
IUniswapV2Router02 _uniswapV2Router = IUniswapV2Router02(addrs[1]);
address _uniswapV2Pair = IUniswapV2Factory(_uniswapV2Router.factory())
.createPair(address(this), _uniswapV2Router.WETH());
uniswapV2Router = _uniswapV2Router;
uniswapPair = _uniswapV2Pair;
_setAutomatedMarketMakerPair(_uniswapV2Pair, true);
// exclude from receiving dividends
dividendTracker.excludeFromDividends(address(dividendTracker));
dividendTracker.excludeFromDividends(address(this));
dividendTracker.excludeFromDividends(owner());
dividendTracker.excludeFromDividends(deadWallet);
dividendTracker.excludeFromDividends(address(_uniswapV2Router));
// exclude from paying fees or having max transaction amount
excludeFromFees(owner(), true);
excludeFromFees(_marketingWalletAddress, true);
excludeFromFees(address(this), true);
_mint(owner(), totalSupply);
payable(serviceFeeReceiver_).transfer(serviceFee_);
}
以上构造函数输入参数:买卖不同的税费,分红币种、营销钱包等合约地址已经代币的元数据信息。
2. 为了扩展后续的dex交易所迁移提供的更换uniswapV2router的接口
function updateUniswapV2Router(address newAddress) public onlyOwner {
require(newAddress != address(uniswapV2Router), "The router already has that address");
emit UpdateUniswapV2Router(newAddress, address(uniswapV2Router));
uniswapV2Router = IUniswapV2Router02(newAddress);
address _uniswapV2Pair = IUniswapV2Factory(uniswapV2Router.factory())
.createPair(address(this), uniswapV2Router.WETH());
uniswapPair = _uniswapV2Pair;
}
3. 代币交易核心transfer功能函数
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");
if(amount == 0) {
super._transfer(from, to, 0);
return;
}
uint256 contractTokenBalance = balanceOf(address(this));
bool canSwap = contractTokenBalance >= swapTokensAtAmount;
if( canSwap &&
!swapping &&
!automatedMarketMakerPairs[from] &&
from != owner() &&
to != owner() &&
swapAndLiquifyEnabled
) {
swapping = true;
if(AmountMarketingFee > 0) swapAndSendToFee(AmountMarketingFee);
if(AmountLiquidityFee > 0) swapAndLiquify(AmountLiquidityFee);
if(AmountTokenRewardsFee > 0) swapAndSendDividends(AmountTokenRewardsFee);
swapping = false;
}
bool takeFee = !swapping;
// if any account belongs to _isExcludedFromFee account then remove the fee
if(_isExcludedFromFees[from] || _isExcludedFromFees[to]) {
takeFee = false;
}
if(takeFee) {
uint256 fees;
uint256 LFee; // Liquidity
uint256 RFee; // Rewards
uint256 MFee; // Marketing
uint256 DFee; // Dead
if(automatedMarketMakerPairs[from]){
LFee = amount.mul(buyLiquidityFee).div(100);
AmountLiquidityFee += LFee;
RFee = amount.mul(buyTokenRewardsFee).div(100);
AmountTokenRewardsFee += RFee;
MFee = amount.mul(buyMarketingFee).div(100);
AmountMarketingFee += MFee;
DFee = amount.mul(buyDeadFee).div(100);
fees = LFee.add(RFee).add(MFee).add(DFee);
}
if(automatedMarketMakerPairs[to]){
LFee = amount.mul(sellLiquidityFee).div(100);
AmountLiquidityFee += LFee;
RFee = amount.mul(sellTokenRewardsFee).div(100);
AmountTokenRewardsFee += RFee;
MFee = amount.mul(sellMarketingFee).div(100);
AmountMarketingFee += MFee;
DFee = amount.mul(sellDeadFee).div(100);
fees = LFee.add(RFee).add(MFee).add(DFee);
}
amount = amount.sub(fees);
if(DFee > 0) super._transfer(from, deadWallet, DFee);
super._transfer(from, address(this), fees.sub(DFee));
}
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 {
}
}
}
4. 持币分红usdt轮询处理下发分红核心代码如下:
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);
}
通过轮询方法分红所有达到触发持币分红usdt条件的钱包地址,控制交易的最大gas费用消耗,确保执行中的卖出交易的钱包地址在触发到该分红条件时不至于因过高的gas费用而放弃卖出交易,从而导致整个系统的交易阻滞。同时,通过全局变量遍历器_lastProcessedIndex 来控制下次触发持币分红usdt时仍然从上次分红的索引处继续向下分红usdt,直到遍历完成所有持币分红usdt数组列表,进入下一轮的分红轮询。
5. 根据用户持有的分红跟踪币BABYTOKENDividendTracker计算持币分红usdt权重的函数
/// @notice Withdraws the ether distributed to the sender.
/// @dev It emits a `DividendWithdrawn` event if the amount of withdrawn ether is greater than 0.
function _withdrawDividendOfUser(address payable user)
internal
returns (uint256)
{
uint256 _withdrawableDividend = withdrawableDividendOf(user);
if (_withdrawableDividend > 0) {
withdrawnDividends[user] = withdrawnDividends[user].add(
_withdrawableDividend
);
emit DividendWithdrawn(user, _withdrawableDividend);
bool success = IERC20(rewardToken).transfer(
user,
_withdrawableDividend
);
if (!success) {
withdrawnDividends[user] = withdrawnDividends[user].sub(
_withdrawableDividend
);
return 0;
}
return _withdrawableDividend;
}
return 0;
}
根据用户持币的BABYTOKENDividendTracker币种的数量计算权重,然后分红usdt到所有满足持币分红usdt的钱包地址里,而不是根据用户持有的本币数量计算,从而筛除掉不满足持币分红usdt的钱包地址。
三、持币分红usdt完整版合约代码如下
合约代码中包括了分红派发器合约BABYTOKENDividendTracker,代币业务主合约Token,初始化迭代映射合约IterableMapping
具体部署方式:先部署相关的功能合约,再部署分红派发器子合约BABYTOKENDividendTracker,最后部署Token业务主合约。
至此,完成bsc链上持币分红usdt轮询分发usdt,通过BABYTOKENDividendTracker降低gas费用的源代码实现所有操作流程。
pdf+视频币安智能链BSC发币教程及多模式组合合约源代码下载:
币安智能链BSC发币(合约部署、开源、锁仓、LP、参数配置、开发、故障处理、工具使用)教程下载:
多模式(燃烧、回流指定营销地址、分红本币及任意币种,邀请推广八代收益,LP加池分红、交易分红、复利分红、NFT分红、自动筑池、动态手续费、定时开盘、回购)组合合约源代码下载:
pdf+视频币安智能链BSC发币教程及多模式组合合约源代码下载地址:
添加VX或者telegram获取全程线上免费指导
评论前必须登录!
注册