-
Notifications
You must be signed in to change notification settings - Fork 1
/
ain.ts
executable file
·389 lines (355 loc) · 14.3 KB
/
ain.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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
import * as AinUtil from "@ainblockchain/ain-util";
import { AxiosRequestConfig } from 'axios';
import {
AinOptions, Block, TransactionInfo, TransactionBody, TransactionResult, SetOperationType,
SetOperation, TransactionInput, ValueOnlyTransactionInput, StateUsageInfo, AppNameValidationInfo,
} from './types';
import Provider from './provider';
import Database from './ain-db/db';
import Reference from './ain-db/ref';
import Wallet from './wallet';
import Network from './net';
import EventManager from './event-manager';
import HomomorphicEncryption from './he';
import { Signer } from "./signer/signer";
import { DefaultSigner } from './signer/default-signer';
/**
* The main class of the ain-js SDK library.
*/
export default class Ain {
/** The axios request config object. */
public axiosConfig: AxiosRequestConfig | undefined;
/** The chain ID of the blockchain network. */
public chainId: number;
/** The endpoint Url of the event handler websocket server. */
public eventHandlerUrl?: string | null;
/** The network provider object. */
public provider: Provider;
/** The raw result mode option. */
public rawResultMode: boolean;
/** The database object. */
public db: Database;
/** The network object. */
public net: Network;
/** The wallet object. */
public wallet: Wallet;
/** The homorphic encryption object. */
public he: HomomorphicEncryption;
/** The event manager object. */
public em: EventManager;
/** The signer object. */
public signer: Signer;
/**
* Creates a new Ain object.
* @param {string} providerUrl The endpoint URL of the network provider.
* @param {string} eventHandlerUrl The endpoint URL of the event handler websocket server.
* @param {number} chainId The chain ID of the blockchain network.
* @param {AinOptions} ainOptions The options of the class.
*/
constructor(providerUrl: string, eventHandlerUrl?: string, chainId?: number, ainOptions?: AinOptions) {
this.axiosConfig = ainOptions?.axiosConfig;
this.provider = new Provider(this, providerUrl, this.axiosConfig);
this.eventHandlerUrl = eventHandlerUrl;
this.chainId = chainId || 0;
this.rawResultMode = ainOptions?.rawResultMode || false;
this.net = new Network(this.provider);
this.wallet = new Wallet(this, this.chainId);
this.db = new Database(this, this.provider);
this.he = new HomomorphicEncryption();
this.em = new EventManager(this);
this.signer = new DefaultSigner(this.wallet, this.provider);
}
/**
* Sets a new provider.
* @param {string} providerUrl The endpoint URL of the network provider. e.g. http://localhost:8081, https://testnet-api.ainetwork.ai
* @param {string} eventHandlerUrl The endpoint URL of the event handler websocket server. e.g. ws://localhost:5100, wss://testnet-event.ainetwork.ai
* @param {number} chainId The chain ID of the blockchain network. e.g. 0 for local or testnet, and 1 for mainnet
* @param {AxiosRequestConfig} axiosConfig The axios request config.
*/
setProvider(providerUrl: string, eventHandlerUrl?: string, chainId?: number, axiosConfig?: AxiosRequestConfig | undefined) {
if (axiosConfig) {
this.axiosConfig = axiosConfig;
}
this.provider = new Provider(this, providerUrl, this.axiosConfig);
this.eventHandlerUrl = eventHandlerUrl;
this.chainId = chainId || 0;
this.db = new Database(this, this.provider);
this.net = new Network(this.provider);
this.wallet.setChainId(this.chainId);
}
/**
* Sets a new signer.
* @param {Signer} signer The signer to set.
*/
setSigner(signer: Signer) {
this.signer = signer;
}
/**
* Fetches the last block.
* @returns {Promise<Block>}
*/
getLastBlock(): Promise<Block> {
return this.provider.send('ain_getLastBlock', {});
}
/**
* Fetches the last block number.
* @returns {Promise<Number>}
*/
getLastBlockNumber(): Promise<Block> {
return this.provider.send('ain_getLastBlockNumber', {});
}
/**
* Fetches a block with a block number.
* @param {number} blockNumber The block number.
* @param {boolean} returnTransactionObjects If it's true, returns a block with full transaction objects.
* Otherwise, returns a block with only transaction hashes.
* @returns {Promise<Block>}
*/
getBlockByNumber(blockNumber: number, returnTransactionObjects?: boolean): Promise<Block> {
const data =
Object.assign({}, { getFullTransactions: !!returnTransactionObjects, number: blockNumber });
return this.provider.send('ain_getBlockByNumber', data);
}
/**
* Fetches a block with a block hash.
* @param {string} blockHash The block hash.
* @param {boolean} returnTransactionObjects If it's true, returns a block with full transaction objects.
* Otherwise, returns a block with only transaction hashes.
* @returns {Promise<Block>}
*/
getBlockByHash(blockHash: string, returnTransactionObjects?: boolean): Promise<Block> {
const data =
Object.assign({}, { getFullTransactions: !!returnTransactionObjects, hash: blockHash });
return this.provider.send('ain_getBlockByHash', data);
}
/**
* Fetches blocks with a block number range.
* @param {number} from The begining block number (inclusive).
* @param {number} to The ending block number (exclusive).
* @returns {Promise<Array<Block>>}
*/
getBlockList(from: number, to: number): Promise<Array<Block>> {
return this.provider.send('ain_getBlockList', { from, to });
}
/**
* Fetches block headers with a block number range.
* @param {number} from The begining block number (inclusive).
* @param {number} to The ending block number (exclusive).
* @returns {Promise<Array<Block>>}
*/
getBlockHeadersList(from: number, to: number): Promise<Array<Block>> {
return this.provider.send('ain_getBlockHeadersList', { from, to });
}
/**
* Fetches block transaction count with a block number.
* @param {number} number The block number.
* @returns {Promise<Number>}
*/
getBlockTransactionCountByNumber(number: number): Promise<Number> {
return this.provider.send('ain_getBlockTransactionCountByNumber', { number });
}
/**
* Fetches block transaction count with a block hash.
* @param {string} hash The block hash.
* @returns {Promise<Number>}
*/
getBlockTransactionCountByHash(hash: string): Promise<Number> {
return this.provider.send('ain_getBlockTransactionCountByHash', { hash });
}
/**
* Fetches the information of the given validator address.
* @param {string} address The validator address.
* @returns {Promise<any>}
*/
getValidatorInfo(address: string): Promise<any> {
return this.provider.send('ain_getValidatorInfo', { address });
}
/**
* Fetches the validator list of a block with a block number.
* @param {number} blockNumber The block number.
* @returns {Promise<any>}
*/
getValidatorsByNumber(blockNumber: number): Promise<any> {
return this.provider.send('ain_getValidatorsByNumber', { number: blockNumber });
}
/**
* Fetches the validator list of a block with a block hash.
* @param {string} blockHash The block hash.
* @returns {Promise<any>}
*/
getValidatorsByHash(blockHash: string): Promise<any> {
return this.provider.send('ain_getValidatorsByHash', { hash: blockHash });
}
/**
* Fetches the block proproser's address of a block with a block number.
* @param {number} blockNumber The block number.
* @returns {Promise<string>}
*/
getProposerByNumber(blockNumber: number): Promise<string> {
return this.provider.send('ain_getProposerByNumber', { number: blockNumber });
}
/**
* Fetches the block proproser's address of a block with a block hash.
* @param {string} blockHash The block hash.
* @returns {Promise<string>}
*/
getProposerByHash(blockHash: string): Promise<string> {
return this.provider.send('ain_getProposerByHash', { hash: blockHash });
}
/**
* Fetches pending transactions.
* @returns {Promise<any>}
*/
getPendingTransactions(): Promise<any> {
return this.provider.send('ain_getPendingTransactions', {});
}
/**
* Fetches transaction pool size utilization.
* @returns {Promise<any>}
*/
getTransactionPoolSizeUtilization(): Promise<any> {
return this.provider.send('ain_getTransactionPoolSizeUtilization', {});
}
/**
* Fetches a transaction's information with a transaction hash.
* @param {string} transactionHash The transaction hash.
* @returns {Promise<TransactionInfo>}
*/
getTransactionByHash(transactionHash: string): Promise<TransactionInfo> {
return this.provider.send('ain_getTransactionByHash', { hash: transactionHash });
}
/**
* Fetches a transaction's information with a block hash and an index.
* @param {string} blockHash The block hash.
* @param {number} index The transaction index in the block
* @returns {Promise<TransactionInfo>}
*/
getTransactionByBlockHashAndIndex(blockHash: string, index: number): Promise<TransactionInfo> {
return this.provider.send('ain_getTransactionByBlockHashAndIndex', { block_hash: blockHash, index });
}
/**
* Fetches a transaction's information with a block hash and an index.
* @param {string} blockNumber The block number.
* @param {number} index The transaction index in the block
* @returns {Promise<TransactionInfo>}
*/
getTransactionByBlockNumberAndIndex(blockNumber: number, index: number): Promise<TransactionInfo> {
return this.provider.send('ain_getTransactionByBlockNumberAndIndex', { block_number: blockNumber, index });
}
/**
* Fetches a blockchain app's state usage information with an app name.
* @param {string} appName The blockchain app name.
* @returns {Promise<StateUsageInfo>}
*/
getStateUsage(appName: string): Promise<StateUsageInfo> {
return this.provider.send('ain_getStateUsage', { app_name: appName });
}
/**
* Validates a blockchain app's name.
* @param {string} appName The blockchain app name.
* @returns {Promise<AppNameValidationInfo>}
*/
validateAppName(appName: string): Promise<AppNameValidationInfo> {
return this.provider.send('ain_validateAppName', { app_name: appName });
}
/**
* Signs and sends a transaction to the network.
* @param {TransactionInput} transactionObject The transaction input object.
* @param {boolean} isDryrun The dryrun option.
* @returns {Promise<any>}
*/
async sendTransaction(transactionObject: TransactionInput, isDryrun: boolean = false): Promise<any> {
return this.signer.sendTransaction(transactionObject, isDryrun);
}
/**
* Sends a signed transaction to the network.
* @param {string} signature The signature of the transaction.
* @param {TransactionBody} txBody The transaction body.
* @param {boolean} isDryrun The dryrun option.
* @returns {Promise<any>}
*/
async sendSignedTransaction(signature: string, txBody: TransactionBody, isDryrun: boolean = false): Promise<any> {
return this.signer.sendSignedTransaction(signature, txBody, isDryrun);
}
/**
* Signs and sends multiple transactions in a batch to the network.
* @param {TransactionInput[]} transactionObjects The list of the transaction input objects.
* @returns {Promise<any>}
*/
async sendTransactionBatch(transactionObjects: TransactionInput[]): Promise<any> {
return this.signer.sendTransactionBatch(transactionObjects);
}
/**
* Sends a transaction that deposits AIN for consensus staking.
* @param {ValueOnlyTransactionInput} transactionObject The transaction input object.
* @returns {Promise<any>}
*/
depositConsensusStake(transactionObject: ValueOnlyTransactionInput): Promise<any> {
return this.stakeFunction('/deposit/consensus', transactionObject);
}
/**
* Sends a transaction that withdraws AIN for consensus staking.
* @param {ValueOnlyTransactionInput} transactionObject The transaction input object.
* @returns {Promise<any>}
*/
withdrawConsensusStake(transactionObject: ValueOnlyTransactionInput): Promise<any> {
return this.stakeFunction('/withdraw/consensus', transactionObject);
}
/**
* Fetches the amount of AIN currently staked for participating in consensus protocol.
* @param {string} account The account to fetch the value with. If not specified,
* the default account of the signer is used.
* @returns {Promise<number>}
*/
getConsensusStakeAmount(account?: string): Promise<number> {
const address = account ? Ain.utils.toChecksumAddress(account)
: this.signer.getAddress(account);
return this.db.ref(`/deposit_accounts/consensus/${address}`).getValue();
}
/**
* Getter for ain-util library.
*/
static get utils() {
return AinUtil;
}
/**
* Checks whether an object is an instance of TransactionBody interface.
* @param {any} object The object to check.
* @returns {boolean}
*/
static instanceofTransactionBody(object: any): object is TransactionBody {
return object.nonce !== undefined && object.timestamp !== undefined &&
object.operation !== undefined;
}
/**
* A base function for all staking related database changes. It builds a
* deposit/withdraw transaction and sends the transaction by calling sendTransaction().
* @param {string} path The path to set a value with.
* @param {ValueOnlyTransactionInput} transactionObject The transaction input object.
* @param {boolean} isDryrun The dryrun option.
* @returns {Promise<any>}
*/
private stakeFunction(path: string, transactionObject: ValueOnlyTransactionInput, isDryrun: boolean = false): Promise<any> {
const type: SetOperationType = "SET_VALUE";
if (!transactionObject.value) {
throw new Error('[ain-js.stakeFunction] a value should be specified.');
}
if (typeof transactionObject.value !== 'number') {
throw new Error('[ain-js.stakeFunction] value has to be a number.');
}
transactionObject.address = this.signer.getAddress(transactionObject.address);
const ref = this.db.ref(`${path}/${transactionObject.address}`).push()
if (ref instanceof Reference) {
const operation: SetOperation = {
ref: `${path}/${transactionObject.address}/${ref.key}/value`,
value: transactionObject.value,
type
}
delete transactionObject.value;
const txInput = Object.assign({ operation }, { transactionObject });
return this.sendTransaction(txInput, isDryrun);
} else {
throw new Error('[ain-js.stakeFunction] Error in Reference push.');
}
}
}