内容简介:以太坊钱包生成收款码时,有些是直接拿裸地址例如 "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实现多种排序算法(算法导论第二章)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
CLR via C#
(美)Jeffrey Richter / 周靖 / 清华大学出版社 / 2010-9 / 99.00元
本书针对CLR和.NET Framework 4.0进行深入、全面的探讨,并结合实例介绍了如何利用它们进行设计、开发和调试。全书5部分29章。第Ⅰ部分介绍CLR基础,第Ⅱ部分解释如何设计类型,第Ⅲ部分介绍基本类型,第Ⅳ部分以实用特性为主题,第Ⅴ部分花大量篇幅重点介绍线程处理。 通过本书的阅读,读者可以掌握CLR和.NET Framework的精髓,轻松、高效地创建高性能应用程序。一起来看看 《CLR via C#》 这本书的介绍吧!