在以太坊生态中,除了原生代币 ETH,还有数量庞大的 ERC-20 代币,这些代币的标准化使得它们可以在 DApp(去中心化应用)之间自由流转,当我们谈论 ERC-20 代币转账时,除了基础的 transfer 函数,还有一个至关重要且功能强大的函数——transferFrom,本文将深入浅出地解析 transferFrom 的工作原理、应用场景以及其背后的核心概念——allowance(授权)。

transferFrom 是什么?

transferFrom 是 ERC-20 代币标准中定义的一个核心函数,它的作用是从一个账户中转移代币,而这个转移操作是由第三个账户发起的

换句话说,它允许账户 A 授权账户 B 可以从 A 的账户中提取最多 X 数量的代币,之后,账户 B 就可以调用 transferFrom 函数,从账户 A 的钱包里转走不超过 X 数量的代币到账户 C。

函数签名如下:

function transferFrom(address from, address to, uint256 amount) public returns (bool success);
  • from:代币被转出的源地址(即授权方)。
  • to:代币被转入的目标地址。
  • amount:要转移的代币数量。

transferFrom 的工作原理:allowanceapprove

transferFrom 函数无法凭空工作,它依赖于 ERC-20 标准中的另一个核心概念:allowance(授权额度),整个流程由两个关键函数协同完成:

  1. approve (授权) 这个函数由代币的所有者(授权方)调用,用于授予另一个地址(被授权方)花费自己账户中一定数量代币的权限。

    function approve(address spender, uint256 amount) public returns (bool success);
    • spender:被授权方的地址。
    • amount:授权的代币数量。

    当你调用 approve(spender, amount) 时,你就在智能合约内部记录了一笔账:“spender 这个地址,可以从我这里最多花费 amount 数量的代币”。

  2. allowance (查询授权额度) 这是一个查询函数,任何人都可以调用它来查询一个地址(owner)已经授权给另一个地址(spender)的代币数量。

    function allowance(address owner, address spender) public view returns (uint256 remaining);
  3. transferFrom (执行转账) 当被授权方(spender)想要执行转账时,它会调用 transferFrom 函数,智能合约在执行转账前,会做以下几件事:

    • 检查授权额度:查询 allowance(from, msg.sender),确保 msg.sender(即调用者,被授权方)的剩余授权额度足够支付本次转账的 amount
    • 执行转账:如果额度足够,则从 from 地址扣除 amount 数量的代币,并增加到 to 地址。
    • 更新授权额度关键一步:成功转账后,智能合约会自动将被授权方的可用额度减少 amount,即 allowance(from, msg.sender) -= amount

简单流程总结:

  1. 授权:Alice 调用 approve(Bob, 100),授权 Bob 可以花费她最多 100 个代币。
  2. 查询:任何人都可以调用 allowance(Alice, Bob) 查询到剩余额度为 100。
  3. 转账:Bob 调用 transferFrom(Alice, Charlie, 30),想从 Alice 的账户给 Charlie 转 30 个代币。
  4. 校验与执行:合约检查 Bob 的授权额度(100) >= 30,转账成功,Bob 的剩余授权额度自动更新为 70。

为什么需要 transferFromtransfer 不好吗?

这是一个非常好的问题,直接使用 transfer(from, to, amount) 似乎也能完成转账,但 transferFrom 解决了一个核心问题:用户资产的第三方管理

  • transfer (直接转账):要求转账发起方(msg.sender)必须拥有足够的代币,这适用于点对点的直接转移,比如你直接给朋友转账 10 USDT。

  • transferFrom (授权转账):允许一个应用(如去中心化交易所 DEX、DeFi 借贷协议)在用户不直接操作的情况下,代表用户移动其资产,这是 DeFi 协议能够实现自动化、高效运作的基石。

transferFrom 的核心应用场景

transferFrom 是现代 DeFi 应用的“幕后功臣”,其应用无处不在:

  1. 去中心化交易所 当你在 Uniswap 或 SushiSwap 上用 ETH 交易 USDT 时,你不需要先把 USDT 转到交易所的钱包,你只需要调用 approve,授权交易所可以动用你钱包里的 USDT,当你发起交易时,交易所的智能合约会自动调用 transferFrom,从你的地址划走相应数量的 USDT,并给你相应的 ETH。

  2. 流动性挖矿与质押 在 Aave 或 Compound 等借贷协议中,当你想将你的 USDT 存入协议以赚取利息时,你通过 approve 授权协议可以动用你的 USDT,协议的 deposit 函数会调用 transferFrom 将你的 USDT 转入其资金池,当你提取时,流程则相反。

  3. NFT 市场 在 OpenSea 或 Rarible 上,当你用一种代币(如 WETH)购买 NFT 时,你需要先授权市场合约可以动用你的 WETH,市场在撮合成功后,会调用 transferFrom 从你的账户中扣除 WETH,支付给卖家。

  4. 多签钱包与 DAO 治理 在一个多签钱包中,一个提案可能需要花费一笔资金,提案通过后,执行者可以调用 transferFrom,从多签钱包的地址中划出资金,前提是之前已经通过了 approve 授权。

使用 transferFrom 时的注意事项:重入攻击

由于 transferFrom 在执行转账前后会修改 allowance 状态,开发者必须警惕一种常见的攻击——重入攻击

攻击场景: 一个恶意的合约 MaliciousContract 作为被授权方,它在自己的 receive()fallback() 函数中再次调用 transferFrom

  1. Alice 授权 MaliciousContract 100 个代币。
  2. MaliciousContract 调用 transferFrom(Alice, ..., 50)
  3. 随机配图