简体   繁体   English

如何将合约余额从内部函数转移到外部地址?

[英]How to transfer a contract balance to an external address from an internal function?

In this contract, I call payWinner() once the third participant has bought a ticket.在这个合约中,一旦第三个参与者买了票,我就会调用payWinner() payWinner() is internal to avoid any external call but when it executes winnerAddress.transfer(winnableBalance); payWinner()是内部的,以避免任何外部调用,但是当它执行时, winnerAddress.transfer(winnableBalance); , the contract balance is sent to an internal address rather than to the external address winnerAddress . ,合约余额被发送到一个内部地址,而不是外部地址winnerAddress Same thing goes for burnLeftBalance() obviously.显然, burnLeftBalance()也是如此。

I guess either it's impossible to transfer part of the contract holdings to an external address from an internal function and I need to create a public function for that (but I don't see how I can be sure that it's the contract itself calling the function), or there is something I'm missing.我想要么不可能将部分合约持有量从内部函数转移到外部地址,我需要为此创建一个公共函数(但我不知道如何确定是合约本身在调用该函数),或者我缺少一些东西。

pragma solidity ^0.8.14;

contract Lottery {
  address payable public burnAddress = payable(0x0000000000000000000000000000000000000000);
  uint256 public ticketsPerRound = 3;
  uint256 public ticketPrice = 0.001 * 10e8 * 10e8;
  address[] public participantAddresses;

  error WrongTicketPrice(uint256 expectedRole, uint256 actualRole);

  function buyTicket() external payable {
    if (msg.value != ticketPrice) {
      revert WrongTicketPrice(ticketPrice, msg.value);
    }

    participantAddresses.push(msg.sender);

    if (participantAddresses.length >= ticketsPerRound) {
      payWinner();
    }
  }

  function getBalance() external view returns (uint256) {
    return address(this).balance;
  }

  function getParticipantAddresses() external view returns (address[] memory) {
    return participantAddresses;
  }

  function getWinnableBalance() public view returns (uint256) {
    return address(this).balance / 2;
  }

  function getWinner() internal view returns (address payable winnerAddress) {
    uint256 unsafeRandomNumber = uint256(
      keccak256(abi.encodePacked(block.difficulty, block.timestamp, participantAddresses))
    );
    uint256 winnerIndex = unsafeRandomNumber % participantAddresses.length;
    winnerAddress = payable(participantAddresses[winnerIndex]);
  }

  function burnLeftBalance() internal {
    uint256 leftBalance = address(this).balance;

    burnAddress.transfer(leftBalance);

    reset();
  }

  function payWinner() internal {
    uint256 winnableBalance = getWinnableBalance();
    address payable winnerAddress = getWinner();

    winnerAddress.transfer(winnableBalance);

    burnLeftBalance();
  }

  function reset() internal {
    delete participantAddresses;
  }
}

There's no such thing as "internal and external addresses".没有“内部地址和外部地址”之类的东西。 The closest to this term I can think of is Externally Owned Account , which is a term representing an address derived from a private key, without a contract bytecode , mostly used by end user wallets.我能想到的最接近这个术语的是Externally Owned Account ,这是一个表示从私钥派生的地址的术语,没有合约字节码,主要由最终用户钱包使用。 But that does not seem to be related to your question.但这似乎与您的问题无关。

Etherscan is using "internal transactions" as a more user-friedly term for " message calls within the virtual machine". Etherscan 使用“内部事务”作为“虚拟机内的消息调用”的更用户友好的术语。 These "internal transaction" details (such as from what sender, to what recipient, what data was passed, what ETH value, ...) are not part of the public blockchain data - only the combined state changes of the "parent" transaction are stored in the blockchain.这些“内部交易”细节(例如从什么发送者、到什么接收者、传递了什么数据、什么 ETH 值……)不是公共区块链数据的一部分——只是“父”交易的组合状态变化存储在区块链中。 So Etherscan retrieves these details by emulating the transaction, records its message calls and stores them in Etherscan's own database, and then displays them in a separate tab.因此,Etherscan 通过模拟事务来检索这些详细信息,记录其消息调用并将它们存储在 Etherscan 自己的数据库中,然后将它们显示在单独的选项卡中。

So, the transaction that you sent is from your address, to the contract address, with value of 0.01 ETH, its data field contains selector of the buyTicket() function that you want to execute... These are all params of the transaction that you sent.因此,您发送的交易是from您的地址to合约地址, value为 0.01 ETH,其data字段包含您要执行的buyTicket()函数的选择器......这些都是交易的参数你发送。 And the "internal transactions" are just a way of displaying state changes that your transaction produced, and their trace.而“内部事务”只是显示事务产生的状态更改及其跟踪的一种方式。 But as long as the state changes were produced (eg increased balance of the winnerAddress ), there's no difference if they were produced by a "parent" transaction or an "internal transaction".但是只要产生了状态变化(例如增加了获胜者地址的winnerAddress ),它们是由“父”交易还是“内部交易”产生的,没有区别。

TLDR: It's not a bug, it's a feature. TLDR:这不是错误,而是功能。 :) :)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM