Owlio
JA
← ブログ
ハウツー初級

ERC-20トークンのdecimals: 生の残高を読みやすい数量に変換する

コントラクトの大きな整数が、小さなトークン数量を表すこともあります。ウォレット残高を比較する前に単位を確認しましょう。

ERC-20の生の残高を読みやすいトークン数量に変換するには、整数を、10の確認済みdecimals乗で割ります。値がまだ生の最小単位である場合だけ行ってください。 ウォレットやエクスプローラーですでに変換済みかもしれません。

例えば、生の残高1234567は小数点以下6桁なら1.234567トークンです。同じ生の整数でも18桁なら0.000000000001234567トークンです。どちらもドル建ての価値は示しません。これは仮の計算例で、ウォレットから取得した残高ではありません。

残高を読むときにdecimalsが変えるもの

ERC-20コントラクトのbalanceOfメソッドは整数を返します。ERC-20仕様では、decimalsをトークン数量をユーザーに提示するための桁数として説明しています。整数はそのトークンの最小の会計単位を数えたもので、decimalsが表示時の小数点の位置を決めると考えてください。

計算は次のとおりです。

読みやすいトークン数量 = 生の整数 ÷(10のdecimals乗)。

この記事では生の整数をすべて十進数で、桁区切りなしで記します。0xで始まる十六進数の値は、まず整数にデコードする必要があります。その表現の文字や数字を、そのまま十進のトークン数量としてこの割り算に使うことはできません。

同じ仮の整数を3通りの桁数で示します。

生の整数 decimals トークン数量
1234567 6 1.234567
1234567 18 0.000000000001234567
1234567 0 1234567

0桁なら割る数は1です。6桁なら1トークンは生の単位1000000に相当します。18桁なら1000000000000000000です。整数の大きさだけでは、どの桁数が適用されるかは分かりません。

計算する前に桁数を確認する

ネットワークとトークンコントラクトの完全なアドレスから始めます。シンボルはラベルであり、一意な識別子ではありません。どれがトークンのアドレスで、どれが保有者のアドレスか不明なら、先にウォレットアドレスとトークンコントラクトのガイドを確認してください。

そのネットワークに対するプロジェクト公式のデプロイ情報でコントラクトを特定します。次に、信頼できるエクスプローラーやコントラクト読み取りツールで、読み取り専用のdecimalsの結果を調べます。結果をコントラクトとネットワークとともに記録してください。別のデプロイから読み取ったメタデータでは、対象の保有分の桁数は確定しません。

decimalsが欠けていても18で埋めないでください。 ERC-20ではこのメソッドは任意です。OpenZeppelinのERC20リファレンスには、その実装の初期値は18で、上書き可能だと記されています。実装の初期値は全トークン共通の規則ではありません。同じ資料は、decimalsは表示の整形に使われ、コントラクト内の整数による残高や送金の計算は変えないとも説明しています。

読み取りに失敗したら、情報源が利用できない場合と、コントラクトが利用可能なメタデータを公開していない場合を区別します。同じデプロイについて信頼できる別の情報源を試すか、実装の資料を確認してください。それでも桁数が確認できなければ、生の整数を保ち、読みやすい数量は未確定と記します。もっともらしい数字でも、検証済みの変換とはいえません。

数値がすでに整形済みか確認する

式を使う前に、項目名と情報源の資料を読みます。コントラクトの生の結果、APIの正規化済み数量、ウォレットの丸められた表示は、同じ保有分を異なる形で表せます。小数点は整形済みである可能性を示しますが、小数点がなくても生の値とは限りません。整形済みの数量がちょうど2トークンということもあります。

仮の6桁のトークンでは、生の2500000は2.5トークンになります。ウォレットがすでに2.5トークンと示している場合、その表示値を1000000で割ると0.0000025となり、誤った二重変換です。

正確なトークン数量を得てから、表示の丸めを別に適用します。生の1は6桁なら0.000001トークンです。小数点以下4桁までの画面では0.0000と表示されることがあります。この丸めた表示だけでは残高が空だとは確定できません。食い違いを調べるときは正確な結果を参照できるようにし、情報源の精度を超えた有効桁を作り足さないでください。

