# [ERC7673] アドレスを絵文字に置き換えて識別子やすくする仕組みを理解しよう！

> ユーザーのアカウントアドレスを扱う時に16進数やBase64の代わりに、256種類の絵文字を用いるbase256emojiの導入を提案しています。

- URL: https://cardene.dev/articles/ef3add52e6a533b9fe3f
- 公開日: 2024-06-15
- 更新日: 2024-06-15
- トピック: Blockchain
- タグ: ethereum, solidity, smartcontract, ブロックチェーン

## はじめに

初めまして。
**CryptoGames**というブロックチェーンゲーム企業でエンジニアをしている **cardene（かるでね）** です！
スマートコントラクトを書いたり、フロントエンド・バックエンド・インフラと幅広く触れています。

https://cryptogames.co.jp/

代表的なゲームは**クリプトスペルズ**というブロックチェーンゲームです。

https://cryptospells.jp/

今回は、アカウントアドレスを絵文字からなる文字列に変換する仕組みを提案している**ERC7673**についてまとめていきます！

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

https://eips.ethereum.org/EIPS/eip-7673

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

https://cardene.notion.site/ERC-EIP-2a03fa3ea33d43baa9ed82288f98d4a9?pvs=4

## 概要

ユーザーのアカウントアドレスを扱う時に16進数やBase64の代わりに、256種類の絵文字を用いる**base256emoji**の導入を提案しています。

## 動機

アドレスを人間が識別するのは非常に難しいです。
よく先頭と末尾の何文字かを確認してアドレスをチェックしていると思います。
ただ、これはあくまで先頭と末尾だけのチェックであり、その間にある値は何もチェックされません。

:::message
これを悪用した仕組みとして「**アドレスポイズニング**」などがあります。
アドレスポイズニングとは、トークンの送付時に自身のトランザクション履歴から自分のアドレスをコピペすることを狙って、先頭と末尾の何桁かが一緒のアドレスを生成し、該当のアドレスに向けて何らかのトランザクションを送付します。
ユーザーは過去の自分のトランザクション履歴から自分のアドレスをコピペして、トークイン取得のトランザクションを実行します。
この時コピペしたアドレスが悪意あるユーザーのアドレスの場合、トークンは悪意あるユーザーのアドレスに送付されてしまいます。
より詳しくは以下の記事を参考にしてください。
:::

https://support.metamask.io/ja/privacy-and-security/staying-safe-in-web3/address-poisoning-scams/

この対策としてまず挙げられることとしては、「**アドレスをわかりやすくする**」ということです。
アドレスが読みやすくなれば、一目でアドレスの間違いに気づくことができます。

## 仕様

アカウントアドレスは、16進数ではなく**base256emoji**文字列である必要があります。
ユーザーのアカウントアドレスを入力として受け取り、全て有効な**base256emoji**である場合、20個の連続した絵文字の文字列をアドレスとして扱います。

### base256emojiエンコーディング テーブル

