如果您使用 Uniswap 平台交换代币,您将有 2 个步骤。您将批准令牌,在此步骤中元掩码将弹出,您将确认它。然后 Uniswap 将进行实际的交换,它将代币从你的钱包中取出并为你进行交换。
这是swapExactETHForTokens
功能
function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline)
external
virtual
override
payable
ensure(deadline)
returns (uint[] memory amounts)
{
require(path[0] == WETH, 'UniswapV2Router: INVALID_PATH');
amounts = UniswapV2Library.getAmountsOut(factory, msg.value, path);
require(amounts[amounts.length - 1] >= amountOutMin, 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT');
IWETH(WETH).deposit{value: amounts[0]}();
assert(IWETH(WETH).transfer(UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0]));
_swap(amounts, path, to);
}
最后一个函数_swap
调用swap
函数:
从文档
同样重要的是要确保你的合约控制足够的 ETH/代币来进行交换,并已批准路由器撤回这么多代币。
想象一下,你想从你的智能合约中用 50 DAI 换取尽可能多的 ETH。
从转移
在交换之前,我们的智能合约需要控制 50 DAI。完成此操作的最简单方法是在 DAI 上调用 transferFrom,并将所有者设置为 msg.sender:
uint amountIn = 50 * 10 ** DAI.decimals();
require(DAI.transferFrom(msg.sender, address(this), amountIn), 'transferFrom failed.');
Uniswap 最终会transferFrom
,但在你的代币必须批准交易之前,它必须添加uniswap address
到它的allowance
映射中。
mapping(address=>mapping(address=>uint)) public allowance;
// token address is allowign uniswap address for this much token
除非您设置了交换令牌并且您的交换令牌必须调用approve
.
如果你有前端应用程序,当你调用合约的交换函数时,metamask 会弹出,你会确认它。但是,在测试环境中,您需要实际的 ERC20 合约,部署它并调用approve
. 在前端,您将有两个函数swapToken
和approve
. 你会按这个顺序打电话给他们吗?
const startSwap = async () => {
await approve()
await swapToken()
}
在测试套件中:
const MyContract = artifacts.require("MyContract");
const Dai = artifacts.require("Dai");
// ganache provides an array of accounts
contract("Uniswap", (ganachProvidedAccounts) => {
let myContract,dai;
// intialize the contracts before each test
before(async () => {
myContract = await myContract.new();
dai = await Dai.new();
})
describe("Swapping", async () => {
it("swap tokens", async () => {
let result;
// first ask for approval of 100 token transfer
await dai.approve(myContract.address, tokens("100"), {
from:ganachProvidedAccounts[0] ,
});
// // check staking for customer
await myContract.swapExactETHForTokens("100"), { from: ganachProvidedAccounts[0] });
// make your assetion
})})