Flash Swap 与正常 Swap 的区别
Flash Swap 与正常 Swap 的区别
Flash Swap(闪电交换)和正常 Swap(普通交换)是去中心化交易所(如 Uniswap)中的两种不同交易方式,它们的主要区别如下:
1. 交易流程不同
-
正常 Swap:
- 用户直接支付代币A,立即获得代币B。
- 交易流程:
用户 → 支付代币A → 获得代币B
。 - 必须先拥有代币A才能发起交易。
-
Flash Swap:
- 用户可以先借入代币B,使用代币B执行任意操作(如套利、清算),然后在同一笔交易中偿还代币B及手续费。
- 交易流程:
借入代币B → 使用代币B → 偿还代币B + 手续费
。 - 无需预先持有代币,依赖智能合约的原子性保证还款。
2. 资金要求不同
- 正常 Swap:需要预先拥有足够的代币A作为交易本金。
- Flash Swap:无需预先持有任何代币,只需在交易结束前偿还借款及手续费。
3. 智能合约交互
- 正常 Swap:直接调用交易所的 Router 合约的 Swap 函数(如
swapExactTokensForTokens
) ,无需额外逻辑。 - Flash Swap:
- 调用
swap
函数时传入数据(如data
参数)触发闪电贷款。 - 交易所会回调合约的
uniswapV2Call
函数,用户在此函数中执行自定义操作(如套利)。 - 必须在
uniswapV2Call
函数中偿还借款及手续费,否则整个交易回滚。
- 调用
4. 风险与收益
- 正常 Swap:风险低,只需承担市场价格波动风险。
- Flash Swap:
- 高风险:若操作失败(如套利机会消失),交易回滚,仅损失 gas 费用。
- 高收益:可利用市场价格差异进行无本金套利,或执行清算等复杂策略。
5. 手续费
- 正常 Swap:支付交易手续费(Uniswap 的输入金额的 0.3%)。
- Flash Swap:支付闪电贷款的利息(通常为借款金额的 3 / 997),因为他是确定的输出,来计算输入,但是所有的swap都是计算输入的0.3%。和
swapTokensForExactTokens
中要调用的getamountin一样,通过确定的输出求输入,但是公式不一样。
Flash Swap测试代码
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "./interfaces/Uniswap.sol";
// uniswap will call this function when we execute the flash swap
interface IUniswapV2Callee {
function uniswapV2Call(
address sender,
uint256 amount0,
uint256 amount1,
bytes calldata data
) external;
}
// flash swap contract
contract flashSwap is IUniswapV2Callee {
address private constant WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
address private constant UniswapV2Factory =
0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f;
// we'll call this function to call to call FLASHLOAN on uniswap
function testFlashSwap(address _tokenBorrow, uint256 _amount) external {
// check the pair contract for token borrow and weth exists
address pair = IUniswapV2Factory(UniswapV2Factory).getPair(
_tokenBorrow,
WETH
);
require(pair != address(0), "!pair");
// right now we dont know tokenborrow belongs to which token
address token0 = IUniswapV2Pair(pair).token0();
address token1 = IUniswapV2Pair(pair).token1();
// as a result, either amount0out will be equal to 0 or amount1out will be
uint256 amount0Out = _tokenBorrow == token0 ? _amount : 0;
uint256 amount1Out = _tokenBorrow == token1 ? _amount : 0;
// need to pass some data to trigger uniswapv2call
bytes memory data = abi.encode(_tokenBorrow, _amount);
// last parameter tells whether its a normal swap or a flash swap
IUniswapV2Pair(pair).swap(amount0Out, amount1Out, address(this), data);
// adding data triggers a flashloan
}
// in return of flashloan call, uniswap will return with this function
// providing us the token borrow and the amount
// we also have to repay the borrowed amt plus some fees
function uniswapV2Call(
address _sender,
uint256 _amount0,
uint256 _amount1,
bytes calldata _data
) external override {
// check msg.sender is the pair contract
// take address of token0 n token1
address token0 = IUniswapV2Pair(msg.sender).token0();
address token1 = IUniswapV2Pair(msg.sender).token1();
// call uniswapv2factory to getpair
address pair = IUniswapV2Factory(UniswapV2Factory).getPair(token0, token1);
require(msg.sender == pair, "!pair");
// check sender holds the address who initiated the flash loans
require(_sender == address(this), "!sender");
(address tokenBorrow, uint amount) = abi.decode(_data, (address, uint));
// 0.3% fees
uint fee = ((amount * 3) / 997) + 1;
uint amountToRepay = amount + fee;
IERC20(tokenBorrow).transfer(pair, amountToRepay);
}
}
正常swap的调用流程
-
用户 → Router 合约:
- 用户调用 Router 合约的 Swap 函数(如
swapExactTokensForTokens
、swapTokensForExactTokens
等)。 - Router 合约会根据用户输入计算最优路径,并调用相应 Pair 合约的
swap
函数。
- 用户调用 Router 合约的 Swap 函数(如
-
Router → Pair 合约:
- Router 合约内部调用目标 Pair 合约的
swap
函数完成实际交换。
- Router 合约内部调用目标 Pair 合约的
总结
Flash Swap 与正常 Swap 的区别
特性 | 正常 Swap | Flash Swap |
---|---|---|
资金要求 | 需要预先持有代币 | 无需预先持有,依赖原子性还款 |
交易流程 | 直接交换代币 | 借款 → 操作 → 还款 |
风险 | 低(仅市场风险) | 高(操作失败则交易回滚) |
收益 | 固定(代币兑换) | 潜在高收益(无本金套利) |
智能合约逻辑 | 简单调用 swap | 需要实现回调函数 uniswapV2Call |
用户调用入口 | Router 合约的 Swap 函数(如 swapExactTokensForTokens ) | 直接调用 Pair 合约的 swap 函数,并传入非空 data |
核心逻辑 | Router 计算路径 → 调用多个 Pair 合约的 swap | testFlashSwap调用Pair 合约的 swap 先借款,swap再执行回调函数 uniswapV2Call 还款,swap最后判断流动性是否减少 |
Flash Swap 的核心优势在于允许用户在无本金的情况下利用市场机会,但需要精确的策略和代码实现,否则可能导致交易失败。
在实际应用中,用户通常通过 Router 合约(如 UniswapV2Router02
)发起 Swap 交易,而不是直接调用 Pair 合约。Router 合约封装了复杂的路径计算、多池交换,确定输入或者确定输出等逻辑,为用户提供更友好的接口。
- 正常 Swap:用户通过 Router 合约 发起交易,Router 内部调用 Pair 合约完成交换。
- Flash Swap:合约通过 Pair 合约 的
swap
函数触发,但需传入data
参数,且必须实现回调函数uniswapV2Call
。