如何使用web3.py调用Solidity提现函数提取智能合约以太币余额?
问题结论
你当前编写的withdraw函数不能直接把合约里的以太币转到任意指定账户,该函数逻辑固定将合约余额转给调用者(被onlyOwner限制只能是合约所有者调用),资金只会转入合约所有者的地址。
下面提供两种可实现需求的方案:
方案1:修改Solidity合约,支持直接提现到任意地址
先更新合约代码,新增支持指定收款地址的提现函数,保留权限限制:
function withdrawTo(address payable _to) public payable onlyOwner { _to.transfer(address(this).balance); }
重新部署合约后,web3.py调用代码如下:
booking_contract = w3.eth.contract(address=self.receipt.contractAddress, abi=abi) # 此处必须传入合约所有者的地址 nonce = w3.eth.getTransactionCount(owner_address) # 替换为你要转入的目标地址 target_address = "0x你指定的收款地址" withdraw_txn = booking_contract.functions.withdrawTo(target_address).buildTransaction( { "chainId": chain_id, "gasPrice": w3.eth.gas_price, "from": owner_address, "nonce": nonce, # 此处不需要填value,value是用户向合约转钱时才需要的参数 } ) signed_txn = w3.eth.account.sign_transaction(withdraw_txn, private_key=owner_private_key) txn_hash = w3.eth.send_raw_transaction(signed_txn.rawTransaction) # 可选:等待交易上链确认 tx_receipt = w3.eth.wait_for_transaction_receipt(txn_hash)
方案2:不修改现有合约的实现方式
如果不想改动已部署的合约,分两步操作即可:
- 调用现有
withdraw函数把合约余额全部转到合约所有者地址 - 从所有者地址向你指定的目标地址转对应金额的以太币
第一步:调用现有提现函数提币到所有者地址
booking_contract = w3.eth.contract(address=self.receipt.contractAddress, abi=abi) nonce = w3.eth.getTransactionCount(owner_address) withdraw_txn = booking_contract.functions.withdraw().buildTransaction( { "chainId": chain_id, "gasPrice": w3.eth.gas_price, "from": owner_address, "nonce": nonce, } ) signed_txn = w3.eth.account.sign_transaction(withdraw_txn, private_key=owner_private_key) txn_hash = w3.eth.send_raw_transaction(signed_txn.rawTransaction) w3.eth.wait_for_transaction_receipt(txn_hash)
第二步:从所有者地址转币到指定目标地址
target_address = "0x你指定的收款地址" # 转账金额单位为wei,以下示例是余额扣除少量gas费后全额转出,可按需修改 transfer_amount = w3.eth.get_balance(owner_address) - w3.to_wei(0.001, 'ether') nonce = w3.eth.getTransactionCount(owner_address) tx = { 'nonce': nonce, 'to': target_address, 'value': transfer_amount, 'gas': 21000, # ETH普通转账固定gas上限 'gasPrice': w3.eth.gas_price, 'chainId': chain_id } signed_tx = w3.eth.account.sign_transaction(tx, private_key=owner_private_key) tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction) w3.eth.wait_for_transaction_receipt(tx_hash)
注意事项
- 所有涉及提现的操作必须使用合约所有者的私钥签名,否则会被
onlyOwner修饰符拦截 - 提现交易不需要填
value字段,该字段仅在用户向合约转账时使用 - 操作前确保合约所有者地址有足够的ETH支付gas费
内容的提问来源于stack exchange,提问作者imawful
相关产品推荐
相关产品推荐

