はじめに

『DApps開発入門』という本や色々記事を書いているかるでねです。

今回は、誰でもスマートコントラクトから返される機械的なコードに対し、複数の言語や表現で人間が読めるテキストを登録・取得する仕組みを提案しているERC1444についてまとめていきます!

以下にまとめられているものを翻訳・要約・補足しながらまとめていきます。

他にも様々なEIPについてまとめています。

概要

ERC1444は、スマートコントラクトが出力する機械向けのコードを、任意の言語や表現で人間が理解できる文章に変換する方法を提供するものです。 変換されたテキストは、ブロックチェーン上に保存され、誰でも作成・登録・共有・利用することができます。 特定の言語に限定せず、利用者が自由に翻訳を作成できるため、多様な文化や言語に対応可能です。 これにより、従来のように英語の固定メッセージに依存する必要がなくなり、より包括的なユーザー体験が実現されます。

動機

スマートコントラクトを利用する時、ユーザーはその動作結果についてのフィードバックを必要とします。 これまでのように数値コードや英語の固定メッセージをそのまま表示するだけでは、一般の利用者にとって理解しづらく、ユーザー体験(UX)や開発者体験(DX)の質が低下します。

Ethereumが真にグローバルなプラットフォームとして広く利用されるためには、誰もが理解可能な形でトランザクションの結果を伝える手段が必要です。 ERC1444では、ブロックチェーン上で機械向けのステータスや状態コード(ブール値、列挙型、ERC1066など)に対して、それを自然言語で説明するメッセージを紐付けることを可能にします。 これにより、UIにそのまま表示できるフィードバックが得られるようになり、開発者にはより多くの文脈情報を返すことができ、ユーザーには親しみやすく直感的な操作が可能になります。

このような仕組みを導入することで、世界中のあらゆる言語圏のユーザーに対して、ブロックチェーンとのインタラクションにおいて一貫した、かつわかりやすいメッセージングを実現することができます。

仕様

コントラクト構成

ERC1444の仕組みは、ユーザーがスマートコントラクトの内部状態やステータスコードなどに対応する人間向けのテキストを、任意の言語・表現で取得できるように設計されたものです。 主に2種類のコントラクトで構成されています。

1つ目はLocalizationコントラクトで、コードと対応するテキストを管理します。 2つ目はLocalizationPreferencesコントラクトで、各ユーザーがどのLocalizationコントラクトを優先的に使用するかを記録します。 これにより、同じコードでもユーザーごとに異なる言語・表現でテキストを取得できる柔軟性が実現されています。

さらに、フォールバック(必ず全コードに対応する翻訳を提供する)となるLocalizationコントラクトも定義されており、ユーザーが指定した翻訳が未登録の場合にはこのフォールバックが使用されます。

Localizationコントラクト

js
interface Localization {
  function textFor(bytes32 _code) external view returns (string _text);
}

Localizationは、特定のコード(bytes32)に対応するテキスト(string)を保持するシンプルなコントラクトです。 これにより、定義済みのステータスコードやシグナルを人間が読める形で取得することができます。

textFor

javascript
function textFor(bytes32 _code) external view returns (string _text);

指定したコードに対応するテキストを取得する関数。 指定された_codeがマッピングに登録されていれば、その対応する文字列を返します。 存在しない場合、空文字列("")が返されます。

引数

  • _code
    • 人間が読みたい内容を特定するためのコード。

戻り値

  • _text
    • 対応するテキスト。
    • 存在しない場合は空文字列。

LocalizationPreferencesコントラクト

js
interface LocalizationPreferences {
  function set(Localization _localization) external returns (bool);
  function textFor(bytes32 _code) external view returns (bool _wasFound, string _text);
}

このコントラクトは、ユーザーごとの翻訳設定を記録・管理する役割を持ちます。 呼び出し元(tx.origin)に基づいて、どのLocalizationコントラクトを使用するかを判断し、対応するテキストを取得します。 指定されたコントラクトで該当する翻訳がない場合、フォールバックに登録されたコントラクトへ委譲されます。

set

javascript
function set(Localization _localization) external returns (bool);

