在瀏覽器開 Remix IDE,按 ERC20 合約。從 OpenZeppelin ERC20 智慧合約程式碼先來簡單看個 function decimals()。
/**
* @dev Returns the number of decimals used to get its user representation.
* For example, if `decimals` equals `2`, a balance of `505` tokens should
* be displayed to a user as `5.05` (`505 / 10 ** 2`).
*
* Tokens usually opt for a value of 18, imitating the relationship between
* Ether and Wei. This is the default value returned by this function, unless
* it's overridden.
*
* NOTE: This information is only used for _display_ purposes: it in
* no way affects any of the arithmetic of the contract, including
* {IERC20-balanceOf} and {IERC20-transfer}.
*/
function decimals() public view virtual returns (uint8) {
return 18;
}
綠色註解開頭第一句話寫:「Returns the number of decimals used to get its user representation.」。註解的主詞是 decimals()函式。也就是說,完整的句子其實是:「The decimals function returns the number of decimals used to get its user representation.」
受詞是這一整串「the number of decimals used to get its user representation.」而 used 是指這個被使用的,被用來的。來得到使用者的表示 the number of decimals,就是指 18。To get its user representation 的這邊的 user representation 是指有小數點的。its 用詞模糊,主要要指的是 the number being represented,就是有很多零的這個數字。
這個函式回傳第幾個位數(幾個十進位的位數) the number of decimals used 這個數字,現在回傳 18 就是第十八個位數。現在程式碼寫回傳 18,大概的意思是,合約裡面儲存的會是很大的數字。使用者介面呈現出來的會是比較小的數字。基本上有看到小數點的數字,都是呈現給使用者看到的,沒有例外。沒有小數點的數字才有可能是合約裡面儲存的數字。decimals() 函式的目的是,小數點點在第十八個零 return 18。
綠色註解寫的第二句話,提到小數點以 2 為例子的範例。指如果 decimals 是 2 的話,合約儲存的 balance 數字是 505,在使用端 user 呈現看到的是 5.05,因為小數點放在第二位。
舉例來說,USDT 的合約 decimal 是 6。假想合約儲存的 balance 數字是 10300000,使用者介面 user 看到的就會是 10.3 USDT,因為小數點放在第六位。合約存的數字一定都是整數。Solidity 沒有 floating point,而是 uint8 或 uint256。
接著來看 ERC20.sol 裡面寫的 function _mint() 在寫什麼。
function _mint(address account, uint256 value) internal {
if (account == address(0)) {
revert ERC20InvalidReceiver(address(0));
}
_update(address(0), account, value);
}
function _mint 鑄造代幣的時候,if 條件判斷幫檢查你是不是鑄造代幣到 zero address
,送到 address(0)就不是正確的地址。送到不對的地址就要觸發 revert 讓這個函式 fail。回傳 error 會寫這個理由 ERC20InvalidReceiver,表示失敗是因為他是送給沒效的、不合格的收款人地址。
判斷結束時,收款人地址都正確,就會立刻進到 _update 函式。_update 裡面現在寫有三個 arguments。第一個 argument 是 address(0),第二個 argument 是 account(也就是 mint 給他的地址,鑄造代幣的收款人地址)、第三個是 value(mint的金額)。
現在想確定的是,這個 value 是否需要 decimal。例如,想 mint 46 MTK 代幣的話,是合約裡面要寫 46 數值就好,還是要寫 46 後面接一堆零。
結論是,要 decimal。要寫數字乘上 10 的 18 次方。
_mint(_msgSender(), 46*10**18);
contract MyToken is ERC20, ERC20Permit {
constructor() ERC20("MyToken", "MTK") ERC20Permit("MyToken") {
_mint(_msgSender(), 46*10**18);
}
}
mint 鑄造 function,有兩個 arguments。第一個 argument 是 _msgSender(),是收到鑄造代幣的人。_msgSender 同時也是部署合約的人,是因為他是呼叫 constructor() 的人。第二個 argument 46*1018 是要鑄造多少代幣。兩個米字號就是次方。