OnChain Transaction Debugging: 2. Warm up
Author: Sun
链上交易数据包含从简单的单笔交易转帐、1 个 DeFi 合约交互、多个 DeFi 合约交互、闪电贷套利、治理提案、跨链交易等等,这一节我们先来热身一下,先从简单的开始。我将介绍通常使用区块链浏览器 Etherscan 哪些讯息是我们所在意的,再来我们会使用交易分析工具 Phalcon 看一下这些交易从简单的转帐、UniSWAP上 Swap、Curve 3pool 增加流动性、Compound 治理提案、闪电贷的调用差异。
开始进入热身篇
- 首先环境上需要先安装 Foundry,安装方法请参考 instructions.
- 测试主要会用到 Forge test,如果第一次使用 Foundry,可以参考 Foundry book、Foundry @EthCC、WTF Solidity - Foundry
- 每条链上都有专属的区块链浏览器,这节我们都会使用 Ethereum 主网来当案例所以可以透过 Etherscan 来分析.
- 通常我会特别想看的栏位包含:
- Transaction Action: 因为复杂的交易中 ERC-20 Tokens Transferred 会很复杂,可读性不好,所以可以透过 Transaction Action 看一下关键行为但不一定每笔交易都有
- From: msg.sender 执行这笔交易的来源钱包地址
- Interacted With (To): 跟哪个合约交互
- ERC-20 Tokens Transferred: 代币转移流程
- Input Data: 交易的原始 Input 资料,可以看到呼叫什么 Function 和带入什么 Value
- 如果还不知道常用工具有哪些可以回顾第一课交易分析工具篇
链上转帐
从上图例子可以解读为:From: 发送这笔交易的来源钱包地址
Interacted With (To): Tether USD (USDT) 合约
ERC-20 Tokens Transferred: 从用户A 钱包转 651.13 USDT 到用户 B
Input Data: 呼叫了 transfer function
透过 phalcon 来看: 从调用流程来看就只有一个 Call USDT.transfer
,要注意的是 Value. 因为 EVM 不支持浮点数的运算,所以使用精度代表,每个 Token 都要注意它的精度大小,标准 ERC-20 代币精度为 18,但也有特例,如 USDT 为例,精度是 6 所以 Value 带入的值为 651130000,如果精度处理不当就容易造成问题。精度的查询方式可以到 Etherscan 代币合约上看到。
Uniswap Swap
从上图例子 可以解读为:
Transaction Action: 很直觉就可以知道用户在 Uniswap 上进行 Swap,将 12,716 USDT 换成 7,118 UNDEAD。
From: 发送这笔交易的来源钱包地址
Interacted With (To): 这个例子是一个 MEV Bot 合约呼叫 Uniswap 合约进行 Swap
ERC-20 Tokens Transferred: Token 交换的过程
透过 phalcon 来看: MEV Bot 呼叫 Uniswap V2 USDT/UNDEAD 交易对合约呼叫 swap 函示来进行代币兑换。
我们使用 Foundry 来模拟操作使用 1BTC 在 Uniswap 换成 DAI,范例程式码参考,执行以下指令
forge test --contracts ./src/test/Uniswapv2.sol -vvvv
如下图所示我们透过呼叫 Uniswap_v2_router.swapExactTokensForTokens 函式,将 1BTC 换到 16,788 DAI.
Curve 3pool - DAI/USDC/USDT
从上图例子可以解读为:
在 Curve 3pool 增加流动性
From: 发送这笔交易的来源钱包地址
Interacted With (To): Curve.fi: DAI/USDC/USDT Pool
ERC-20 Tokens Transferred: 用户 A 转入 3,524,968.44 USDT 到 Curve 3 pool,然后 Curve 铸造 3,447,897.54 3Crv 代币给用户 A.
透过 phalcon 来看: 从调用流程来看执行了三个步骤 1.add_liquidity 2.transferFrom 3.mint
Compound propose
从上图例子可以解读为: 用户在 Compound 治理合约上提交了一个提案,从 Etherscan 上可以点击 Decode Input Data 就可以看到提案内容。
透过 phalcon 来看: 透过呼叫 propose 函式来提交 proposal 得到编号 44 号提案。
Uniswap Flashswap
这里我们使用 Foundry 来模拟操作看看如何在 Uniswap 上使用闪电贷,官方Flash swap介绍
范例程式码参考
forge test --contracts ./src/test/Uniswapv2_flashswap.sol -vv
以这个例子透过 Uniswap UNI/WETH 交易兑上进行闪电贷借出 100 颗 WETH,再还回去给 Uniswap. 注意还款时要付 0.3% 手续费。
从下图调用流程可以看出,呼叫 swap 进行 flashswap 然后透过 callback uniswapV2Call 来还款。
简单区分一下 Flashloan 和 Flashswap 的差异,两种都是无需抵押资产就可以借出 Token,且需要在同一个区块内还回去不然交易就会失败,假如透过 token0/token1 进行 Flashloan 借出 token0 就要还 token0回去,Flashswap 借出 token0 可以还 token0 或 token1 回去,比较弹性。
更多 DeFi 基本操作可以参考 DeFiLabs
Foundry cheatcodes
Foundry 的 cheatcodes 在我们做链上分析必须使用到的,这边我介绍一下常用到的函式,更多介绍可以参考 Cheatcodes Reference
- createSelectFork: 指定这次测试要复制哪个网路和区块高度,注意每条链的 RPC 要写在 foundry.toml
- deal: 设定测试钱包余额
- 设定 ETH 余额
deal(address(this), 3 ether);
- 设定 Token 余额
deal(address(USDC), address(this), 1 * 1e18);
- 设定 ETH 余额
- prank: 模拟指定钱包身份,只有在下一个呼叫有效,下一个 msg.sender 是会所指定的钱包,例如使用巨鲸钱包转帐
- startPrank: 模拟指定钱包身份,在没有执行
stopPrank()
之前,所有 msg.sender 都会是指定的钱包地址 - label: 将钱包地址标签化,方便在使用 Foundry debug 时提高可读性
- roll: 调整区块高度
- warp: 调整 block.timestamp
谢谢收看,我们准备进入下一课