如何从智能合约向EOA账户发送以太币并附带自定义数据
结论
可以实现,你遇到的问题是call方法的参数使用错误,同时对数据的存储位置认知有偏差。
核心原理
你之前的基础认知是正确的:智能合约无法发起独立的链上交易,所有操作都依附于触发合约调用的父交易,属于消息调用(也就是你说的非正式的“内部交易”)。
当你使用底层call方法向EOA地址转账时,你传入的自定义calldata会被保存在这笔父交易的**调用痕迹(Trace)**中,不会作为独立交易的input字段存在,链下可以通过以太坊节点的trace类API查询到对应的数据。
你之前的写法错误点
call方法仅接受一个bytes类型的参数作为调用数据,你之前的几种写法都不符合参数要求:
- 传入多个参数
("data", value)不符合入参格式要求 - 直接传入
uint32类型的value不会自动编码为bytes类型 abi.encodeWithSignature用于编码智能合约的函数调用,首参数要求为函数签名字符串,直接传入value完全不符合该方法的使用规范
正确实现代码
你可以使用abi.encode或abi.encodePacked将需要发送的数据编码为bytes类型传入call方法,修正后的合约示例如下:
pragma solidity 0.8.6; contract Simple { uint32 value; constructor() payable { // 合约初始化时转入0.5 ether value = 22; } function foo() public { require(address(this).balance >= 0.1 ether, "Insufficient balance"); // 转账0.1 ether同时附带value变量的数据 (bool success, ) = payable(msg.sender).call{value: 0.1 ether}(abi.encodePacked(value)); require(success, "Transfer failed"); // 如果要同时传字符串和数值,可写为: // (bool success, ) = payable(msg.sender).call{value: 0.1 ether}(abi.encodePacked("data", value)); } }
注意事项
transfer/send方法仅提供2300Gas且不支持自定义calldata,无法满足附带数据的需求,必须使用底层call方法- 你发送的数据不会存储在EOA账户的链上属性中,也不会主动通知EOA持有者,需要你主动查询对应父交易的调用痕迹,解码后才能拿到附带的数据
- 区块的
extra data是矿工写入的内容,和你通过call传入的数据没有关联,不要混淆两类数据的存储位置
内容的提问来源于stack exchange,提问作者Pedro Perpétua
相关产品推荐
相关产品推荐