| Emoji | Unicode codepoint | Byte Value |
|:-:|:-:|:-:|
| 🚀 | U+1F680 | 0 |
| 🪐 | U+1FA90 | 1 |
| ☄ | U+2604 | 2 |
| 🛰 | U+1F6F0 | 3 |
| 🌌 | U+1F30C | 4 |
| 🌑 | U+1F311 | 5 |
| 🌒 | U+1F312 | 6 |
| 🌓 | U+1F313 | 7 |
| 🌔 | U+1F314 | 8 |
| 🌕 | U+1F315 | 9 |
| 🌖 | U+1F316 | 10 |
| 🌗 | U+1F317 | 11 |
| 🌘 | U+1F318 | 12 |
| 🌍 | U+1F30D | 13 |
| 🌏 | U+1F30F | 14 |
| 🌎 | U+1F30E | 15 |
| 🐉 | U+1F409 | 16 |
| ☀ | U+2600 | 17 |
| 💻 | U+1F4BB | 18 |
| 🖥 | U+1F5A5 | 19 |
| 💾 | U+1F4BE | 20 |
| 💿 | U+1F4BF | 21 |
| 😂 | U+1F602 | 22 |
| ❤ | U+2764 | 23 |
| 😍 | U+1F60D | 24 |
| 🤣 | U+1F923 | 25 |
| 😊 | U+1F60A | 26 |
| 🙏 | U+1F64F | 27 |
| 💕 | U+1F495 | 28 |
| 😭 | U+1F62D | 29 |
| 😘 | U+1F618 | 30 |
| 👍 | U+1F44D | 31 |
| 😅 | U+1F605 | 32 |
| 👏 | U+1F44F | 33 |
| 😁 | U+1F601 | 34 |
| 🔥 | U+1F525 | 35 |
| 🥰 | U+1F970 | 36 |
| 💔 | U+1F494 | 37 |
| 💖 | U+1F496 | 38 |
| 💙 | U+1F499 | 39 |
| 😢 | U+1F622 | 40 |
| 🤔 | U+1F914 | 41 |
| 😆 | U+1F606 | 42 |
| 🙄 | U+1F644 | 43 |
| 💪 | U+1F4AA | 44 |
| 😉 | U+1F609 | 45 |
| ☺ | U+263A | 46 |
| 👌 | U+1F44C | 47 |
| 🤗 | U+1F917 | 48 |
| 💜 | U+1F49C | 49 |
| 😔 | U+1F614 | 50 |
| 😎 | U+1F60E | 51 |
| 😇 | U+1F607 | 52 |
| 🌹 | U+1F339 | 53 |
| 🤦 | U+1F926 | 54 |
| 🎉 | U+1F389 | 55 |
| 💞 | U+1F49E | 56 |
| ✌ | U+270C | 57 |
| ✨ | U+2728 | 58 |
| 🤷 | U+1F937 | 59 |
| 😱 | U+1F631 | 60 |
| 😌 | U+1F60C | 61 |
| 🌸 | U+1F338 | 62 |
| 🙌 | U+1F64C | 63 |
| 😋 | U+1F60B | 64 |
| 💗 | U+1F497 | 65 |
| 💚 | U+1F49A | 66 |
| 😏 | U+1F60F | 67 |
| 💛 | U+1F49B | 68 |
| 🙂 | U+1F642 | 69 |
| 💓 | U+1F493 | 70 |
| 🤩 | U+1F929 | 71 |
| 😄 | U+1F604 | 72 |
| 😀 | U+1F600 | 73 |
| 🖤 | U+1F5A4 | 74 |
| 😃 | U+1F603 | 75 |
| 💯 | U+1F4AF | 76 |
| 🙈 | U+1F648 | 77 |
| 👇 | U+1F447 | 78 |
| 🎶 | U+1F3B6 | 79 |
| 😒 | U+1F612 | 80 |
| 🤭 | U+1F92D | 81 |
| ❣ | U+2763 | 82 |
| 😜 | U+1F61C | 83 |
| 💋 | U+1F48B | 84 |
| 👀 | U+1F440 | 85 |
| 😪 | U+1F62A | 86 |
| 😑 | U+1F611 | 87 |
| 💥 | U+1F4A5 | 88 |
| 🙋 | U+1F64B | 89 |
| 😞 | U+1F61E | 90 |
| 😩 | U+1F629 | 91 |
| 😡 | U+1F621 | 92 |
| 🤪 | U+1F92A | 93 |
| 👊 | U+1F44A | 94 |
| 🥳 | U+1F973 | 95 |
| 😥 | U+1F625 | 96 |
| 🤤 | U+1F924 | 97 |
| 👉 | U+1F449 | 98 |
| 💃 | U+1F483 | 99 |
| 😳 | U+1F633 | 100 |
| ✋ | U+270B | 101 |
| 😚 | U+1F61A | 102 |
| 😝 | U+1F61D | 103 |
| 😴 | U+1F634 | 104 |
| 🌟 | U+1F31F | 105 |
| 😬 | U+1F62C | 106 |
| 🙃 | U+1F643 | 107 |
| 🍀 | U+1F340 | 108 |
| 🌷 | U+1F337 | 109 |
| 😻 | U+1F63B | 110 |
| 😓 | U+1F613 | 111 |
| ⭐ | U+2B50 | 112 |
| ✅ | U+2705 | 113 |
| 🥺 | U+1F97A | 114 |
| 🌈 | U+1F308 | 115 |
| 😈 | U+1F608 | 116 |
| 🤘 | U+1F918 | 117 |
| 💦 | U+1F4A6 | 118 |
| ✔ | U+2714 | 119 |
| 😣 | U+1F623 | 120 |
| 🏃 | U+1F3C3 | 121 |
| 💐 | U+1F490 | 122 |
| ☹ | U+2639 | 123 |
| 🎊 | U+1F38A | 124 |
| 💘 | U+1F498 | 125 |
| 😠 | U+1F620 | 126 |
| ☝ | U+261D | 127 |
| 😕 | U+1F615 | 128 |
| 🌺 | U+1F33A | 129 |
| 🎂 | U+1F382 | 130 |
| 🌻 | U+1F33B | 131 |
| 😐 | U+1F610 | 132 |
| 🖕 | U+1F595 | 133 |
| 💝 | U+1F49D | 134 |
| 🙊 | U+1F64A | 135 |
| 😹 | U+1F639 | 136 |
| 🗣 | U+1F5E3 | 137 |
| 💫 | U+1F4AB | 138 |
| 💀 | U+1F480 | 139 |
| 👑 | U+1F451 | 140 |
| 🎵 | U+1F3B5 | 141 |
| 🤞 | U+1F91E | 142 |
| 😛 | U+1F61B | 143 |
| 🔴 | U+1F534 | 144 |
| 😤 | U+1F624 | 145 |
| 🌼 | U+1F33C | 146 |
| 😫 | U+1F62B | 147 |
| ⚽ | U+26BD | 148 |
| 🤙 | U+1F919 | 149 |
| ☕ | U+2615 | 150 |
| 🏆 | U+1F3C6 | 151 |
| 🤫 | U+1F92B | 152 |
| 👈 | U+1F448 | 153 |
| 😮 | U+1F62E | 154 |
| 🙆 | U+1F646 | 155 |
| 🍻 | U+1F37B | 156 |
| 🍃 | U+1F343 | 157 |
| 🐶 | U+1F436 | 158 |
| 💁 | U+1F481 | 159 |
| 😲 | U+1F632 | 160 |
| 🌿 | U+1F33F | 161 |
| 🧡 | U+1F9E1 | 162 |
| 🎁 | U+1F381 | 163 |
| ⚡ | U+26A1 | 164 |
| 🌞 | U+1F31E | 165 |
| 🎈 | U+1F388 | 166 |
| ❌ | U+274C | 167 |
| ✊ | U+270A | 168 |
| 👋 | U+1F44B | 169 |
| 😰 | U+1F630 | 170 |
| 🤨 | U+1F928 | 171 |
| 😶 | U+1F636 | 172 |
| 🤝 | U+1F91D | 173 |
| 🚶 | U+1F6B6 | 174 |
| 💰 | U+1F4B0 | 175 |
| 🍓 | U+1F353 | 176 |
| 💢 | U+1F4A2 | 177 |
| 🤟 | U+1F91F | 178 |
| 🙁 | U+1F641 | 179 |
| 🚨 | U+1F6A8 | 180 |
| 💨 | U+1F4A8 | 181 |
| 🤬 | U+1F92C | 182 |
| ✈ | U+2708 | 183 |
| 🎀 | U+1F380 | 184 |
| 🍺 | U+1F37A | 185 |
| 🤓 | U+1F913 | 186 |
| 😙 | U+1F619 | 187 |
| 💟 | U+1F49F | 188 |
| 🌱 | U+1F331 | 189 |
| 😖 | U+1F616 | 190 |
| 👶 | U+1F476 | 191 |
| 🥴 | U+1F974 | 192 |
| ▶ | U+25B6 | 193 |
| ➡ | U+27A1 | 194 |
| ❓ | U+2753 | 195 |
| 💎 | U+1F48E | 196 |
| 💸 | U+1F4B8 | 197 |
| ⬇ | U+2B07 | 198 |
| 😨 | U+1F628 | 199 |
| 🌚 | U+1F31A | 200 |
| 🦋 | U+1F98B | 201 |
| 😷 | U+1F637 | 202 |
| 🕺 | U+1F57A | 203 |
| ⚠ | U+26A0 | 204 |
| 🙅 | U+1F645 | 205 |
| 😟 | U+1F61F | 206 |
| 😵 | U+1F635 | 207 |
| 👎 | U+1F44E | 208 |
| 🤲 | U+1F932 | 209 |
| 🤠 | U+1F920 | 210 |
| 🤧 | U+1F927 | 211 |
| 📌 | U+1F4CC | 212 |
| 🔵 | U+1F535 | 213 |
| 💅 | U+1F485 | 214 |
| 🧐 | U+1F9D0 | 215 |
| 🐾 | U+1F43E | 216 |
| 🍒 | U+1F352 | 217 |
| 😗 | U+1F617 | 218 |
| 🤑 | U+1F911 | 219 |
| 🌊 | U+1F30A | 220 |
| 🤯 | U+1F92F | 221 |
| 🐷 | U+1F437 | 222 |
| ☎ | U+260E | 223 |
| 💧 | U+1F4A7 | 224 |
| 😯 | U+1F62F | 225 |
| 💆 | U+1F486 | 226 |
| 👆 | U+1F446 | 227 |
| 🎤 | U+1F3A4 | 228 |
| 🙇 | U+1F647 | 229 |
| 🍑 | U+1F351 | 230 |
| ❄ | U+2744 | 231 |
| 🌴 | U+1F334 | 232 |
| 💣 | U+1F4A3 | 233 |
| 🐸 | U+1F438 | 234 |
| 💌 | U+1F48C | 235 |
| 📍 | U+1F4CD | 236 |
| 🥀 | U+1F940 | 237 |
| 🤢 | U+1F922 | 238 |
| 👅 | U+1F445 | 239 |
| 💡 | U+1F4A1 | 240 |
| 💩 | U+1F4A9 | 241 |
| 👐 | U+1F450 | 242 |
| 📸 | U+1F4F8 | 243 |
| 👻 | U+1F47B | 244 |
| 🤐 | U+1F910 | 245 |
| 🤮 | U+1F92E | 246 |
| 🎼 | U+1F3BC | 247 |
| 🥵 | U+1F975 | 248 |
| 🚩 | U+1F6A9 | 249 |
| 🍎 | U+1F34E | 250 |
| 🍊 | U+1F34A | 251 |
| 👼 | U+1F47C | 252 |
| 💍 | U+1F48D | 253 |
| 📣 | U+1F4E3 | 254 |
| 🥂 | U+1F942 | 255 |