スクリプトや表計算では、整形するまで生の整数を文字列か正確な整数のまま保ちます。MDNの安全な整数についての資料が説明するように、大きな整数は通常のJavaScriptのNumberでは精度を失う場合があります。失った精度は割り算では戻せません。ethers v6のドキュメントには、十進表記の文字列を返すformatUnitsがあります。確認済みのdecimalsを明示的に渡し、便宜上、不正確な数値に変換せず、その文字列を保ってください。

トークンを動かさずに2つの表示を照合する

同じ保有分を使って確認します。公開コントラクトの読み取りには、送金、承認、リカバリーフレーズ、ウォレットの署名は必要ありません。

  1. 対象を固定する。 ネットワーク、保有者の公開アドレス、確認済みのトークンコントラクトを記録します。残高を読む際に、保有者の代わりにコントラクトのアドレスを使わないでください。
  2. 観測を記録する。 取得できれば時刻とブロック番号を保存します。同じブロックの読み取りを優先してください。異なる時点の間に送金があると、完全には一致しない場合があります。
  3. 入力に単位を付ける。 元の値、生か整形済みか、コントラクトのdecimalsの根拠を保存します。情報源が単位を説明していなければ、そこで変換を止めます。
  4. 換算は一度だけ。 そのdecimalsで生の整数を変換し、表示用の丸めの前の正確な桁を保ちます。すでにトークン単位で渡された数量はそのままにします。
  5. 同じ単位を比べる。 得られたトークン数量と別の画面のトークン数量を、比較可能な精度で比べます。丸めによるゼロ表示なら、生の残高がゼロだと結論づける前に詳細を確認します。
  6. 残る差を扱う。 対象、観測時点、単位が一致しても数量が違うなら、両方の値と情報源を記録します。情報源が失敗した場合は、ゼロを入れず、読み取り不能と記します。ポートフォリオの食い違いのガイドでは、情報源からの応答不足、価格、ポジションの網羅範囲を扱っています。

役立つ結果とは、別の人が再現できる記録です。どのコントラクトで、誰の残高を、いつ観測し、生の値とdecimalsはいくつで、変換した数量は何かを残します。変換の証明に取引は必要ありません。

トークン数量と価値を分ける

整形で得られるのは、このトークンの個数です。ドル建ての見積もりには、さらに、その正確な資産について、通貨と時点を明示した価格が必要です。decimalsから価格、売買の流動性、コントラクトの安全性は確認できません。知らないトークンでも、ごく普通のdecimalsの値を返すことがあります。

受取証トークンやラップトークンには、1トークンが原資産のどれだけに相当するかという別の問いがあります。生の残高を変換して得られるのは受取証トークンやラップトークンの数量です。原資産相当量には、そのプロトコルの換算方法と単位が必要です。トークンのdecimalsはこの交換比率の代わりになりません。ヘルスファクターのようなプロトコルの比率にも、独自の資料に記された換算規則が必要です。

それでも数字が不自然なら、重要な不明点を残します。decimalsが不明なら、読みやすい数量は未確定です。数量が既知でも価格が不明なら、評価額は未確定です。こうした空白を明示すれば、理解したい保有分を動かすことなく、次に何を確認すべきか分かります。

よくある質問

すべてのERC-20トークンは小数点以下18桁を使いますか?

いいえ。OpenZeppelinのERC20実装では18が初期値ですが、ERC-20規格はこの値を必須としていません。decimalsメソッドも任意です。生の残高を変換する前に、対象のコントラクトとネットワークでdecimalsを確認してください。

ウォレットに表示された数量もdecimalsに従って割るべきですか?

換算が必要なのは、生の最小単位だと資料で確認できる値だけです。ウォレットはすでに読みやすいトークン数量を表示している場合があります。整形済みの数量を再び割ると誤った結果になります。まず読み取る項目の単位を確認してください。

ゼロ表示ならトークン残高が空だと断定できますか?

いいえ。小さな正の数量が丸められてゼロ表示になることがあります。より精密な数量、または確認済みのdecimalsと生の残高を調べてください。正常に読み取れた生の残高がゼロであることと、読み取り不能であることは別の結果です。