ERC20代币中msg.sender、from、spender的区别及相关合约疑问
ERC20中msg.sender、from、spender的区别及疑问解答
一、三个核心概念的定义
- msg.sender:Solidity内置全局变量,永远指向当前触发合约函数调用的主体地址。如果是外部账户直接发起交易,msg.sender就是该外部账户地址;如果是A合约调用B合约的函数,那么B合约执行上下文里的msg.sender就是A合约的地址。
- from:交易层面的参数,是你在前端/脚本调用合约时指定的交易签名发起者,该参数最终会决定合约执行时的msg.sender值。
- spender:ERC20授权机制的专属概念,指代被代币持有者授权、可代为花费持有者名下代币的账户/合约地址。
二、疑问解答
1. transferFrom中的授权额度扣减逻辑问题
你产生角色切换的困惑,本质是把msg.sender的动态属性和固定角色混淆了,实际逻辑完全对应:
- 你调用
token.approve(exchange, amount, { from: deployer })时,执行approve函数的msg.sender是deployer(代币持有者),所以会将allowance[deployer][exchange]赋值为你指定的amount,意思是deployer授权给exchange最多花费amount额度的自身代币。 - 你调用
token.transferFrom(deployer, receiver, amount, { from: exchange })时,执行transferFrom函数的msg.sender是exchange,也就是之前被授权的spender。此时函数里的allowance[_from][msg.sender]就是allowance[deployer][exchange],扣减的就是deployer给exchange的授权额度,逻辑完全自洽,不存在角色切换。
注意:你当前的transferFrom函数遗漏了两个必要校验,存在安全漏洞:
- 缺少
require(allowance[_from][msg.sender] >= _value)的额度检查,可能出现超额转账- 缺少
require(balanceOf[_from] >= _value)的余额检查,可能出现负数余额问题
2. 调用函数时大括号传参的原因
大括号里的参数是以太坊交易级别的元数据,不属于你写的合约函数的业务入参,这些参数是EVM处理交易的通用字段,和具体合约的业务逻辑无关,因此不能放到函数参数列表中。常见的交易元参数包括:
from:交易签名发起者,决定合约执行时的msg.sendervalue:该笔交易附带转账的ETH数量gasLimit:该笔交易允许消耗的最大gas上限gasPrice:发起者愿意支付的单位gas价格
3. msg.sender的作用和授权机制的必要性
msg.sender是智能合约做权限校验的核心依据,所有涉及资产操作的逻辑都需要基于msg.sender做判断,否则任何人都可以随意操作其他用户的资产,合约没有任何安全性可言。比如你写的transfer函数,就是限制只能调用者转自己名下的代币,靠的就是balanceOf[msg.sender] >= _value的校验。
你提到的exchange不能直接转deployer的代币,原因也在此:如果没有授权机制,exchange调用transfer时的msg.sender是自己,只能转自己名下的代币,无法操作deployer的资产。而ERC20的授权+transferFrom机制,就是为了在保证用户资产安全的前提下,满足第三方代付的需求:用户作为持有者可以主动授予第三方有限的花费权限,不需要把代币直接转到第三方地址,也不用担心第三方私自挪用超出授权额度的资产,是去中心化交易所、借贷协议等场景的基础能力。
内容的提问来源于stack exchange,提问作者Dhruv Singhal
相关产品推荐
相关产品推荐

