内容简介:以太坊钱包生成收款码时,有些是直接拿裸地址例如 "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实现多种排序算法(算法导论第二章)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
"笨办法"学Python
肖 (Zed A.Shaw) / 王巍巍 / 人民邮电出版社 / 2014-11-1 / CNY 49.00
本书是一本Python入门书籍,适合对计算机了解不多,没有学过编程,但对编程感兴趣的读者学习使用。这本书以习题的方式引导读者一步一步学习编程,从简单的打印一直讲到完整项目的实现,让初学者从基础的编程技术入手,最终体验到软件开发的基本过程。 本书结构非常简单,共包括52个习题,其中26个覆盖了输入/输出、变量和函数三个主题,另外26个覆盖了一些比较高级的话题,如条件判断、循环、类和对象、代码测......一起来看看 《"笨办法"学Python》 这本书的介绍吧!