Distinguishable base256emoji Addresses
Abstract
Introduce base256emoji for use as the primary input and display for account addresses in all user interfaces.
Motivation
Human users often fail to distinguish between long strings of hexadecimal characters, especially when they match at the beginning and at the end. This makes hexadecimal strings a poor format for human-readable account addresses. The problem is being exploited by several spoofing strategies that mine similar addresses and spoof ERC-20 Transfer events with the goal of tricking the end user into copying the wrong recipient address. These address spoofing attacks have mislead tens of thousands of ether, and countless other tokens. Spoofers flooding the network with fake Transfer events waste network resources and complicate blockchain accounting. Improving the distinguishability of addresses will reduce the incentives for this behavior.
Specification
The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “NOT RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119 and RFC 8174.
User interfaces:
- SHALL depict account addresses as a base256emoji string instead of hexadecimal.
- SHALL accept base256emoji strings as input for user-supplied account address parameters.
- SHOULD recognize and interpret strings of exactly 20 consecutive emoji as addresses when all of them are valid base256emoji.
base256emoji encoding table
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 |
Rationale
Previous attempts to reduce spoofing and other copy errors such as ERC-55 have not reduced the number of characters in an address. Any base-256 standard would achieve this goal but emoji were chosen to maximize human-distinguishability. Multiple base-256 emoji encodings have been proposed. The base256emoji encoding was chosen due to its acceptance into the multibase repository.
This standard does not also recommend base256emoji for use in depicting other bytestrings such as transaction hashes and calldata. Transaction hashes are not yet being spoofed. Calldata is best decoded via the appropriate ABI. By only using base256emoji for addresses, addresses can be easily noticed among other information.
Backwards Compatibility
Using the encoding table, the base256emoji encoding can be transcoded into hexadecimal and vice-versa.
Test Cases
| base256emoji | ERC-55 |
|:-:|:-:|
|🚀🚀🚀🚀🚀🚀😀💓🥴💣👻🙌🙈🤢😥☹🌏💩🍎💕|0x0000000000004946c0e9F43F4Dee607b0eF1fA1c
|
|🚀🚀🚀🚀🚀🚀💸🎊💡🌿🚩🔥📌🙂💙❄🛰💩🤝⭐|0x000000000000c57CF0A1f923d44527e703F1ad70
|
|☀☀☀☀☀❤🌊🌖❌💀✔🌎🎈❌💞🛰💗😅❓☄|0x111111111117dC0aa78b770fA6A738034120C302
|
|👍🤫😋✊🤪😞🤐👶😭❤👉🚩💔🌱🤝🌊💚🪐🚩😐|0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984
|
|😆🌎✅✨👋😜💛☺😶👋🐸🤩🌔🙌✋🤤⭐🍑☹⚡|0x2a0f713aA953442EacA9EA47083f656170e67BA4
|
|🔥🤬🌔😝😞🙄👌💢🗣🌍✨😙🐾😡😑🤘💸😂😤🔵|0x23B608675a2B2fB1890d3ABBd85c5775c51691d5
|
|🗣😅😞✨🤷😆🌟🐷🌷👶☝🪐🥀🖥🤟🐉💀💪😏❄|0x89205A3A3b2A69De6Dbf7f01ED13B2108B2c43e7
|
|🥴😆😰✌🤟🔥📣🎵🌖🌏😡🎶💙🐸🍒🌔😱🤘🍀➡|0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
|
|▶🌻😥👏💘😛💐💨❄💸😂😪😝🤤🐸💻😟☝🍃🥺|0xC18360217D8F7Ab5e7c516566761Ea12Ce7F9D72
|
Reference Implementation
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
Security Considerations
With the base256emoji encoding, addresses use half as many characters. The characters used are more distinguishable. This squares the difficulty of generating similar addresses, making address spoofing impractical.
Copyright
Copyright and related rights waived via CC0.