以太坊公开拍卖智能合约(truffle + ganache-cli)

本文主要介绍了如何使用truffle + Atom进行以太坊公开透明拍卖智能合约的编写,以及如何使用ganache-cli进行智能合约的交互测试。


1 Trueffle框架编写代码

1.1 建立项目

新建项目文件夹SimpleAuction开启另一个终端窗口,输入以下命令建立项目:

PS H:\TestContract> mkdir SimpleAuction


    目录: H:\TestContract


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----        2018/7/12     12:01                SimpleAuction

PS H:\TestContract> cd SimpleAuction
PS H:\TestContract\SimpleAuction> truffle init
Downloading...
Unpacking...
Setting up...
Unbox successful. Sweet!

Commands:

  Compile:        truffle compile
  Migrate:        truffle migrate
  Test contracts: truffle test
PS H:\TestContract\SimpleAuction>

目录结构:

目录结构.PNG

打开contracts文件夹,再通过truffle命令创建SimpleAuction合约,必须通过命令行创建。

PS H:\TestContract\SimpleAuction> cd contracts
PS H:\TestContract\SimpleAuction\contracts> truffle create contract SimpleAuction
  • \contracts:存放智能合约源代码的地方,可以看到里面已经有一个sol文件,我们开发的BlindAuction.sol文件就存放在这个文件夹。
  • \migrations:这是Truffle用来部署智能合约的功能,待会儿我们会新建一个类似1_initial_migration.js的文件来部署BlindAuction.sol
  • \test:测试智能合约的代码放在这里,支持jssol测试。
  • truffle-config.jstruffle.jsTruffle的配置文件,需要配置要连接的以太坊网络。

1.2 创建合约

在Atom中打开项目文件夹SimpleAuction,开始编辑contracts文件夹下的SimpleAuction.sol文件。

整个流程如下:

  • 我们首先要记录拍卖的基本数据:谁是受益人,什么时候结束
  • 我们开启拍卖,一个出价更高的人会替代之前出价最高的人
  • 当出现替代时,还要退还之前出价高的人的代币
  • 出于安全的考虑,退还过程将由之前用户主动发起
pragma solidity ^0.4.22;

contract SimpleAuction {
  // 定义参数:受益人、拍卖结束时间
    address public beneficiary;
    uint public auctionEnd;
    uint public biddingTime;
    uint public auctionStart;

    // 最高出价者
    address public highestBidder;

    // 最高出价
    uint public highestBid;

    mapping (address => uint) pendingReturns; // 用于取回之前的出价

    // 拍卖是否结束,不允许被修改
    bool ended;

    // 最高出价变动时调用事件
    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.

    // 构造函数
    // 创建一个拍卖对象,初始化参数值:受益人、拍卖持续时间
    constructor(uint _biddingTime, address _beneficiary) public {
        beneficiary = _beneficiary;
        auctionStart = now;
        biddingTime = _biddingTime;
        auctionEnd = now + _biddingTime; // now: current block's timestamp

    }

    // 使用代币进行拍卖,当拍卖失败时,会退回代币
    // 出价功能:包括交易参数
    // 当出价不是最高,资金会被自动退回
    function bid() public payable{
        // 不需要参数,因为都被自动处理了
        // 当一个函数要处理Ether时,需要包含payable的修饰符

        // 如果超过了截止期,交易撤回
        if(now > auctionStart + biddingTime){
            revert();
        }

        // 如果出价不够,交易撤回
        if (msg.value <= highestBid){
            revert();
        }

        // 如果出价最高,当前出价者作为最高出价人
        if (highestBidder != 0){
          //highestBidder.send(highestBid); // send ether(in wei)to the address
          // 调用highestBidder.send(highestBid)的方式是危险的
          // 因为会执行不知道的协议
          // 因此最好让用户自己取回自己的代币
          pendingReturns[highestBidder] += highestBid;
        }
        highestBidder = msg.sender;
        highestBid = msg.value;
        emit HighestBidIncreased(msg.sender, msg.value);
    }

    // 取回被超出的拍卖前的出资
    function withdraw() public returns (bool){
        uint amount = pendingReturns[msg.sender];
        if (amount > 0){
            // 需要提前设置为0,因为接收者可以在这个函数结束前再次调用它
            pendingReturns[msg.sender] = 0;

            if (!msg.sender.send(amount)){
                // 不需要throw,直接重置代币数量即可
                pendingReturns[msg.sender] = amount;
                return false;
            }
        }
        return true;
    }

    // 结束拍卖,将金额给予受益人
    function auctionEnd() public {
        // 与其他协议交互的最好遵循以下顺序的三个步骤:
        // 1.检查状况
        // 2.修改状态
        // 3.合约交互
        // 如果这三个步骤混在一起,那么攻击者可能通过多次调用这个函数来进行攻击

        // 1.检查状况
        if (now <= auctionEnd) {
          revert();
        }
        if(ended){
          revert();
        }
      //  require (now >= auctionEnd, "Auction not yet ended.");
      //  require (!ended, "auctionEnd has already called.");

        // 2.修改状态
        ended = true;
        emit AuctionEnded(highestBidder, highestBid);

        // 3.合约交互
        beneficiary.transfer(highestBid);
      }

      function () public{
        revert();
      }
}