ユーザーが使用したいLocalizationコントラクトを登録する関数。 呼び出し元(tx.origin)のユーザーに対して、今後使用する翻訳先のコントラクトを記録します。 この設定は、textFor呼び出し時に使用されます。

引数

  • _localization
    • 使用したいLocalizationコントラクトのアドレス。

textFor

javascript
function textFor(bytes32 _code) external view returns (bool _wasFound, string _text);

ユーザーが指定した翻訳設定に基づき、テキストを取得する関数。 ユーザーが登録したLocalizationコントラクトで指定されたコードを検索します。 該当する文字列が見つからなかった場合は、フォールバックのLocalizationコントラクトから取得されます。 フォールバックが使われたかどうかは _wasFound で判断できます。

引数

  • _code
    • 翻訳対象のコード。

戻り値

  • _wasFound
    • 指定された翻訳設定でテキストが見つかった場合はtrue、フォールバックが使われた場合はfalse。
  • _text
    • 対応するテキスト。

文字列フォーマット

全てのテキストはUTF-8でエンコードされる必要があります。 特殊文字、日本語、絵文字なども利用可能であり、多様な言語表現に対応しています。

テンプレート文字列

テンプレート付きの文字列にも対応しており、ANSI C の printf 形式で記述できます。 複数のパラメータを持つ場合は、POSIXの番号付きフォーマット(例: %1$s)を使うことが推奨されています。

参考実装

js
pragma solidity ^0.4.25;

contract Localization {
  mapping(bytes32 => string) private dictionary_;

  constructor() public {}

  // Currently overwrites anything
  function set(bytes32 _code, string _message) external {
    dictionary_[_code] = _message;
  }

  function textFor(bytes32 _code) external view returns (string _message) {
    return dictionary_[_code];
  }
}

contract LocalizationPreference {
  mapping(address => Localization) private registry_;
  Localization public defaultLocalization;

  bytes32 private empty_ = keccak256(abi.encodePacked(""));

  constructor(Localization _defaultLocalization) public {
    defaultLocalization = _defaultLocalization;
  }

  function set(Localization _localization) external returns (bool) {
    registry_[tx.origin] = _localization;
    return true;
  }

  function get(bytes32 _code) external view returns (bool, string) {
    return get(_code, tx.origin);
  }

  // Primarily for testing
  function get(bytes32 _code, address _who) public view returns (bool, string) {
    string memory text = getLocalizationFor(_who).textFor(_code);

    if (keccak256(abi.encodePacked(text)) != empty_) {
      return (true, text);
    } else {
      return (false, defaultLocalization.textFor(_code));
    }
  }

  function getLocalizationFor(address _who) internal view returns (Localization) {
    if (Localization(registry_[_who]) == Localization(0)) {
      return Localization(defaultLocalization);
    } else {
      return Localization(registry_[tx.origin]);
    }
  }
}

補足

bytes32 キーの採用理由

bytes32型はEVMの基礎単位であるため非常に効率的です。 約10の77乗という膨大な表現力を持ち、現実的なあらゆるコード、状態、識別子を一意に表現することができます。 仮に32バイトより長いキーを使いたい場合でも、ハッシュ化することで容易にbytes32にマッピングできます。 小さいサイズの型(例えばERC1066で使われるbytes1)も、bytes32の中に単純に埋め込むことができ、拡張性と互換性を両立できます。

グローバル単一管理とローカル分散管理の比較

ERC1444は、単一のグローバルレジストリに依存せず、用途ごとに複数のLocalizationPreferencesコントラクトを自由に展開できる設計を採用しています。 このアプローチは、柔軟性と分散性を重視しており、ウォレットやフレームワークなどが共通で使う場合に限り、合意された単一インスタンスを用意することも可能です。

ただし、統一的な「レジストリのレジストリ」的仕組みは、一見便利に見えるものの、中央集権的で自由度が低くアップグレードや命名衝突、複雑な検索処理などの問題を伴うため、ERC1444では採用していません。 軽量で分散的、自由な運用ができることを優先しています。

オフチェーンストレージとの比較

