内容简介:以太坊钱包生成收款码时,有些是直接拿裸地址例如 "0x0728F0...75445F" 生成收款二维码,例如 TrustWallet;还有些是使用 "iban:" 开头的 ICAP 串来生成收款二维码,例如 imToken 1.0。IBAN 本身是国际上一部分银行间转账使用的账号代码格式,以太坊社区在 IBAN 地址格式上做了一些扩展,用来编码以太坊地址和校验码,用作地址交换使用,叫做 ICAP (IBAN 编码看起来很简单,但在实现上字母到数值的转换方法挺 trick 的,需要花一些时间进行理解。为简化
以太坊钱包生成收款码时,有些是直接拿裸地址例如 "0x0728F0...75445F" 生成收款二维码,例如 TrustWallet;还有些是使用 "iban:" 开头的 ICAP 串来生成收款二维码,例如 imToken 1.0。
IBAN 本身是国际上一部分银行间转账使用的账号代码格式,以太坊社区在 IBAN 地址格式上做了一些扩展,用来编码以太坊地址和校验码,用作地址交换使用,叫做 ICAP ( Inter exchange Client Address Protocol )。
IBAN 编码看起来很简单,但在实现上字母到数值的转换方法挺 trick 的,需要花一些时间进行理解。为简化理解,下面我拿一个例子来说明整个编码过程。
假设我们已经有了一个以太坊地址:0x730aEA2B39AA2Cf6B24829b3D39dC9a1F9297B88,下面是生成对应 ICAP 地址的过程:
第一步:将原始 16 进制以太坊地址转换成为 36 进制地址:
16 进制 ETH 地址:0x730aEA2B39AA2Cf6B24829b3D39dC9a1F9297B88 36 进制 ETH 地址:DFRZLRUTFTFY4EVINAHYF7TQ6MACYH4
第二步:为 36 进制 ETH 地址拼接上国家码 "XE" 和空校验字符串 "00" 形成 36 进制待校验字串:
36 进制 ETH 地址: DFRZLRUTFTFY4EVINAHYF7TQ6MACYH4 36 进制待校验字串: DFRZLRUTFTFY4EVINAHYF7TQ6MACYH4<font>XE00</font>
第三步:将 36 进制待校验字串逐字符转成 10 进制数字字串:
36 进制待校验字串: <font>D</font>FRZLRUTFTFY<font>4</font>EVINAHYF7TQ6MACYH4XE00
10 进制待校验字串: <font>13</font>1527352127302915291534<font>4</font>143118231017341572926622101234174331400
第四步:将 10 进制大整数对 97 取模,然后用 98 - 模数:
校验码:42 = 98 - 1315273521273029152915344143118231017341572926622101234174331400 % 97
第五步:将校验码替换空校验字符串,然后重新安排 XE** 到地址前,并加上前缀:
36 进制待校验字串: DFRZLRUTFTFY4EVINAHYF7TQ6MACYH4<font>XE00</font> 36 进制已校验字串: DFRZLRUTFTFY4EVINAHYF7TQ6MACYH4<font>XE42</font> 36 进制 IBAN 号: iban:<font>XE42</font>DFRZLRUTFTFY4EVINAHYF7TQ6MACYH4
可以用这个 IBAN 号生成二维码,用支持 iban 地址的 app 扫描二维码验证下是否能解析到正确的 ETH 原始地址。
ICAP 地址生成和校验的实现,可以参考下面这段 Java 代码,可直接用于 Android 客户端:
package com.yangwenbo; import java.math.BigInteger; /** * Ethereum ICAP (Inter exchange Client Address Protocol) Address Converter * Convert Ethereum Address from/to ICAP iban address * * @ref https://github.com/ethereum/wiki/wiki/Inter-exchange-Client-Address * -Protocol-(ICAP) */ public class EthICAP { private static String ICAP_XE_PREFIX = "XE"; private static String IBAN_SCHEME = "iban:"; private static String IBAN_MOD = "97"; /** * Build ICAP iban address from ethereum address. * * @param ethAddress ethereum address * @return ICAP iban address * @example input: 0x730aea2b39aa2cf6b24829b3d39dc9a1f9297b88 * return: iban:XE42DFRZLRUTFTFY4EVINAHYF7TQ6MACYH4 */ public static String buildICAP(String ethAddress) { if (!ethAddress.startsWith("0x") || ethAddress.length() != 42) { throw new IllegalArgumentException("Invalid ethereum address."); } BigInteger ethInt = new BigInteger(ethAddress.substring(2), 16); String base36Addr = ethInt.toString(36).toUpperCase(); String checkAddr = base36Addr + ICAP_XE_PREFIX + "00"; String base10Str = ""; for (Character c : checkAddr.toCharArray()) { base10Str += new BigInteger(c.toString(), 36); } Integer checkSum = 98 - (new BigInteger(base10Str)).mod(new BigInteger(IBAN_MOD)).intValue(); String icapAddress = IBAN_SCHEME + ICAP_XE_PREFIX + checkSum.toString() + base36Addr; return icapAddress; } /** * Decode ethereum address from ICAP iban address * * @param icapAddress ICAP iban address * @return ethereum address * @example input: iban:XE42DFRZLRUTFTFY4EVINAHYF7TQ6MACYH4 * return: 0x730aea2b39aa2cf6b24829b3d39dc9a1f9297b88 */ public static String decodeICAP(String icapAddress) { if (!isValid(icapAddress)) { throw new IllegalArgumentException("Invalid icap address."); } BigInteger ethInt = new BigInteger(icapAddress.substring(9), 36); String base16Addr = ethInt.toString(16).toLowerCase(); return "0x" + base16Addr; } /** * Check ICAP iban address validation * * @param icapAddress ICAP iban address * @return true if valid; false if invalid */ public static boolean isValid(String icapAddress) { if (!icapAddress.startsWith("iban:XE") || icapAddress.length() != 40) { return false; } String base10Str = ""; for (Character c : icapAddress.substring(9).toCharArray()) { base10Str += new BigInteger(c.toString(), 36); } for (Character c : icapAddress.substring(5, 9).toCharArray()) { base10Str += new BigInteger(c.toString(), 36); } Integer checkSum = (new BigInteger(base10Str)).mod(new BigInteger(IBAN_MOD)).intValue(); return checkSum == 1; } }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 图算法|Dijkstra算法python实现
- 算法:经典排序算法的 Go 实现
- js实现数据结构及算法之排序算法
- 算法 - 06 | 链表(上):如何实现LRU缓存淘汰算法?
- Twitter雪花算法SnowFlake算法的java实现
- js实现多种排序算法(算法导论第二章)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Head First HTML and CSS
Elisabeth Robson、Eric Freeman / O'Reilly Media / 2012-9-8 / USD 39.99
Tired of reading HTML books that only make sense after you're an expert? Then it's about time you picked up Head First HTML and really learned HTML. You want to learn HTML so you can finally create th......一起来看看 《Head First HTML and CSS》 这本书的介绍吧!