? ? ApeSwap一個去中心化的交易所,既有類似Uniswap的TokenA/TokenB兌換,又有類似SushiSwap的質押挖礦,其工廠合約、路由合約、配對合約參考了Uniswap V2,BananaToken、MasterApe合約參考SushiSwap的SushiToken和MasterChef,具體如下:
-
ApeFactory合約
https://bscscan.com/address/0x0841BD0B734E4F5853f0dD8d7Ea041c241fb0Da6#code
參考 UniswapV2的UniswapV2Factory -
ApeRouter合約
https://bscscan.com/address/0xcF0feBd3f17CEf5b47b0cD257aCf6025c5BFf3b7#code
參考UniswapV2的UniswapV2Router02 -
BananaToken合約
https://bscscan.com/address/0x603c7f932ED1fc6575303D8Fb018fDCBb0f39a95#code
參考 SushiSwap的SushiToken -
MasterApe合約
https://bscscan.com/address/0x5c8D727b265DBAfaba67E050f2f739cAeEB4A6F9#code
參考SushiSwap的MasterChef -
Timelock合約
https://bscscan.com/address/0x2F07969090a2E9247C761747EA2358E5bB033460#code
參考SushiSwap的Timelock
1、協議抽成 Φ {\Phi} Φ
? ? 查看ApeSwap的配對合約: ApePair.sol的swap()函式,可知它仍然采用AMM機制,手續費抽成改成了2/1000 = 0.2%,
function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external lock {
require(amount0Out > 0 || amount1Out > 0, 'ApeSwap: INSUFFICIENT_OUTPUT_AMOUNT');
(uint112 _reserve0, uint112 _reserve1,) = getReserves(); // gas savings
require(amount0Out < _reserve0 && amount1Out < _reserve1, 'ApeSwap: INSUFFICIENT_LIQUIDITY');
uint balance0;
uint balance1;
{ // scope for _token{0,1}, avoids stack too deep errors
address _token0 = token0;
address _token1 = token1;
require(to != _token0 && to != _token1, 'ApeSwap: INVALID_TO');
if (amount0Out > 0) _safeTransfer(_token0, to, amount0Out); // optimistically transfer tokens
if (amount1Out > 0) _safeTransfer(_token1, to, amount1Out); // optimistically transfer tokens
if (data.length > 0) IApeCallee(to).pancakeCall(msg.sender, amount0Out, amount1Out, data);
balance0 = IERC20(_token0).balanceOf(address(this));
balance1 = IERC20(_token1).balanceOf(address(this));
}
uint amount0In = balance0 > _reserve0 - amount0Out ? balance0 - (_reserve0 - amount0Out) : 0;
uint amount1In = balance1 > _reserve1 - amount1Out ? balance1 - (_reserve1 - amount1Out) : 0;
require(amount0In > 0 || amount1In > 0, 'ApeSwap: INSUFFICIENT_INPUT_AMOUNT');
{ // scope for reserve{0,1}Adjusted, avoids stack too deep errors
//手續費抽成為2/1000 == 0.2%
uint balance0Adjusted = balance0.mul(1000).sub(amount0In.mul(2));
uint balance1Adjusted = balance1.mul(1000).sub(amount1In.mul(2));
require(balance0Adjusted.mul(balance1Adjusted) >= uint(_reserve0).mul(_reserve1).mul(1000**2), 'ApeSwap: K');
}
_update(balance0, balance1, _reserve0, _reserve1);
emit Swap(msg.sender, amount0In, amount1In, amount0Out, amount1Out, to);
}
? ? 查看ApeSwap.sol里的 _mintFee()函式,可知給開發團隊是1/4,給LP提供者是3/4,
function _mintFee(uint112 _reserve0, uint112 _reserve1) private returns (bool feeOn) {
address feeTo = IApeFactory(factory).feeTo();
feeOn = feeTo != address(0);
uint _kLast = kLast; // gas savings
if (feeOn) {
if (_kLast != 0) {
uint rootK = Math.sqrt(uint(_reserve0).mul(_reserve1));
uint rootKLast = Math.sqrt(_kLast);
if (rootK > rootKLast) {
uint numerator = totalSupply.mul(rootK.sub(rootKLast));
//抽取1/4給開發團隊,剩下1-1/4=3/4給LP提供者
uint denominator = rootK.mul(3).add(rootKLast);
uint liquidity = numerator / denominator;
if (liquidity > 0) _mint(feeTo, liquidity);
}
}
} else if (_kLast != 0) {
kLast = 0;
}
}
? ? 根據UniswapV2白皮書,LP令牌的鑄造公式,如公式(6)所示:
? ? 這個_mint()函式,實際上就是求公式(6)里的LP令牌數
S
m
S_m
Sm?
? ? 由代碼:uint denominator = rootK.mul(3).add(rootKLast) 可知如下:
1
Φ
?
1
=
3
{\frac{1}{\Phi}} - 1 = 3
Φ1??1=3
? ? 即
Φ
=
1
4
{{\Phi}} = {\frac{1}{4}}
Φ=41?
? ? 可知,協議抽成為1/4,
? ? 即在ApeSwap的配對合約中,手續費仍然是0.2%,但協議抽成比例改成了1/4,即從這0.2%中再抽取1/4給開發團隊,剩余的給LP提供者,下面介紹ApeSwap的審查流程,
2 下載ApeSwap工程
? ? 地址:https://github.com/ApeSwapFinance/apeswap-banana-farm
3 修改配置和安裝依賴包
? ? 將下載的apeswap-banana-farm-master.zip解壓,然后將工程檔案夾名稱改為apeswap-banana-farm,
3.1 修改yarn.lock
? ? 由于dependencies欄位下的ethereumjs-abi需要手動指定版本號,故在yarn.lock的第3729行,改成如下:
dependencies:
ethereumjs-abi "0.6.8"
3.2 安裝依賴包
cd apeswap-banana-farm
sudo yarn install
4 編譯合約
? ? a) 在ganache設定IP為127.0.0.1,埠為8545,重啟ganache
? ? b)打開一個黑框框終端,依次輸入如下命令:
## 進入工程
cd apeswap-banana-farm
## 打開truffle控制臺
truffle console
## 編譯智能合約
compile
## 退出truffle
## 按Ctrl+C、Ctrl+D 退出truffle
5 用Slither檢查合約
5.1 用相對路徑代替@
? ? 由于Slither不支持@方式的代碼匯入,所以需要用相對路徑來代替@,比如
## 修改前
import "@pancakeswap/pancake-swap-lib/contracts/token/BEP20/BEP20.sol";
## 修改后
import "../node_modules/@pancakeswap/pancake-swap-lib/contracts/token/BEP20/BEP20.sol";
? ? 即在apeswap-banana-farm/contracts的每個合約檔案里,用 …/node_modules/@pancakeswap 替換 @pancakeswap
5.2 啟動Docker
? ? 在桌面的任務欄找到Docker,雙擊啟動它,然后,打開Slither實體,命令如下:
## 在Slither實體
docker run -it -v /Users/apple/Downloads/ShenJi/20211012/apeswap-banana-farm:/contract trailofbits/eth-security-toolbox
## 進入/contract目錄
cd /contract
5.3 檢查合約
? ? a) 檢查BananaToken合約
slither ./contracts/BananaToken.sol --solc /usr/bin/solc-v0.6.12
? ? b) 檢查BEP20RewardApe合約
slither ./contracts/BEP20RewardApe.sol --solc /usr/bin/solc-v0.6.12
? ? c) 檢查BEP20RewardApeV2合約
slither ./contracts/BEP20RewardApeV2.sol --solc /usr/bin/solc-v0.6.12
? ? d) 檢查BNBRewardApe合約
slither ./contracts/BNBRewardApe.sol --solc /usr/bin/solc-v0.6.12
? ? e) 檢查BnbStaking合約
slither ./contracts/BnbStaking.sol --solc /usr/bin/solc-v0.6.12
? ? f) 查LotteryRewardPool合約
slither ./contracts/LotteryRewardPool.sol --solc /usr/bin/solc-v0.6.12
? ? g) 檢查MasterApe合約
slither ./contracts/MasterApe.sol --solc /usr/bin/solc-v0.6.12
? ? 注意,Slither的誤報率比較高,約為40%,這些有歧義的報錯,需要進行人工走讀代碼,進行審計,
參考文獻
【1】UniswapV2 白皮書
【2】UinswapV2計算公式
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/330956.html
標籤:區塊鏈
上一篇:UDF使用陣列拆分列中的字串
