如何在PancakeSwap控制单个钱包流动性供给上限至总供应量3%?
能否在PancakeSwap限制单个钱包的流动性供给量?
可行性结论
能实现,但没法直接用PancakeSwap官方合约完成——你得自定义合约来限制单个钱包的流动性存入上限。PancakeSwap的核心AMM合约(比如UniswapV2Pair)本身没内置单钱包额度限制逻辑,必须通过额外的合约层或者修改相关合约来达成需求。你的目标(单钱包上限为总供应量3200万的3%,即960万代币)完全可以实现。
实现方案与代码示例
方案:自定义流动性代理合约
写一个代理合约,要求用户必须通过这个合约向PancakeSwap添加流动性。合约在执行添加操作前,会检查该钱包已存入的流动性对应的目标代币量是否超过960万的上限。
以下是核心Solidity代码示例(适配BSC网络):
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "@pancakeswap/pancake-swap-core/contracts/interfaces/IPancakePair.sol"; import "@pancakeswap/pancake-swap-core/contracts/interfaces/IPancakeFactory.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; // 加入重入防护,避免安全漏洞 contract LiquidityLimiter is ReentrancyGuard { IPancakeFactory public immutable factory; address public immutable targetToken; address public immutable quoteToken; // 比如WBNB address public pair; uint256 public constant MAX_PER_WALLET = 9_600_000 * 10**18; // 假设目标代币是18位小数,按需调整 constructor(address _factory, address _targetToken, address _quoteToken) { factory = IPancakeFactory(_factory); targetToken = _targetToken; quoteToken = _quoteToken; pair = factory.getPair(_targetToken, _quoteToken); require(pair != address(0), "Liquidity pair doesn't exist"); } // 计算用户已存入的流动性对应的目标代币数量 function getUserDepositedTargetToken(address user) public view returns (uint256) { uint256 userLPBalance = IPancakePair(pair).balanceOf(user); uint256 totalLP = IPancakePair(pair).totalSupply(); if (totalLP == 0) return 0; // 判断目标代币是reserve0还是reserve1 bool isTargetToken0 = IPancakePair(pair).token0() == targetToken; uint256 targetReserve = isTargetToken0 ? IPancakePair(pair).reserve0() : IPancakePair(pair).reserve1(); return (userLPBalance * targetReserve) / totalLP; } // 代理添加流动性,用户需先授权合约转移目标代币和报价代币 function addLiquidity( uint256 targetAmountDesired, uint256 quoteAmountDesired, uint256 targetAmountMin, uint256 quoteAmountMin, address to ) external nonReentrant { uint256 currentDeposited = getUserDepositedTargetToken(msg.sender); // 计算本次添加的目标代币实际数量(按池内比例) (uint256 reserve0, uint256 reserve1, ) = IPancakePair(pair).getReserves(); bool isTargetToken0 = IPancakePair(pair).token0() == targetToken; uint256 targetReserve = isTargetToken0 ? reserve0 : reserve1; uint256 quoteReserve = isTargetToken0 ? reserve1 : reserve0; uint256 targetAmount = targetAmountDesired; uint256 quoteAmount = (targetAmountDesired * quoteReserve) / targetReserve; if (quoteAmount > quoteAmountDesired) { targetAmount = (quoteAmountDesired * targetReserve) / quoteReserve; quoteAmount = quoteAmountDesired; } // 检查是否超过上限 require(currentDeposited + targetAmount <= MAX_PER_WALLET, "Exceeds max liquidity per wallet"); // 转移代币到合约 IERC20(targetToken).transferFrom(msg.sender, address(this), targetAmount); IERC20(quoteToken).transferFrom(msg.sender, address(this), quoteAmount); // 授权给流动性池合约 IERC20(targetToken).approve(pair, targetAmount); IERC20(quoteToken).approve(pair, quoteAmount); // 调用PancakeSwap mint流动性 (uint256 targetOut, uint256 quoteOut, uint256 liquidity) = IPancakePair(pair).mint(to); // 退回多余的代币给用户 if (targetOut < targetAmount) { IERC20(targetToken).transfer(msg.sender, targetAmount - targetOut); } if (quoteOut < quoteAmount) { IERC20(quoteToken).transfer(msg.sender, quoteAmount - quoteOut); } } }
关键说明
- 依赖与部署:部署时需要传入PancakeSwap工厂合约地址(BSC主网:
0xcA143Ce32Fe78f1f7019d7d551a6402fC5350c73)、你的目标代币地址和报价代币地址(比如WBNB)。 - 小数位数适配:代码中
MAX_PER_WALLET假设代币是18位小数,如果你的代币小数位数不同,要调整10**18为对应值。 - 安全防护:加入了
ReentrancyGuard防止重入攻击,部署前务必在测试网(如BSC Testnet)做全面测试。
替代方案
如果你是自定义代币的发行方,也可以在代币合约中添加逻辑:当用户将代币转入PancakeSwap流动性池时,检查该用户已存入池中的代币总量是否超过上限。但这种方式只能限制单方向的代币存入,灵活性不如代理合约。
内容的提问来源于stack exchange,提问作者user3033562
相关产品推荐
相关产品推荐

