Solidity

如何在松露測試中使用大數字?

  • November 22, 2019

我正在使用 Truffle V5 測試智能合約。如果我不使用所有小數,一切都會很好。如果我設置 18 位小數,所有這些都會爆炸。測試程式碼是這樣的(來自 truffle docs):

const MetaCoin = artifacts.require("MetaCoin");

contract("2nd MetaCoin test", async accounts => {
 it("should put 10000 MetaCoin in the first account", async () => {
   let instance = await MetaCoin.deployed();
   let balance = await instance.getBalance.call(accounts[0]);
   assert.equal(balance.valueOf(), 10000);
 });

 it("should call a function that depends on a linked library", async () => {
   let meta = await MetaCoin.deployed();
   let outCoinBalance = await meta.getBalance.call(accounts[0]);
   let metaCoinBalance = outCoinBalance.toNumber();
   let outCoinBalanceEth = await meta.getBalanceInEth.call(accounts[0]);
   let metaCoinEthBalance = outCoinBalanceEth.toNumber();
   assert.equal(metaCoinEthBalance, 2 * metaCoinBalance);
 });

 it("should send coin correctly", async () => {
   // Get initial balances of first and second account.
   let account_one = accounts[0];
   let account_two = accounts[1];

   let amount = 10;

   let instance = await MetaCoin.deployed();
   let meta = instance;

   let balance = await meta.getBalance.call(account_one);
   let account_one_starting_balance = balance.toNumber();

   balance = await meta.getBalance.call(account_two);
   let account_two_starting_balance = balance.toNumber();
   await meta.sendCoin(account_two, amount, { from: account_one });

   balance = await meta.getBalance.call(account_one);
   let account_one_ending_balance = balance.toNumber();

   balance = await meta.getBalance.call(account_two);
   let account_two_ending_balance = balance.toNumber();

   assert.equal(
     account_one_ending_balance,
     account_one_starting_balance - amount,
     "Amount wasn't correctly taken from the sender"
   );
   assert.equal(
     account_two_ending_balance,
     account_two_starting_balance + amount,
     "Amount wasn't correctly sent to the receiver"
   );
 });
});

這是我需要測試的智能合約(來自 MetaCoin.sol 文件,為了使用最新的編譯器而修改(目前我使用 0.5.2)等等)。原文可以在這裡找到:

pragma solidity >=0.4.25 <0.6.0;

import "./ConvertLib.sol";

// This is just a simple example of a coin-like contract.
// It is not standards compatible and cannot be expected to talk to other
// coin/token contracts. If you want to create a standards-compliant
// token, see: https://github.com/ConsenSys/Tokens. Cheers!

contract MetaCoin {

// I add this section in EIP20 style
   string public symbol;
   string public  name;
   uint8 public decimals;
   uint _totalSupply

   mapping (address => uint) balances;

   event Transfer(address indexed _from, address indexed _to, uint256 _value);

   constructor() public {

// I modified constructor to introduce symbol, name, decimals and totalSupply
       symbol = "MTC";
       name = "MetaCoin Example Token";
       decimals = 18;
       _totalSupply = 10000 * 10**uint(decimals);  
       balances[tx.origin] = _totalSupply;
   }

   function sendCoin(address receiver, uint amount) public returns(bool sufficient) {
       if (balances[msg.sender] < amount) return false;
       balances[msg.sender] -= amount;
       balances[receiver] += amount;
       emit Transfer(msg.sender, receiver, amount);
       return true;
   }

   function getBalanceInEth(address addr) public view returns(uint){
       return ConvertLib.convert(getBalance(addr),2);
   }

   function getBalance(address addr) public view returns(uint) {
       return balances[addr];
   }
}

如果小數是,一切都可以,例如“1”或“2”,但是當我使用“18”時,我失去了控制。如何在 javascript 測試中實現 bignumbers 處理?我試過了,但它不起作用。

由於 所施加的限制Number.MAX_SAFE_INTEGER,請盡量遵守以下規則:

規則1:

避免使用toNumber()從返回值類型為以下之一的合約函式返回的任何值:

  • uint64
  • uint128
  • uint256

這也適用於公共變數(因為編譯器會為它們生成隱式 getter 函式)。

規則#2:

保持返回值的原始類型(BigNumber在 Truffle 4.x / web3 0.x上,BN在 Truffle 5.x / web3 1.x 上),並且只使用這種類型的函式(例如,plusminusmuldivequals等)。

規則#3:

對於列印輸出,最好不要使用toFixed(),以避免由於科學記數法(例如123.456e78)而導致精度損失。

請注意,規則 #1 也適用於返回address值的鏈上函式(string在鏈外端轉換為)。

引用自:https://ethereum.stackexchange.com/questions/67087