## 補足

これまでのコピエラーを減らす仕組みなど（**ERC55**など）では、アドレスの文字数自体を減らすことができませんでした。

:::message
**ERC55**については以下の記事を参考にしてください。
ざっくり説明すると、アドレスの混同を防ぐために大文字小文字を区別するハッシュベースのチェックサムを導入した規格です。

:::

[\[EIP55\] Ethereumアドレスのチェックサムの仕組みを理解しよう！](/articles/985f03760df12929b5f9)

この規格で提案されている**base256emoji**の絵文字を使用することで、アドレスの文字数を削減して人間にとって読みやすい文字列に変換することができます。

また、この規格で提案されている**base256emoji**はアドレスの表示にのみ使用することが推奨されています。
アドレスに似たランダム文字列として、「**トランザクションハッシュ**」があります。
ただ、トランザクションハッシュが悪意あるユーザーによって悪用される対象となっていないため、現時点（2024年6月）においてはまだ**base256emoji**を適用する必要はありません。

他にも、**calldata**は適切なABIを通じてデコードするのが最適であり、**base256emoji**の使用は推奨されません。

## テスト

各アドレスは以下のように文字列として出力されます。

| base256emoji | ERC-55 |
|:-:|:-:|
|🚀🚀🚀🚀🚀🚀😀💓🥴💣👻🙌🙈🤢😥☹🌏💩🍎💕|`0x0000000000004946c0e9F43F4Dee607b0eF1fA1c`|
|🚀🚀🚀🚀🚀🚀💸🎊💡🌿🚩🔥📌🙂💙❄🛰💩🤝⭐|`0x000000000000c57CF0A1f923d44527e703F1ad70`|
|☀☀☀☀☀❤🌊🌖❌💀✔🌎🎈❌💞🛰💗😅❓☄|`0x111111111117dC0aa78b770fA6A738034120C302`|
|👍🤫😋✊🤪😞🤐👶😭❤👉🚩💔🌱🤝🌊💚🪐🚩😐|`0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984`|
|😆🌎✅✨👋😜💛☺😶👋🐸🤩🌔🙌✋🤤⭐🍑☹⚡|`0x2a0f713aA953442EacA9EA47083f656170e67BA4`|
|🔥🤬🌔😝😞🙄👌💢🗣🌍✨😙🐾😡😑🤘💸😂😤🔵|`0x23B608675a2B2fB1890d3ABBd85c5775c51691d5`|
|🗣😅😞✨🤷😆🌟🐷🌷👶☝🪐🥀🖥🤟🐉💀💪😏❄|`0x89205A3A3b2A69De6Dbf7f01ED13B2108B2c43e7`|
|🥴😆😰✌🤟🔥📣🎵🌖🌏😡🎶💙🐸🍒🌔😱🤘🍀➡|`0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2`|
|▶🌻😥👏💘😛💐💨❄💸😂😪😝🤤🐸💻😟☝🍃🥺|`0xC18360217D8F7Ab5e7c516566761Ea12Ce7F9D72`|