翻訳文をオフチェーンに保存し、オンチェーンではbytes32のキーだけを返す方法もありますが、この方法には可用性の問題があります。 外部リソース(Webサーバーなど)が常に動作しているとは限らず、revertメッセージのようなオンチェーンで即時に必要な場面では不適です。 したがって、翻訳データはオンチェーンに存在する必要があります。

文字エンコーディングの選定

文字列はすべてUTF-8でエンコードする必要があります。 UTF-8はASCIIと互換性を保ちつつ、世界中の自然言語、記号、絵文字まで幅広くカバーできます。 現在もっとも広く使われているエンコーディング方式であり、国際化対応には最適です。

テキストが見つからなかった場合の挙動

ユーザーが指定した翻訳が存在しなかった場合、空文字列("")を返すだけではローカライズシステムの意味が失われてしまいます。 そのため、2つの方針が考えられます。

1つは「翻訳が見つかりませんでした」というメッセージを返す方法ですが、本仕様ではこれは採用されていません。 理由は、そのメッセージ自体が無意味であり、情報としての価値が乏しいからです。

代わりに、ERC1444ではフォールバック翻訳の仕組みを採用しています。 これは、英語や中国語など広く使われている言語で最低限の翻訳を提供し、ユーザーが翻訳設定をしていない場合や見つからない場合に参照されます。 どの言語から取得したかは、textFor の戻り値に含まれるブール値で明示され、UIでの表示や説明に活用できます。

分散型翻訳のクラウドソーシング

Ethereumが真にグローバルなシステムとして普及するためには、誰もが自分に馴染みのある言語や表現で情報を受け取れる必要があります。 ERC1444では、中央集権的に翻訳を定義するのではなく、誰でも翻訳を作成・登録・共有できる仕組みを提供することで、文化的・言語的に多様な表現を実現します。 これはWeb3の分散性の精神にも合致した設計です。

printfスタイルのテンプレート

翻訳テキストにはC言語由来のprintf形式テンプレートが使用されます。 多くのプログラミング言語やライブラリでサポートされており、開発者にとって扱いやすく、UI側でのテキスト挿入処理が容易になります。

パラメータフィールドの重要性

各言語には語順や構文の違いがあります。%1$s, %2$dのような番号付き引数は、引数の順番を入れ替える必要がある場合にも対応でき、同じデータを使って多言語対応の翻訳が可能になります。 言語によっては一部の引数だけを使い、技術的な情報を隠すことも可能です。

テンプレート補間戦略

テンプレート文字列はそのまま返却し、実際の文字列の補間(プレースホルダの埋め込み)はオフチェーンで行うことが推奨されています。 例えば、スマートコントラクトからはテンプレートコードと引数だけをイベントで出力し、クライアント側が該当する翻訳と値を受け取って組み立てることで、高速かつ柔軟な対応が可能になります。

想定されていない実装仕様

ERC1444では、以下のような設計要素には言及しません。 つまり、実装者の判断に任せられています。

  • デフォルトのLocalizationコントラクトが公開か非公開か。
  • 誰がテキストを登録できるか(例:デプロイヤー、所有者、誰でも、ホワイトリストなど)。
  • いつ登録できるか(例:コンストラクタでのみ、任意タイミングで、追記のみ可能で上書き不可など)。

この柔軟性は、幅広いユースケースに対応するために必要不可欠です。プロトコル、ツール、DAppの目的に応じた自由な実装が期待されています。

引用

Brooklyn Zelenka (@expede), Jennifer Cooper (@jenncoop), "ERC-1444: Localized Messaging with Signal-to-Text [DRAFT]," Ethereum Improvement Proposals, no. 1444, September 2018. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-1444.

最後に

今回は「誰でもスマートコントラクトから返される機械的なコードに対し、複数の言語や表現で人間が読めるテキストを登録・取得する仕組みを提案しているERC1444」についてまとめてきました! いかがだったでしょうか?

質問などがある方は以下のTwitterのDMなどからお気軽に質問してください!

他の媒体でも情報発信しているのでぜひ他も見ていってください!