Note:一定要有最后的function()不然调用bid()总会报错。

1.3 编译合约

在项目根目录SimpleAuction的powershell中执行truffle compile命令:

PS H:\TestContract\SimpleAuction> truffle compile
Compiling .\contracts\Migrations.sol...
Compiling .\contracts\SimpleAuction.sol...

Compilation warnings encountered:

/H/TestContract/SimpleAuction/contracts/SimpleAuction.sol:32:5: Warning: Defining constructors as functions with the same name as the contract is deprecated. Use "constructor(...) { ... }" instead.
    function SimpleAuction(uint _biddingTime, address _beneficiary) public {
    ^ (Relevant source part starts here and spans across multiple lines).

Writing artifacts to .\build\contracts

PS H:\TestContract\SimpleAuction>

2 Ganache-cli 部署测试智能合约

2.1 启动ganache-cli

打开powershell终端,可以看到ganache-cli启动后自动建立了10个账号(Accounts),与每个账号对应的私钥(Private Key)。每个账号中都有100个测试用的以太币(Ether)。
Note. ganache-cli仅运行在内存中,因此每次重开时都会回到全新的状态。

C:\Users\aby>ganache-cli
Ganache CLI v6.1.6 (ganache-core: 2.1.5)

Available Accounts
==================
(0) 0x553cc75f3099ec4f6ba57e2580f65f982dfcbc67 (~100 ETH)
(1) 0xed700e53205af0b9daa4548cc48465cab55d376c (~100 ETH)
(2) 0x3fdcbf82e2343f3d88a5ec967800ee188b7bc440 (~100 ETH)
(3) 0x76757998260e9d7bb01e2761a4abacffd73162e2 (~100 ETH)
(4) 0x0e53c9c2cb04a7b46acd3e94703434c6e0b1e1c9 (~100 ETH)
(5) 0xfb7db3e68877e08df576d0071d1f68b1ad185d50 (~100 ETH)
(6) 0x0ff87726fac78f3675751fc67c3b2b174aa7ec68 (~100 ETH)
(7) 0x8bee12196d694c864b00c4b19295b0c0a067bb1a (~100 ETH)
(8) 0x14e498d9ca25b050e17fb702e1325135da21e9e7 (~100 ETH)
(9) 0x1aed5d4a441d50716313426bdc519b8263c37bfc (~100 ETH)

Private Keys
==================
(0) 0x260ed471ee7c4897c3b478a3ae36fb47f7b5dc4e2bfaeea2062e53edbc664f8e
(1) 0xbbaaf6be4797da3598ca72969b46a04569448a7d67185f96b55b2618327176b6
(2) 0xca9fd89f5c5ada96b35afd2b5782c14b2286894454178e9225df2aa3bed133d4
(3) 0x5e282a3ddb12f4f77318a30f2e653b1764b3fac52f43d575e5b1cd9564e6c6f6
(4) 0x17f336fbcc161a20f38979d787eb9f1ae33fea870acdd37142dc3be3bcf127e7
(5) 0x9521e42f1d3a03079883032a47a7146cd76275bf0bf206b5f0467c8a2249e553
(6) 0x4fd49f71649d35d9d93d5c9be03f554844ee68a7c45ae9c899f08ead8d2e0405
(7) 0x0221b4004e5b70684a0d19926739d5ed2e420d9e7c908a734763fbbf51d13133
(8) 0xd54daf5bfda3d3491ff5b3cefbba6a9e88b68d8ae322135337e9d530523308a6
(9) 0x73420d353ed74fd5939590dc30c2e7a966727f6561c84526ce71f04e0c668bec

HD Wallet
==================
Mnemonic:      give sick brand tail farm mechanic fence flock submit boost fiction magnet
Base HD Path:  m/44'/60'/0'/0/{account_index}

Gas Price
==================
20000000000

Gas Limit
==================
6721975

Listening on 127.0.0.1:8545

2.2 部署合约

(1)migrations目录下创建一个名字叫做2_deploy_contracts.js的文件。文件中的内容为:

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

module.exports = function(deployer) {
    deployer.deploy(SimpleAuction);
}

(2)修改truffle.js文件,连接本地ganache-cli环境。参数在最开初始化ganache-cli环境的窗口可以看到。

module.exports = {
  // See <http://truffleframework.com/docs/advanced/configuration>
  // to customize your Truffle configuration!
  networks: {
    development:{
      host: "127.0.0.1",
      port: 8545,
      network_id: "*" // match any network id
    }
  }
};

(3)现在执行truffle migrate命令,我们可以将SimpleAuction.sol原始码编译成Ethereum bytecode

PS H:\TestContract\SimpleAuction> truffle migrate
Using network 'development'.

Running migration: 2_deploy_contracts.js
  Deploying SimpleAuction...
Error encountered, bailing. Network state unknown. Review successful transactions manually.
Error: SimpleAuction contract constructor expected 2 arguments, received 0
    at C:\Users\aby\AppData\Roaming\npm\node_modules\truffle\build\webpack:\packages\truffle-contract\contract.js:390:1
    at new Promise (<anonymous>)
    at C:\Users\aby\AppData\Roaming\npm\node_modules\truffle\build\webpack:\packages\truffle-contract\contract.js:374:1
    at <anonymous>
    at process._tickCallback (internal/process/next_tick.js:188:7)
PS H:\TestContract\SimpleAuction>

发现报错,Error: SimpleAuction contract constructor expected 2 arguments, received 0,可以在部署时进行构造函数的赋值,不必修改智能合约内容:在2_deploy_contracts.js中,修改deploy脚本,deployer.deploy(SimpleAuction, 20, "0x553cc75f3099ec4f6ba57e2580f65f982dfcbc67");即可。

PS H:\TestContract\SimpleAuction> truffle migrate
Using network 'development'.

Running migration: 2_deploy_contracts.js
  Deploying SimpleAuction...
  ... 0x3b611b5e12c85ba20b59c66b7a2b997a580fab7dbe1431be323fcdd3f9d07f62
  SimpleAuction: 0x7307036020a33ae1996ff74a5044123eda03302c
Saving successful migration to network...
  ... 0xb646aa61fefa4933f6102d04e7af232c10c0c43f9384df49ab250f54a083c2c6
Saving artifacts...
PS H:\TestContract\SimpleAuction>

2.3 与合约交互

truffle提供命令行工具,执行truffle console命令后,可用Javascript来和刚刚部署的合约互动。

PS H:\TestContract\SimpleAuction> truffle console
truffle(development)>

使用web3.eth.accounts会输出ganache-cli网络上的所有账户。

truffle(development)> web3.eth.accounts
[ '0x553cc75f3099ec4f6ba57e2580f65f982dfcbc67',
  '0xed700e53205af0b9daa4548cc48465cab55d376c',
  '0x3fdcbf82e2343f3d88a5ec967800ee188b7bc440',
  '0x76757998260e9d7bb01e2761a4abacffd73162e2',
  '0x0e53c9c2cb04a7b46acd3e94703434c6e0b1e1c9',
  '0xfb7db3e68877e08df576d0071d1f68b1ad185d50',
  '0x0ff87726fac78f3675751fc67c3b2b174aa7ec68',
  '0x8bee12196d694c864b00c4b19295b0c0a067bb1a',
  '0x14e498d9ca25b050e17fb702e1325135da21e9e7',
  '0x1aed5d4a441d50716313426bdc519b8263c37bfc' ]

我们需要准备一些测试账户。
它会把第一个帐户的地址分配给变量account0,第二个帐户分配给变量account1Web3是一个JavaScript API,它将RPC调用包装起来以方便我们与区块链进行交互。

truffle(development)> acc1 = web3.eth.accounts[1]
'0xed700e53205af0b9daa4548cc48465cab55d376c'

我们可以看一下拍卖发起人以及第一个账户的余额:

truffle(development)> web3.eth.getBalance(address)
BigNumber { s: 1, e: 19, c: [ 999060, 70900000000000 ] }
truffle(development)> web3.eth.getBalance(acc1)
BigNumber { s: 1, e: 20, c: [ 1000000 ] }

此时我们用acc1调用bid(),发送2 ether

truffle(development)> contract.bid({from:acc1, value:web3.toWei(2,"ether")})
{ tx: '0xfad44c38347ee56220bf3810c4e6904b6c1e10a3cbd6495da9008533ffc5a1ee',
  receipt:
   { transactionHash: '0xfad44c38347ee56220bf3810c4e6904b6c1e10a3cbd6495da9008533ffc5a1ee',
     transactionIndex: 0,
     blockHash: '0xd9657a80fd84cb9a6582f560f3ce91dcc7f571932772d7f4ce4dd60ecd0f25c9',
     blockNumber: 5,
     gasUsed: 63946,
     cumulativeGasUsed: 63946,
     contractAddress: null,
     logs: [ [Object] ],
     status: '0x1',
     logsBloom: '0x00004000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000' },
  logs:
   [ { logIndex: 0,
       transactionIndex: 0,
       transactionHash: '0xfad44c38347ee56220bf3810c4e6904b6c1e10a3cbd6495da9008533ffc5a1ee',
       blockHash: '0xd9657a80fd84cb9a6582f560f3ce91dcc7f571932772d7f4ce4dd60ecd0f25c9',
       blockNumber: 5,
       address: '0x4faf92d14a7ac059b4fb97975376f52c32e1abe1',
       type: 'mined',
       event: 'HighestBidIncreased',
       args: [Object] } ] }

并且查看此时acc1余额,以及highestBid

truffle(development)> contract.highestBid.call()
BigNumber { s: 1, e: 18, c: [ 20000 ] }
truffle(development)> web3.eth.getBalance(acc1)
BigNumber { s: 1, e: 19, c: [ 979936, 5400000000000 ] }

由于拍卖时间设置较短,所以结束拍卖。

truffle(development)> contract.auctionEnd({from:address})
{ tx: '0x8701d85470423c67608d14eaa96e807a156981bf9d47826aa0bfcd69b4711fcc',
  receipt:
   { transactionHash: '0x8701d85470423c67608d14eaa96e807a156981bf9d47826aa0bfcd69b4711fcc',
     transactionIndex: 0,
     blockHash: '0x5dc6e9b00d495f19b2e3427b128c5b70544191a2bf8c78d9deabf6a79deaf097',
     blockNumber: 8,
     gasUsed: 51912,
     cumulativeGasUsed: 51912,
     contractAddress: null,
     logs: [ [Object] ],
     status: '0x1',
     logsBloom: '0x00004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000001000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000' },
  logs:
   [ { logIndex: 0,
       transactionIndex: 0,
       transactionHash: '0x8701d85470423c67608d14eaa96e807a156981bf9d47826aa0bfcd69b4711fcc',
       blockHash: '0x5dc6e9b00d495f19b2e3427b128c5b70544191a2bf8c78d9deabf6a79deaf097',
       blockNumber: 8,
       address: '0x4faf92d14a7ac059b4fb97975376f52c32e1abe1',
       type: 'mined',
       event: 'AuctionEnded',
       args: [Object] } ] }

2.4 拍卖过程

由于上面结束拍卖,我们现在重新设置拍卖时长,并连贯顺序地进行一次拍卖过程。由于ganache-cli每次都重新启动,都会随机创建10个账户,所以这里地址不同。
同样创建其他账户

PS H:\TestContract\SimpleAuction> truffle console
truffle(development)> address = web3.eth.accounts[0]
'0x0bf5cd9a0313121dda0f91e2da6ff9479be4ec5c'
truffle(development)> acc1 = web3.eth.accounts[1]
'0xdfa9eca806498bcf1c083b14ab20c53b2a3815a5'
truffle(development)> acc2 = web3.eth.accounts[2]
'0xc8dd1ff47b6e7067f1b4c2ec18fc60f36da97c46'
truffle(development)> acc3 = web3.eth.accounts[3]
'0xf758b41d6bb008e6f64bea810ecc38be46299ae6'
truffle(development)> acc4 = web3.eth.accounts[4]
'0x0830f17d845b90d8dc965ddb73b43e0f46e06bb8'

address调用创建一个拍卖:

truffle(development)> let contract
undefined
truffle(development)> SimpleAuction.deployed().then(instance => contract = instance)

我们可以看一下,当前创建拍卖的收益人,最高价,以及各个账户的余额等。

truffle(development)> contract.beneficiary.call()
'0x0bf5cd9a0313121dda0f91e2da6ff9479be4ec5c'
truffle(development)> contract.auctionStart.call()
BigNumber { s: 1, e: 9, c: [ 1531385059 ] }
truffle(development)> contract.highestBid.call()
BigNumber { s: 1, e: 0, c: [ 0 ] }
truffle(development)> contract.highestBidder.call()
'0x0000000000000000000000000000000000000000'
truffle(development)> web3.eth.getBalance(address)
BigNumber { s: 1, e: 19, c: [ 999060, 70900000000000 ] }
truffle(development)> web3.eth.getBalance(acc1)
BigNumber { s: 1, e: 20, c: [ 1000000 ] }
truffle(development)> web3.eth.getBalance(acc2)
BigNumber { s: 1, e: 20, c: [ 1000000 ] }

使用acc1进行一次bid()

truffle(development)> contract.bid({from:acc1, value:web3.toWei(2,"ether")})
{ tx: '0x68d752b6afc9b1bbb5c987bf4c4faad3907ea312f552f9280573a22dca662f05',
  receipt:
   { transactionHash: '0x68d752b6afc9b1bbb5c987bf4c4faad3907ea312f552f9280573a22dca662f05',
     transactionIndex: 0,
     blockHash: '0x30f1edf3689d8af7639c2bf2475e932d34155891d333512e3b97dffac25f5220',
     blockNumber: 5,
     gasUsed: 63946,
     cumulativeGasUsed: 63946,
     contractAddress: null,
     logs: [ [Object] ],
     status: '0x1',
     logsBloom: '0x00000000000000000000000000800080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' },
  logs:
   [ { logIndex: 0,
       transactionIndex: 0,
       transactionHash: '0x68d752b6afc9b1bbb5c987bf4c4faad3907ea312f552f9280573a22dca662f05',
       blockHash: '0x30f1edf3689d8af7639c2bf2475e932d34155891d333512e3b97dffac25f5220',
       blockNumber: 5,
       address: '0x55ac96c388568a6d2e233a8dbb9c1e5be1c3e4c8',
       type: 'mined',
       event: 'HighestBidIncreased',
       args: [Object] } ] }

查看当前acc1的余额,以及highestBid,可以看到acc1减少了,highestBid变成了2000

truffle(development)> web3.eth.getBalance(acc1)
BigNumber { s: 1, e: 19, c: [ 979936, 5400000000000 ] }
truffle(development)> contract.highestBid.call()
BigNumber { s: 1, e: 18, c: [ 20000 ] }

同样的,使用acc2acc3acc4分别进行bid:

Account Value
acc1 2
acc2 4
acc3 1
acc4 6

可以看到当bid价格比highestBid高时会出现上面的结果,如果低,则会被revert()抛出异常。

truffle(development)> contract.bid({from:acc3, value:web3.toWei(1,"ether")})
Error: VM Exception while processing transaction: revert
    at XMLHttpRequest._onHttpResponseEnd (C:\Users\aby\AppData\Roaming\npm\node_modules\truffle\build\webpack:\~\xhr2\lib\xhr2.js:509:1)
    at XMLHttpRequest._setReadyState (C:\Users\aby\AppData\Roaming\npm\node_modules\truffle\build\webpack:\~\xhr2\lib\xhr2.js:354:1)
    at XMLHttpRequestEventTarget.dispatchEvent (C:\Users\aby\AppData\Roaming\npm\node_modules\truffle\build\webpack:\~\xhr2\lib\xhr2.js:64:1)
    at XMLHttpRequest.request.onreadystatechange (C:\Users\aby\AppData\Roaming\npm\node_modules\truffle\build\webpack:\~\web3\lib\web3\httpprovider.js:128:1)
    at C:\Users\aby\AppData\Roaming\npm\node_modules\truffle\build\webpack:\packages\truffle-provider\wrapper.js:134:1
    at C:\Users\aby\AppData\Roaming\npm\node_modules\truffle\build\webpack:\~\web3\lib\web3\requestmanager.js:86:1
    at Object.InvalidResponse (C:\Users\aby\AppData\Roaming\npm\node_modules\truffle\build\webpack:\~\web3\lib\web3\errors.js:38:1)

此时,调用结束拍卖函数auctionEnd(),也会被revert()抛出异常,因为当前时间小于结束时间auctionEnd

过一段时间,再次调用auctionEnd()

truffle(development)> contract.auctionEnd.sendTransaction({from:address})
'0xfe1ed3d6fb181d2f0bb122edcadb99c735abee31f4d620f25a7e8ca7c8677014'

再看看此时受益者,也就是address地址的余额:
可以明显看到他增加了6 ether,得到收益。

truffle(development)> web3.eth.getBalance(address)
BigNumber { s: 1, e: 20, c: [ 1058987, 14600000000000 ] }

最后每个报价者取回自己的余额,竞拍失败者可以取回钱。

truffle(development)> contract.withdraw({from:acc1})
{ tx: '0x44d9f709c52d2e2b27e0d075b2afbd3fb9f065a1d66b70026a6657bd48a3c1ef',
  receipt:
   { transactionHash: '0x44d9f709c52d2e2b27e0d075b2afbd3fb9f065a1d66b70026a6657bd48a3c1ef',
     transactionIndex: 0,
     blockHash: '0xa5b1f3a0e2670e88462bd1c6338fe4eaa1afc6496a81fc508899fedc86d38e8a',
     blockNumber: 11,
     gasUsed: 19482,
     cumulativeGasUsed: 19482,
     contractAddress: null,
     logs: [],
     status: '0x1',
     logsBloom: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' },
  logs: [] }

acc1查看自己当前账户余额:

truffle(development)> web3.eth.getBalance(acc1)
BigNumber { s: 1, e: 19, c: [ 999916, 57200000000000 ] }

其他账户做同样操作。

2.5 账户变化

最后可以总结一下,每个参与拍卖的账户余额变化:

账户 1.初始化 2.创建合约 3.bid 4.拍卖结束及取回
address 1000000 999060, 70900000000000 999060, 70900000000000 1058987, 14600000000000
acc1 1000000 1000000 979936, 5400000000000(2) 999916, 57200000000000
acc2 1000000 1000000 4 999925, 81300000000000
acc3 1000000 1000000 1 999956, 8300000000000
acc4 1000000 1000000 6 939923, 41400000000000

由于发起交易需要消耗gas所以,账户1,2,3余额会比最开始少一点。而acc4则因为拍卖成功,相对较少的较多。

本文作者:Joyce
文章来源:https://www.jianshu.com/p/65c93265ad8e
版权声明:转载请注明出处!

2018年7月12日


参考:一个使用Atom,truffle,ganache-cli创建部署智能合约的方法智能合约开发之 Hello World!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,602评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,442评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,878评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,306评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,330评论 5 373
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,071评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,382评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,006评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,512评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,965评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,094评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,732评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,283评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,286评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,512评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,536评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,828评论 2 345

推荐阅读更多精彩内容