## 参考実装

```python
to_emoji = [
    '🚀', '🪐', '☄', '🛰', '🌌', '🌑', '🌒', '🌓', '🌔', '🌕', '🌖', '🌗', '🌘', '🌍', '🌏', '🌎',
    '🐉', '☀', '💻', '🖥', '💾', '💿', '😂', '❤', '😍', '🤣', '😊', '🙏', '💕', '😭', '😘', '👍',
    '😅', '👏', '😁', '🔥', '🥰', '💔', '💖', '💙', '😢', '🤔', '😆', '🙄', '💪', '😉', '☺', '👌',
    '🤗', '💜', '😔', '😎', '😇', '🌹', '🤦', '🎉', '💞', '✌', '✨', '🤷', '😱', '😌', '🌸', '🙌',
    '😋', '💗', '💚', '😏', '💛', '🙂', '💓', '🤩', '😄', '😀', '🖤', '😃', '💯', '🙈', '👇', '🎶',
    '😒', '🤭', '❣', '😜', '💋', '👀', '😪', '😑', '💥', '🙋', '😞', '😩', '😡', '🤪', '👊', '🥳',
    '😥', '🤤', '👉', '💃', '😳', '✋', '😚', '😝', '😴', '🌟', '😬', '🙃', '🍀', '🌷', '😻', '😓',
    '⭐', '✅', '🥺', '🌈', '😈', '🤘', '💦', '✔', '😣', '🏃', '💐', '☹', '🎊', '💘', '😠', '☝',
    '😕', '🌺', '🎂', '🌻', '😐', '🖕', '💝', '🙊', '😹', '🗣', '💫', '💀', '👑', '🎵', '🤞', '😛',
    '🔴', '😤', '🌼', '😫', '⚽', '🤙', '☕', '🏆', '🤫', '👈', '😮', '🙆', '🍻', '🍃', '🐶', '💁',
    '😲', '🌿', '🧡', '🎁', '⚡', '🌞', '🎈', '❌', '✊', '👋', '😰', '🤨', '😶', '🤝', '🚶', '💰',
    '🍓', '💢', '🤟', '🙁', '🚨', '💨', '🤬', '✈', '🎀', '🍺', '🤓', '😙', '💟', '🌱', '😖', '👶',
    '🥴', '▶', '➡', '❓', '💎', '💸', '⬇', '😨', '🌚', '🦋', '😷', '🕺', '⚠', '🙅', '😟', '😵',
    '👎', '🤲', '🤠', '🤧', '📌', '🔵', '💅', '🧐', '🐾', '🍒', '😗', '🤑', '🌊', '🤯', '🐷', '☎',
    '💧', '😯', '💆', '👆', '🎤', '🙇', '🍑', '❄', '🌴', '💣', '🐸', '💌', '📍', '🥀', '🤢', '👅',
    '💡', '💩', '👐', '📸', '👻', '🤐', '🤮', '🎼', '🥵', '🚩', '🍎', '🍊', '👼', '💍', '📣', '🥂'
]
from_emoji = {emoji: "{0:02x}".format(i) for i, emoji in enumerate(to_emoji)}

def encode_address(hexadecimal_address):
    if len(hexadecimal_address) != 42 or not hexadecimal_address.startswith('0x'):
        return None
    return ''.join([to_emoji[int(hexadecimal_address[i:i+2], 16)] for i in range(2, 42, 2)])


def decode_address(emoji_address):
    # In python, these unicode characters all have a len() of 1
    if len(emoji_address) != 20:
        return None
    try:
        return '0x' + ''.join(from_emoji[emoji] for emoji in emoji_address)
    except IndexError:
        return None
```

実際に手元でも試してみました。

https://gist.github.com/cardene777/551b621b04be7a1675ced08b12a5337b

「**Open in Colab**」からぜひ試してみてください。

## セキュリティ

**base256emoji**を使用すると、アドレスに使用する文字数が半分になるため文字を区別しやすくなります。
これにより類似のアドレスを生成することが難しくなり、識別もしやすくなります。

## 引用

William Morriss (@wjmelements), "ERC-7673: Distinguishable base256emoji Addresses [DRAFT]," Ethereum Improvement Proposals, no. 7673, April 2024. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-7673.

## 最後に

今回は「アカウントアドレスを絵文字からなる文字列に変換する仕組みを提案している**ERC7673**」についてまとめてきました！
いかがだったでしょうか？

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

[Twitter @cardene777](https://twitter.com/cardene777)

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

https://chaldene.net/

https://zenn.dev/heku

https://cardene.substack.com/

https://mirror.xyz/0xcE77b9fCd390847627c84359fC1Bc02fC78f0e58

https://cardene.notion.site/ERC-EIP-2a03fa3ea33d43baa9ed82288f98d4a9?pvs=4
