如何通过Governor提案实现原生代币(如ETH)转账?
如何在Governor提案中实现原生代币(ETH)转账
核心问题分析
你之前的尝试存在两个关键错误:
- 直接将收款人地址作为target时,传入的
3是普通数值而非wei单位的ETH——以太坊合约仅识别以wei为单位的金额 - 使用
web3.eth.sendTransaction().encodeABI()是错误操作,sendTransaction是Web3发送交易的API,并非合约方法,无法编码为提案所需的calldata
正确实现方案
前提准备
确保Timelock合约地址持有足够的ETH,因为最终由Timelock执行转账操作,需先向其转入对应金额的ETH。
方案1:直接通过提案向收款人转ETH(无需修改合约)
利用Governor提案的values参数指定要发送的ETH金额(wei单位),calldatas传空值(仅需转ETH,无需调用目标地址的函数):
// 转换3 ETH为wei单位 const ethAmount = web3.utils.toWei('3', 'ether'); // 创建提案 const nativeProposal = await governor.propose( [accounts[6]], // 收款人地址 [ethAmount], // 要发送的ETH金额(wei) ["0x"], // 空calldata,仅执行转账 "Grant 3 ETH for marketing to Bob", {from: accounts[4]} );
方案2:通过Timelock合约的自定义方法转账(更安全可控)
如果需要对转账操作做权限控制或日志记录,可给Timelock合约添加一个转账ETH的方法:
// Timelock合约中添加 function transferEth(address payable _recipient, uint256 _amount) external onlyGovernor { require(address(this).balance >= _amount, "Insufficient ETH balance"); _recipient.transfer(_amount); emit EthTransferred(_recipient, _amount); }
然后在JS中编码该方法的calldata并创建提案:
const timelock = await artifacts.require("Timelock").deployed(); const ethAmount = web3.utils.toWei('3', 'ether'); // 编码转账方法的calldata const calldata = timelock.contract.methods.transferEth(accounts[6], ethAmount).encodeABI(); const propose_res = await governor.propose( [timelock.address], // 目标为Timelock合约 [0], // 此处value为0,ETH从Timelock余额中扣除 [calldata], // 调用自定义转账方法的calldata "Grant 3 ETH for marketing to Bob", {from: accounts[4]} );
提案执行流程
无论采用哪种方案,都需要走完标准Governor提案流程:
- 等待提案进入投票期
- 发起投票并获得足够支持
- 提案通过后进入Timelock延迟期
- 延迟期结束后执行提案,完成ETH转账
内容的提问来源于stack exchange,提问作者Yakshesh Gupta
相关产品推荐
相关产品推荐

