Solidity文档中的简单公开竞价示例合同不支付受益人

问题描述 投票:1回答:2

我尝试了使用ganache-cli和松露的Solidity文档中的Simple Open Auction示例(https://solidity.readthedocs.io/en/v0.4.24/solidity-by-example.html#simple-open-auction)。在migrations / 2_deploy_contracts.js中,我设置了:

var SimpleAuction = artifacts.require("./SimpleAuction.sol");

module.exports = function(deployer) {
  deployer.deploy(SimpleAuction, 300, "0xe6ebc74aa685527a83c9e0df01b21acf0a1e8286");
};

使用“0xe6ebc74aa685527a83c9e0df01b21acf0a1e8286”ganache中帐户1的地址。

在松露控制台中,我执行了以下命令来模拟拍卖(我在调用auction.auctionEnd()之前等了300秒,成功了):

auction = SimpleAuction.at(SimpleAuction.address)
account1 = web3.eth.accounts[1]
account2 = web3.eth.accounts[2]
account3 = web3.eth.accounts[3]
account4 = web3.eth.accounts[4]
auction.bid({from: account2, value: web3.toWei(10, "ether")})
auction.bid({from: account3, value: web3.toWei(13, "ether")})
auction.bid({from: account4, value: web3.toWei(15, "ether")})
auction.withdraw({from: account2})
auction.withdraw({from: account3})
auction.auctionEnd()
web3.fromWei(web3.eth.getBalance(account1).toString(), "ether")
web3.fromWei(web3.eth.getBalance(account2).toString(), "ether")
web3.fromWei(web3.eth.getBalance(account3).toString(), "ether")
web3.fromWei(web3.eth.getBalance(account4).toString(), "ether")

在此之后,余额为:

  1. 100
  2. 99.9936296
  3. 99.9945537
  4. 84.9945537

帐户4赢得了拍卖并支付了15个eth,但我预计帐户1的余额为115 eth,因为此帐户是受益人。我想我逐字复制的示例代码没有错误,所以我在这里做错了什么?

合同代码是:

pragma solidity ^0.4.22;

contract SimpleAuction {
    // Parameters of the auction. Times are either
    // absolute unix timestamps (seconds since 1970-01-01)
    // or time periods in seconds.
    address public beneficiary;
    uint public auctionEnd;

    // Current state of the auction.
    address public highestBidder;
    uint public highestBid;

    // Allowed withdrawals of previous bids
    mapping(address => uint) pendingReturns;

    // Set to true at the end, disallows any change
    bool ended;

    // Events that will be fired on changes.
    event HighestBidIncreased(address bidder, uint amount);
    event AuctionEnded(address winner, uint amount);

    // The following is a so-called natspec comment,
    // recognizable by the three slashes.
    // It will be shown when the user is asked to
    // confirm a transaction.

    /// Create a simple auction with `_biddingTime`
    /// seconds bidding time on behalf of the
    /// beneficiary address `_beneficiary`.
    constructor(
        uint _biddingTime,
        address _beneficiary
    ) public {
        beneficiary = _beneficiary;
        auctionEnd = now + _biddingTime;
    }

    /// Bid on the auction with the value sent
    /// together with this transaction.
    /// The value will only be refunded if the
    /// auction is not won.
    function bid() public payable {
        // No arguments are necessary, all
        // information is already part of
        // the transaction. The keyword payable
        // is required for the function to
        // be able to receive Ether.

        // Revert the call if the bidding
        // period is over.
        require(
            now <= auctionEnd,
            "Auction already ended."
        );

        // If the bid is not higher, send the
        // money back.
        require(
            msg.value > highestBid,
            "There already is a higher bid."
        );

        if (highestBid != 0) {
            // Sending back the money by simply using
            // highestBidder.send(highestBid) is a security risk
            // because it could execute an untrusted contract.
            // It is always safer to let the recipients
            // withdraw their money themselves.
            pendingReturns[highestBidder] += highestBid;
        }
        highestBidder = msg.sender;
        highestBid = msg.value;
        emit HighestBidIncreased(msg.sender, msg.value);
    }

    /// Withdraw a bid that was overbid.
    function withdraw() public returns (bool) {
        uint amount = pendingReturns[msg.sender];
        if (amount > 0) {
            // It is important to set this to zero because the recipient
            // can call this function again as part of the receiving call
            // before `send` returns.
            pendingReturns[msg.sender] = 0;

            if (!msg.sender.send(amount)) {
                // No need to call throw here, just reset the amount owing
                pendingReturns[msg.sender] = amount;
                return false;
            }
        }
        return true;
    }

    /// End the auction and send the highest bid
    /// to the beneficiary.
    function auctionEnd() public {
        // It is a good guideline to structure functions that interact
        // with other contracts (i.e. they call functions or send Ether)
        // into three phases:
        // 1. checking conditions
        // 2. performing actions (potentially changing conditions)
        // 3. interacting with other contracts
        // If these phases are mixed up, the other contract could call
        // back into the current contract and modify the state or cause
        // effects (ether payout) to be performed multiple times.
        // If functions called internally include interaction with external
        // contracts, they also have to be considered interaction with
        // external contracts.

        // 1. Conditions
        require(now >= auctionEnd, "Auction not yet ended.");
        require(!ended, "auctionEnd has already been called.");

        // 2. Effects
        ended = true;
        emit AuctionEnded(highestBidder, highestBid);

        // 3. Interaction
        beneficiary.transfer(highestBid);
    }
}

当我在300秒之前调用auction.auctionEnd()时,我得到一个例外“拍卖尚未结束”,这是应该做的:

truffle(development)> auction.auctionEnd()
Error: VM Exception while processing transaction: revert Auction not yet ended.
    at XMLHttpRequest._onHttpResponseEnd (/usr/local/lib/node_modules/truffle/build/webpack:/~/xhr2/lib/xhr2.js:509:1)
    at XMLHttpRequest._setReadyState (/usr/local/lib/node_modules/truffle/build/webpack:/~/xhr2/lib/xhr2.js:354:1)
    at XMLHttpRequestEventTarget.dispatchEvent (/usr/local/lib/node_modules/truffle/build/webpack:/~/xhr2/lib/xhr2.js:64:1)
    at XMLHttpRequest.request.onreadystatechange (/usr/local/lib/node_modules/truffle/build/webpack:/~/web3/lib/web3/httpprovider.js:128:1)
    at /usr/local/lib/node_modules/truffle/build/webpack:/packages/truffle-provider/wrapper.js:134:1
    at /usr/local/lib/node_modules/truffle/build/webpack:/~/web3/lib/web3/requestmanager.js:86:1
    at Object.InvalidResponse (/usr/local/lib/node_modules/truffle/build/webpack:/~/web3/lib/web3/errors.js:38:1)

当我在300秒后调用它时,我得到一个事务和一个事件AuctionEnded,所以它看起来像now >= auctionEnd条件满足:

truffle(development)> auction.auctionEnd()
{ tx: '0x480208cd6c4ac3580e7dcc3aa7e64cd0e7b5e11d5bea75e4769b554767158e35',
  receipt: 
   { transactionHash: '0x480208cd6c4ac3580e7dcc3aa7e64cd0e7b5e11d5bea75e4769b554767158e35',
     transactionIndex: 0,
     blockHash: '0xfde6956d9c7d6e99235606b70e11161965ddf832063e572a87df00c14484e5a1',
     blockNumber: 12,
     gasUsed: 76921,
     cumulativeGasUsed: 76921,
     contractAddress: null,
     logs: [ [Object] ],
     status: '0x1',
     logsBloom: '0x00000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000100000000040000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' },
  logs: 
   [ { logIndex: 0,
       transactionIndex: 0,
       transactionHash: '0x480208cd6c4ac3580e7dcc3aa7e64cd0e7b5e11d5bea75e4769b554767158e35',
       blockHash: '0xfde6956d9c7d6e99235606b70e11161965ddf832063e572a87df00c14484e5a1',
       blockNumber: 12,
       address: '0xef0a6e95779240516e8a05039f97968f727c4f18',
       type: 'mined',
       event: 'AuctionEnded',
       args: [Object] } ] }
ethereum solidity truffle
2个回答
0
投票

希望这可以帮助你。我想你错过了时间旅行的一部分。

// test/SimpleAuction.js

const sa = artifacts.require("SimpleAuction");

contract('SimpleAuction', async function(accounts) {

  /**
  * TimeTravel function - can move this to helper file
  * https://www.reddit.com/r/ethdev/comments/6n65ar/using_testrpc_and_truffles_built_in_js_tests_how/dk7357l/
  */
  const timeTravel = function (time) {
    return new Promise((resolve, reject) => {
      web3.currentProvider.sendAsync({
        jsonrpc: "2.0",
        method: "evm_increaseTime",
        params: [time], // 86400 is num seconds in day
        id: new Date().getTime()
      }, (err, result) => {
        if(err){ return reject(err) }
        return resolve(result)
      });
    })
  }

  var sa_instance;
  var highest_bid = 2; // ether
  var bob         = accounts[1];
  var alice       = accounts[2];
  var john        = accounts[3];
  var beneficiary = accounts[accounts.length - 1]; // last account in Ganache
  var beneficiary_initial_balance;

  before(async function() {
    sa_instance = await sa.new(300, beneficiary);

    var bib_balance_wei = await web3.eth.getBalance(beneficiary);
    var bib_balance_eth = web3.fromWei(web3.toDecimal(bib_balance_wei), "ether");
    beneficiary_initial_balance = parseInt(bib_balance_eth);
  })

  it("Bob bids with 1 ETH", async function() {
    await sa_instance.bid({from: bob, value: web3.toWei(1, "ether")})
    var sa_balance_wei = await web3.eth.getBalance(sa_instance.address);
    var sa_balance_eth = web3.fromWei(web3.toDecimal(sa_balance_wei), "ether");
    assert.equal(sa_balance_eth, 1);
  })

  it("Alice bids with 2 ETH", async function() {
    await sa_instance.bid({from: alice, value: web3.toWei(highest_bid, "ether")})
    var sa_balance_wei = await web3.eth.getBalance(sa_instance.address);
    var sa_balance_eth = web3.fromWei(web3.toDecimal(sa_balance_wei), "ether");
    assert.equal(sa_balance_eth, 3);
  })

  it("Bob can withdraw his 1 ETH back", async function() {
    await sa_instance.withdraw({from: bob})
    var sa_balance_wei = await web3.eth.getBalance(sa_instance.address);
    var sa_balance_eth = web3.fromWei(web3.toDecimal(sa_balance_wei), "ether");
    assert.equal(sa_balance_eth, highest_bid);
  })

  it("Anyone can end the auction when it's due", async function() {
    await timeTravel(300);
    await sa_instance.auctionEnd({from: john});
  })

  it("Contract balance left with 0 ETH", async function() {
    var sa_balance_wei = await web3.eth.getBalance(sa_instance.address);
    var sa_balance_eth = web3.fromWei(web3.toDecimal(sa_balance_wei), "ether");
    assert.equal(sa_balance_eth, 0);
  })

  it("And beneficiary is now 2 ETH richer", async function() {
    var bib_balance_wei = await web3.eth.getBalance(beneficiary);
    var bib_balance_eth = web3.fromWei(web3.toDecimal(bib_balance_wei), "ether");
    var expected_new_beneficiary_balance = beneficiary_initial_balance + highest_bid;
    assert.equal(expected_new_beneficiary_balance, bib_balance_eth);
  })

})

0
投票

auctionEnd()成功了吗?

很可能require(now >= auctionEnd)不满意,因此auctionEnd()失败了。


更新:自己调试合同,转移成功。收款人地址是:0xe6ebc74aa685527a83c9e0df01b21acf0a1e8286 not account1。所以合同按预期工作,没有问题。检查受益人地址的余额,你会看到它有15个以太。

澄清:

这是部署指令:

module.exports = function(deployer) {
  deployer.deploy(SimpleAuction, 300, "0xe6ebc74aa685527a83c9e0df01b21acf0a1e8286");
};

因此,您将受益人地址设置为:0xe6ebc74aa685527a83c9e0df01b21acf0a1e8286

这是auctionEnd()内部的转移指令:

beneficiary.transfer(highestBid);

因此,执行后,如果您运行以下命令,您将看到受益人有15个以太。

web3.eth.getBalance("0xe6ebc74aa685527a83c9e0df01b21acf0a1e8286")

BigNumber {s:1,e:19,c:[150000]}

© www.soinside.com 2019 - 2024. All rights reserved.