-
Notifications
You must be signed in to change notification settings - Fork 18
/
erc20reader.ts
89 lines (79 loc) · 2.99 KB
/
erc20reader.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
// Make sure this file is not importet from index.d.ts to avoid a dependency on @types/bn.js
import { Address } from "@iov/bcp";
import { Encoding } from "@iov/encoding";
import BN from "bn.js";
import { Abi } from "./abi";
import { Erc20Options } from "./erc20";
export interface EthereumRpcClient {
readonly ethCall: (to: Address, data: Uint8Array) => Promise<Uint8Array>;
}
/** Class to query read-only information from an ERC20 contract. */
export class Erc20Reader {
private readonly client: EthereumRpcClient;
private readonly options: Erc20Options;
public constructor(client: EthereumRpcClient, options: Erc20Options) {
this.client = client;
this.options = options;
}
public async totalSupply(): Promise<BN> {
const data = Abi.calculateMethodId("totalSupply()");
const result = await this.client.ethCall(this.options.contractAddress, data);
return new BN(result);
}
public async balanceOf(address: Address): Promise<BN> {
const methodId = Abi.calculateMethodId("balanceOf(address)");
const data = new Uint8Array([...methodId, ...Abi.encodeAddress(address)]);
const result = await this.client.ethCall(this.options.contractAddress, data);
return new BN(result);
}
/**
* Returns symbol value from options or from chain.
*
* On-chain values will be cached internally, i.e. it is cheap to use this getter
* as long as the class instance is long living.
*/
public async name(): Promise<string> {
if (this.options.name) {
return this.options.name;
} else {
// TODO: cache this call
const data = Abi.calculateMethodId("name()");
const result = await this.client.ethCall(this.options.contractAddress, data);
const [nameBinary] = Abi.decodeHeadTail(result).tail;
return Encoding.fromUtf8(Abi.decodeVariableLength(nameBinary));
}
}
/**
* Returns symbol value from options or from chain.
*
* On-chain values will be cached internally, i.e. it is cheap to use this getter
* as long as the class instance is long living.
*/
public async symbol(): Promise<string> {
if (this.options.symbol) {
return this.options.symbol;
} else {
// TODO: cache this call
const data = Abi.calculateMethodId("symbol()");
const result = await this.client.ethCall(this.options.contractAddress, data);
const [symbolBinary] = Abi.decodeHeadTail(result).tail;
return Encoding.fromUtf8(Abi.decodeVariableLength(symbolBinary));
}
}
/**
* Returns decimals value from options or from chain.
*
* On-chain values will be cached internally, i.e. it is cheap to use this getter
* as long as the class instance is long living.
*/
public async decimals(): Promise<number> {
if (this.options.decimals) {
return this.options.decimals;
} else {
// TODO: cache this call
const data = Abi.calculateMethodId("decimals()");
const result = await this.client.ethCall(this.options.contractAddress, data);
return new BN(result).toNumber();
}
}
}