一、说明
defi智能合约开发过程中可能会涉及到如下项目需求:项目运营过程中允许用户正常添加流动性,但是撤销流动性的话就需要收取比较高的手续费,并且只是对部分早期参数私募的用户收取高手续费,目的是限制早期参与用户撤销流动性导致资金池底池厚度减小。这样就需要将早期用户的钱包地址加入私募地址列表,私募地址列表中的用户撤销流动性时收取高额的手续费。同时,禁止私募用户将LP从私募钱包转移到其他钱包地址,从而逃避撤销流动性的高手续费的限制。普通用户正常添加撤销流动性,不受撤销流动性的高手续费限制。
实现上述功能的合约主要有以下几个需求点:
- 合约可以正常识别添加和撤销流动性的动作。在合约交易过程中有五种动作行为:买入,卖出,钱包之间转账,添加流动性,撤销流动性。合约需要可以正确识别上述交易行为,才能根据不同的交易行为设置不同的交易税费,并且对添加流动性和撤销流动性设置单独的限制条件。
- 合约中记录用户添加流动性后获取的LP数量和实际的LP数量必须一致。当用户添加流动性时同步用户实际获取的LP数量到合约中,记录用户实际持有的LP数量。
- 当用户撤销流动性时,校验用户持有的LP数量是否匹配实际需要撤销的LP数量,如果合约中记录的用户持有的LP数量大于用户实际撤销的LP数量,则允许用户撤销流动性。如果合约中记录的LP数量小于用户实际撤销的LP数量,则不允许用户用户撤销流动性。通过合约中记录的LP数量和实际的LP数量的一致性验证,保障不允许用户转移LP到其他钱包地址,即使用户转移LP到其他钱包地址也不能撤销流动性,从而绕开私募用户撤销流动性的高手续费限制。
二、主要业务流程
a. 普通用户可以正常添加和撤销流动性,并且设置添加和撤销流动性无手续费
b. 早期参与用户可以正常添加流动性,但是撤销流动性时需要收取高额的撤销流动性手续费
c. 早期参与用户不能转移LP到钱包钱包地址,从而绕开撤销流动性的高手续费限制
d. 用户持币数量达到指定数量后可以获取usdt的分红
e. 用户添加流动性LP分红usdt,添加流动性的LP数量达到指定要求的阈值时,可以获取LP分红usdt
f. 为了保证流动性的底池不因用户的卖单而出现快速的缩小,需要单边燃烧资金池中的代币,实现代币价格被动上涨的效果。同时,用户在撤销LP流动性时仍然可以获得资金池通缩后的usdt和代币数量。
三、核心源代码实现
- 识别添加流动性行为的逻辑代码函数
function _isAddLiquidity(uint256 amount) internal view returns (uint256 liquidity) {
(uint256 rOther, uint256 rThis, uint256 balanceOther) = _getReserves();
uint256 amountOther;
if (rOther > 0 && rThis > 0) {
amountOther = amount * rOther / rThis;
}
//isAddLP
if (balanceOther >= rOther + amountOther) {
(liquidity,) = calLiquidity(balanceOther, amount, rOther, rThis);
}
}
2. 判断撤销流动性行为的逻辑代码函数片段
function _isRemoveLiquidity(uint256 amount) internal view returns (uint256 liquidity) {
(uint256 rOther, , uint256 balanceOther) = _getReserves();
//isRemoveLP
if (balanceOther <= rOther) {
liquidity = (amount * IUniswapV2Pair(liquidityMainPair).totalSupply() + 1) /
(balanceOf(liquidityMainPair) - amount - 1);
}
}
3. 计算用户添加流动性后实际获取LP数量,同步合约中LP数量和实际获取的LP数量的函数代码
function calLiquidity(
uint256 balanceA,
uint256 amount,
uint256 r0,
uint256 r1
) private view returns (uint256 liquidity, uint256 feeToLiquidity) {
uint256 pairTotalSupply = IUniswapV2Pair(liquidityMainPair).totalSupply();
address feeTo = IUniswapV2Factory(uniswapV2Router.factory()).feeTo();
bool feeOn = feeTo != address(0);
uint256 _kLast = IUniswapV2Pair(liquidityMainPair).kLast();
if (feeOn) {
if (_kLast != 0) {
uint256 rootK = SafeMath.sqrt(r0 * r1);
uint256 rootKLast = SafeMath.sqrt(_kLast);
if (rootK > rootKLast) {
uint256 numerator = pairTotalSupply * (rootK - rootKLast) * 8;
uint256 denominator = rootK * 17 + (rootKLast * 8);
feeToLiquidity = numerator / denominator;
if (feeToLiquidity > 0) pairTotalSupply += feeToLiquidity;
}
}
}
uint256 amount0 = balanceA - r0;
if (pairTotalSupply == 0) {
liquidity = SafeMath.sqrt(amount0 * amount) - 1000;
} else {
liquidity = SafeMath.min(
(amount0 * pairTotalSupply) / r0,
(amount * pairTotalSupply) / r1
);
}
}
4. 轮询方式实现LP分红usdt的合约代码实现。用户添加流动性即可获取LP,通过持有LP可以定期轮询方式给所有添加流动性的用户分红usdt
function processLiquidityReward(uint256 gas) private {
if (progressLPRewardBlock.add(progressLPRewardBlockDebt) > block.number) {
return;
}
IERC20 CAKE = IERC20(rewardToken);
uint256 balance = CAKE.balanceOf(address(this));
if (balance < lpRewardCondition) {
return;
}
IERC20 lpToken = IERC20(liquidityMainPair);
uint lpTokenTotal = lpToken.totalSupply() - lpToken.balanceOf(deadWallet) - lpToken.balanceOf(zeroWallet);
address shareHolder;
uint256 tokenBalance;
uint256 amount;
uint256 shareholderCount = holders.length;
uint256 gasUsed = 0;
uint256 iterations = 0;
uint256 gasLeft = gasleft();
while (gasUsed < gas && iterations < shareholderCount) {
if (currentIndex >= shareholderCount) {
currentIndex = 0;
}
shareHolder = holders[currentIndex];
tokenBalance = lpToken.balanceOf(shareHolder);
if (tokenBalance > 0 && !excludeHolder[shareHolder]) {
amount = balance.mul(tokenBalance).div(lpTokenTotal);
if (amount > 0) {
CAKE.transfer(shareHolder, amount);
}
}
gasUsed = gasUsed + (gasLeft - gasleft());
gasLeft = gasleft();
currentIndex++;
iterations++;
}
progressLPRewardBlock = block.number;
}
5. 初始化早期私募用户LP数量的接口函数,通过该函数可以设置用户的初始化参与私募获取的LP数量,lp锁定数量,lp线性释放比例和频率。通过LP的线性释放可以有限的控制盘面不会出现短期的砸盘导致的资金池崩盘现象。
function initLPLockAmounts(address[] memory accounts, uint256 lpAmount) public onlyOwner {
uint256 len = accounts.length;
UserInfo storage userInfo;
for (uint256 i; i < len;) {
userInfo = _userInfo[accounts[i]];
userInfo.lpAmount = lpAmount;
userInfo.lockLPAmount = lpAmount;
unchecked{
++i;
}
}
}
四、完整版本合约代码
源码及合约部署、开源、上线交易所、动态参数配置教程下载地址:
五、综述
融合持币分红usdt和LP分红usdt的合约开发难度比较大,并且配合其他交易税率滑点限制。需要精确计算两种分红的比例已经需要的消耗的gas费用,保证用户支付最低数量的gas费用,同时,确保交易的成功。另外涉及到代币的通缩模型和跟单分红模型,跟单代币要实时的从资金池通缩到直到地址一加速代币的销毁机制,保证资金池的代币价格稳定。由于持币分红usdt和LP分红usdt两种分红模式的机制不同(持币分红派发tricker,lp加权分红)导致融合两种模式功能开发难度很大。
至此,完成DEFI智能合约开发过程中怎样限制用户添加流动性后不允许转移LP到其他钱包,然后使用该钱包撤销流动性LP所有操作流程。
pdf+视频币安智能链BSC发币教程及多模式组合合约源代码下载:
币安智能链BSC发币(合约部署、开源、锁仓、LP、参数配置、开发、故障处理、工具使用)教程下载:
多模式(燃烧、回流指定营销地址、分红本币及任意币种,邀请推广八代收益,LP加池分红、交易分红、复利分红、NFT分红、自动筑池、动态手续费、定时开盘、回购)组合合约源代码下载:
pdf+视频币安智能链BSC发币教程及多模式组合合约源代码下载地址:
添加VX或者telegram获取全程线上免费指导
评论前必须登录!
注册