0%

Crypto-调用pancake合约进行交易

Pre:

最近在看pancakeBunny机枪池的源代码时,看到了他们有个zap功能

Zap 功能本质上允许用户直接从单一资产(BNB)切换到 LP 代币(BNB-CAKE LP),只需单击一个按钮,而无需进行煎饼交换和切换不同的资产

源码里是直接调用pancakeswap router合约,后面打算尝试写个类似的dex dapp玩一下。

现在先试一下如何调用pancakeswap router进行代币的交换。


pancakebunny zap 源码:

贴个函数,solidity的代码量感觉都比较少,多看看多实践应该不难掌握吧~

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 将代币的一半换成另一种代币,然后提供流动性
function zapInToken(address _from, uint amount, address _to) external override {
IBEP20(_from).safeTransferFrom(msg.sender, address(this), amount);
_approveTokenIfNeeded(_from);

if (isFlip(_to)) {
IPancakePair pair = IPancakePair(_to);
address token0 = pair.token0();
address token1 = pair.token1();
if (_from == token0 || _from == token1) {
// swap half amount for other
address other = _from == token0 ? token1 : token0;
_approveTokenIfNeeded(other); // 授权
uint sellAmount = amount.div(2); // 一半的数量
uint otherAmount = _swap(_from, sellAmount, other, address(this)); // 兑换
pair.skim(address(this));
ROUTER.addLiquidity(_from, other, amount.sub(sellAmount), otherAmount, 0, 0, msg.sender, block.timestamp); // 添加流动性
} else {
uint bnbAmount = _from == WBNB ? _safeSwapToBNB(amount) : _swapTokenForBNB(_from, amount, address(this));
_swapBNBToFlip(_to, bnbAmount, msg.sender);
}
} else {
_swap(_from, amount, _to, msg.sender);
}
}

Pancakeswap Router交互

pancakeswap router contract里面共17个函数,如下

流动性相关:

  • addLiquidity

  • addLiquidityETH

  • removeLiquidity

  • removeLiquidityETH

  • removeLiquidityETHSupportingFeeOnTransferTokens

  • removeLiquidityETHWithPermit

  • removeLiquidityETHWithPermitSupportingFeeOnTransferTokens

  • removeLiquidityWithPermit

swap相关:

  • swapETHForExactTokens

  • swapExactETHForTokens

  • swapExactETHForTokensSupportingFeeOnTransferTokens

  • swapExactTokensForETH

  • swapExactTokensForETHSupportingFeeOnTransferTokens

  • swapExactTokensForTokens

  • swapExactTokensForTokensSupportingFeeOnTransferTokens

  • swapTokensForExactETH

  • swapTokensForExactTokens


Swap: BNB -> anyToken

swapExactETHForTokens:

2C5A9C3B-04CF-42FA-9542-72640DFFBC3E

swapExactETHForTokens():

  • amountOutMin:收到最小量

  • path:代币地址列表,eg:[BNB代币地址,anyToken代币地址]

  • to:收币地址

  • deadline:交易过期时间

1
2
3
4
5
6
7
8
9
10
11
12
13
pancakeswap2_txn = contract.functions.swapExactETHForTokens(
# 10000000000, # set to 0, or specify minimum amount of tokeny you want to receive - consider decimals!!!
0,
[spend, tokenToBuy],
sender_address,
(int(time.time()) + 10000)
).buildTransaction({
'from': sender_address,
'value': web3.toWei(0.0001, 'ether'), # This is the Token(BNB) amount you want to Swap from
'gas': 160000,
'gasPrice': web3.toWei('5', 'gwei'),
'nonce': nonce,
})

例子:记录tx

20211014204336


Swap: AToken -> BToken

approve授权:

先要将你的代币授权给pancakeswap router contract

A7140CDA-DE03-4BE6-86B4-1490396BE088

approve():

  • spender:给予授权的地址,这里是要授权给pancakeswap router contract

  • rawAmount:代币数量

1
2
3
4
5
6
7
8
9
10
aprove_txn = erc20_contract.functions.approve(
# 10000000000, # set to 0, or specify minimum amount of tokeny you want to receive - consider decimals!!!
panRouterContractAddress, max_approval_int
).buildTransaction({
'from': sender_address,
'value': 0, # This is the Token(BNB) amount you want to Swap from
'gas': 160000,
'gasPrice': web3.toWei('5', 'gwei'),
'nonce': nonce,
})

例子:记录tx
20211014202846

swapExactTokensForTokens:

C28E659E-C391-4DC5-9A22-C5E78E5C92E7

swapExactTokensForTokens():

  • amountIn:交换数量

  • amountOutMin:收到最小量,考虑滑点

  • path:代币地址列表,一般要有中间代币,eg:[AToken代币地址,中间代币地址,BToken代币地址]

  • to:收币地址

  • deadline:交易过期时间

1
2
3
4
5
6
7
8
9
10
pancakeswap2_txn = contract.functions.swapExactTokensForTokens(
# 10000000000, # set to 0, or specify minimum amount of tokeny you want to receive - consider decimals!!!
web3.toWei(50, 'ether'), web3.toWei(0.04, 'ether'), [tokenToBuy, cake_token, USDT_token], sender_address, (int(time.time()) + 10000)
).buildTransaction({
'from': sender_address,
'value': 0, # This is the Token(BNB) amount you want to Swap from
'gas': 220000,
'gasPrice': web3.toWei('5.1', 'gwei'),
'nonce': nonce,
})

例子:记录tx
20211014204147


Bug:

暂时只遇到以下报错:

TRANSFER_FAILED:

Fail with error 'Pancake: TRANSFER_FAILED':

  • 注意授权

  • 注意gas fee够不够

INSUFFICIENT_OUTPUT_AMOUNT or INSUFFICIENT_INPUT_AMOUNT

Fail with error 'PancakeRouter: INSUFFICIENT_OUTPUT_AMOUNT
Fail with error 'PancakeLibrary: INSUFFICIENT_INPUT_AMOUNT

注意数量单位是wei,可以用web3.toWei('5.1', 'gwei'),转换成gwei


Question:

还有几个问题还有些疑惑:

  1. 调用swapExactTokensForTokens,如何自动获取中间的转换代币?是用BNB还是CAKE?

  2. 通过滑点计算出amountOutMin

  3. gas fee要给多少?才不会过高过低?


Todo:

  1. 部署合约,做个和Zap类似的小dapp

  2. defi自动收菜

    • 定时收菜,每过一段时间(如每月15号),自动collect,然后卖出换U, 甚至进一步可以 将u质押到venus
    • 冲新矿的二矿,有高apr,短时间挖提买,监控代币,如果代币价格接近成本价,则全部清仓

还是要多实践多do呀,maybe会有一些new idea~


Refs: