-
Notifications
You must be signed in to change notification settings - Fork 11
/
Copy pathPlatformAddress.ts
156 lines (136 loc) · 4.74 KB
/
PlatformAddress.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
import { Buffer } from "buffer";
import * as _ from "lodash";
import { blake160 } from "../hash";
import { toHex } from "../utility";
import { H160 } from "../value/H160";
import { H512 } from "../value/H512";
import { decode, encode, fromWords, toWords } from "./bech32";
export type PlatformAddressValue = PlatformAddress | string;
/**
* The bech32 form of account id. The human readable part(HRP) is used to
* represent the network. For platform address, the HRP is "ccc" for mainnet or
* "tcc" for testnet.
*
* Refer to the spec for the details about PlatformAddress.
* https://github.com/CodeChain-io/codechain/blob/master/spec/CodeChain-Address.md
*/
export class PlatformAddress {
public static fromPublic(
publicKey: H512 | string,
options: { networkId: string; version?: number }
): PlatformAddress {
if (!H512.check(publicKey)) {
throw Error(
`Invalid public key for creating PlatformAddress: ${publicKey}`
);
}
return PlatformAddress.fromAccountId(
getAccountIdFromPublic(H512.ensure(publicKey).value),
options
);
}
public static fromAccountId(
accountId: H160 | string,
options: { networkId: string; version?: number }
) {
const { networkId, version = 1 } = options;
if (!H160.check(accountId)) {
throw Error(
`Invalid accountId for creating PlatformAddress: "${accountId}"`
);
}
if (version !== 1) {
throw Error(
`Unsupported version for PlatformAddress: "${version}"`
);
}
if (typeof networkId !== "string" || networkId.length !== 2) {
throw Error(
`Unsupported networkId for PlatformAddress: "${networkId}"`
);
}
const words = toWords(
Buffer.from(
_.padStart(version.toString(16), 2, "0") +
H160.ensure(accountId).value,
"hex"
)
);
return new PlatformAddress(
H160.ensure(accountId),
encode(networkId + "c", words)
);
}
public static fromString(address: string) {
if (typeof address !== "string") {
throw Error(
`Expected PlatformAddress string but found: "${address}"`
);
} else if (address.charAt(2) !== "c") {
throw Error(`Unknown prefix for PlatformAddress: ${address}`);
}
const { words } = decode(address, address.substr(0, 3));
const bytes = fromWords(words);
const version = bytes[0];
if (version !== 1) {
throw Error(`Unsupported version for PlatformAddress: ${version}`);
}
const accountId = toHex(Buffer.from(bytes.slice(1)));
return new PlatformAddress(new H160(accountId), address);
}
public static check(address: any): boolean {
return address instanceof PlatformAddress
? true
: PlatformAddress.checkString(address);
}
public static ensure(address: PlatformAddressValue): PlatformAddress {
if (address instanceof PlatformAddress) {
return address;
} else if (typeof address === "string") {
return PlatformAddress.fromString(address);
} else {
throw Error(
`Expected either PlatformAddress or string but found ${address}`
);
}
}
public static ensureAccount(
address: PlatformAddress | H160 | string
): H160 {
if (address instanceof PlatformAddress) {
// FIXME: verify network id
return address.getAccountId();
} else if (address instanceof H160) {
return address;
} else if (address.match(`^(0x)?[a-fA-F0-9]{40}$`)) {
return new H160(address);
} else {
return PlatformAddress.fromString(address).getAccountId();
}
}
private static checkString(value: string): boolean {
// FIXME: verify checksum
return /^.{2}c[qpzry9x8gf2tvdw0s3jn54khce6mua7l]{40}$/.test(value);
}
public readonly accountId: H160;
public readonly value: string;
private constructor(accountId: H160, address: string) {
this.accountId = accountId;
this.value = address;
}
public toString(): string {
return this.value;
}
public getAccountId(): H160 {
return this.accountId;
}
}
function getAccountIdFromPublic(publicKey: string): string {
if (typeof publicKey !== "string") {
throw Error(
`Unexpected parameter for getAccountIdFromPublic: ${publicKey}`
);
}
// FIXME: Check 512-bit hexstring
return blake160(publicKey);
}